about summary refs log tree commit diff stats
path: root/vendor/whereami
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/whereami')
-rw-r--r--vendor/whereami/LICENSE.MIT18
-rw-r--r--vendor/whereami/whereami.c704
-rw-r--r--vendor/whereami/whereami.h67
3 files changed, 789 insertions, 0 deletions
diff --git a/vendor/whereami/LICENSE.MIT b/vendor/whereami/LICENSE.MIT new file mode 100644 index 0000000..fd8ed6b --- /dev/null +++ b/vendor/whereami/LICENSE.MIT
@@ -0,0 +1,18 @@
1Copyright Gregory Pakosz
2
3Permission is hereby granted, free of charge, to any person obtaining a copy of
4this software and associated documentation files (the "Software"), to deal in
5the Software without restriction, including without limitation the rights to
6use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7the Software, and to permit persons to whom the Software is furnished to do so,
8subject to the following conditions:
9
10The above copyright notice and this permission notice shall be included in all
11copies or substantial portions of the Software.
12
13THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file
diff --git a/vendor/whereami/whereami.c b/vendor/whereami/whereami.c new file mode 100644 index 0000000..f238e1b --- /dev/null +++ b/vendor/whereami/whereami.c
@@ -0,0 +1,704 @@
1// (‑●‑●)> dual licensed under the WTFPL v2 and MIT licenses
2// without any warranty.
3// by Gregory Pakosz (@gpakosz)
4// https://github.com/gpakosz/whereami
5
6// in case you want to #include "whereami.c" in a larger compilation unit
7#if !defined(WHEREAMI_H)
8#include <whereami.h>
9#endif
10
11#ifdef __cplusplus
12extern "C" {
13#endif
14
15#if defined(__linux__) || defined(__CYGWIN__)
16#undef _DEFAULT_SOURCE
17#define _DEFAULT_SOURCE
18#elif defined(__APPLE__)
19#undef _DARWIN_C_SOURCE
20#define _DARWIN_C_SOURCE
21#define _DARWIN_BETTER_REALPATH
22#endif
23
24#if !defined(WAI_MALLOC) || !defined(WAI_FREE) || !defined(WAI_REALLOC)
25#include <stdlib.h>
26#endif
27
28#if !defined(WAI_MALLOC)
29#define WAI_MALLOC(size) malloc(size)
30#endif
31
32#if !defined(WAI_FREE)
33#define WAI_FREE(p) free(p)
34#endif
35
36#if !defined(WAI_REALLOC)
37#define WAI_REALLOC(p, size) realloc(p, size)
38#endif
39
40#ifndef WAI_NOINLINE
41#if defined(_MSC_VER)
42#define WAI_NOINLINE __declspec(noinline)
43#elif defined(__GNUC__)
44#define WAI_NOINLINE __attribute__((noinline))
45#else
46#error unsupported compiler
47#endif
48#endif
49
50#if defined(_MSC_VER)
51#define WAI_RETURN_ADDRESS() _ReturnAddress()
52#elif defined(__GNUC__)
53#define WAI_RETURN_ADDRESS() \
54 __builtin_extract_return_addr(__builtin_return_address(0))
55#else
56#error unsupported compiler
57#endif
58
59#if defined(_WIN32)
60
61#ifndef WIN32_LEAN_AND_MEAN
62#define WIN32_LEAN_AND_MEAN
63#endif
64#if defined(_MSC_VER)
65#pragma warning(push, 3)
66#endif
67#include <intrin.h>
68#include <windows.h>
69#if defined(_MSC_VER)
70#pragma warning(pop)
71#endif
72#include <stdbool.h>
73
74static int WAI_PREFIX(getModulePath_)(HMODULE module, char* out, int capacity,
75 int* dirname_length) {
76 wchar_t buffer1[MAX_PATH];
77 wchar_t buffer2[MAX_PATH];
78 wchar_t* path = NULL;
79 int length = -1;
80 bool ok;
81
82 for (ok = false; !ok; ok = true) {
83 DWORD size;
84 int length_, length__;
85
86 size = GetModuleFileNameW(module, buffer1,
87 sizeof(buffer1) / sizeof(buffer1[0]));
88
89 if (size == 0)
90 break;
91 else if (size == (DWORD)(sizeof(buffer1) / sizeof(buffer1[0]))) {
92 DWORD size_ = size;
93 do {
94 wchar_t* path_;
95
96 path_ = (wchar_t*)WAI_REALLOC(path, sizeof(wchar_t) * size_ * 2);
97 if (!path_) break;
98 size_ *= 2;
99 path = path_;
100 size = GetModuleFileNameW(module, path, size_);
101 } while (size == size_);
102
103 if (size == size_) break;
104 } else
105 path = buffer1;
106
107 if (!_wfullpath(buffer2, path, MAX_PATH)) break;
108 length_ = (int)wcslen(buffer2);
109 length__ = WideCharToMultiByte(CP_UTF8, 0, buffer2, length_, out, capacity,
110 NULL, NULL);
111
112 if (length__ == 0)
113 length__ = WideCharToMultiByte(CP_UTF8, 0, buffer2, length_, NULL, 0,
114 NULL, NULL);
115 if (length__ == 0) break;
116
117 if (length__ <= capacity && dirname_length) {
118 int i;
119
120 for (i = length__ - 1; i >= 0; --i) {
121 if (out[i] == '\\') {
122 *dirname_length = i;
123 break;
124 }
125 }
126 }
127
128 length = length__;
129 }
130
131 if (path != buffer1) WAI_FREE(path);
132
133 return ok ? length : -1;
134}
135
136WAI_NOINLINE WAI_FUNCSPEC int WAI_PREFIX(getExecutablePath)(
137 char* out, int capacity, int* dirname_length) {
138 return WAI_PREFIX(getModulePath_)(NULL, out, capacity, dirname_length);
139}
140
141WAI_NOINLINE WAI_FUNCSPEC int WAI_PREFIX(getModulePath)(char* out, int capacity,
142 int* dirname_length) {
143 HMODULE module;
144 int length = -1;
145
146#if defined(_MSC_VER)
147#pragma warning(push)
148#pragma warning(disable : 4054)
149#endif
150 if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
151 GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
152 (LPCTSTR)WAI_RETURN_ADDRESS(), &module))
153#if defined(_MSC_VER)
154#pragma warning(pop)
155#endif
156 {
157 length = WAI_PREFIX(getModulePath_)(module, out, capacity, dirname_length);
158 }
159
160 return length;
161}
162
163#elif defined(__linux__) || defined(__CYGWIN__) || defined(__sun) || \
164 defined(WAI_USE_PROC_SELF_EXE)
165
166#include <stdio.h>
167#include <stdlib.h>
168#include <string.h>
169#if defined(__linux__)
170#include <linux/limits.h>
171#else
172#include <limits.h>
173#endif
174#ifndef __STDC_FORMAT_MACROS
175#define __STDC_FORMAT_MACROS
176#endif
177#include <inttypes.h>
178#include <stdbool.h>
179
180#if !defined(WAI_PROC_SELF_EXE)
181#if defined(__sun)
182#define WAI_PROC_SELF_EXE "/proc/self/path/a.out"
183#else
184#define WAI_PROC_SELF_EXE "/proc/self/exe"
185#endif
186#endif
187
188WAI_FUNCSPEC
189int WAI_PREFIX(getExecutablePath)(char* out, int capacity,
190 int* dirname_length) {
191 char buffer[PATH_MAX];
192 char* resolved = NULL;
193 int length = -1;
194 bool ok;
195
196 for (ok = false; !ok; ok = true) {
197 resolved = realpath(WAI_PROC_SELF_EXE, buffer);
198 if (!resolved) break;
199
200 length = (int)strlen(resolved);
201 if (length <= capacity) {
202 memcpy(out, resolved, length);
203
204 if (dirname_length) {
205 int i;
206
207 for (i = length - 1; i >= 0; --i) {
208 if (out[i] == '/') {
209 *dirname_length = i;
210 break;
211 }
212 }
213 }
214 }
215 }
216
217 return ok ? length : -1;
218}
219
220#if !defined(WAI_PROC_SELF_MAPS_RETRY)
221#define WAI_PROC_SELF_MAPS_RETRY 5
222#endif
223
224#if !defined(WAI_PROC_SELF_MAPS)
225#if defined(__sun)
226#define WAI_PROC_SELF_MAPS "/proc/self/map"
227#else
228#define WAI_PROC_SELF_MAPS "/proc/self/maps"
229#endif
230#endif
231
232#if defined(__ANDROID__) || defined(ANDROID)
233#include <fcntl.h>
234#include <sys/mman.h>
235#include <unistd.h>
236#endif
237#include <stdbool.h>
238
239WAI_NOINLINE WAI_FUNCSPEC int WAI_PREFIX(getModulePath)(char* out, int capacity,
240 int* dirname_length) {
241 int length = -1;
242 FILE* maps = NULL;
243
244 for (int r = 0; r < WAI_PROC_SELF_MAPS_RETRY; ++r) {
245 maps = fopen(WAI_PROC_SELF_MAPS, "r");
246 if (!maps) break;
247
248 for (;;) {
249 char buffer[PATH_MAX < 1024 ? 1024 : PATH_MAX];
250 uint64_t low, high;
251 char perms[5];
252 uint64_t offset;
253 uint32_t major, minor;
254 char path[PATH_MAX];
255 uint32_t inode;
256
257 if (!fgets(buffer, sizeof(buffer), maps)) break;
258
259 if (sscanf(buffer, "%" PRIx64 "-%" PRIx64 " %s %" PRIx64 " %x:%x %u %s\n",
260 &low, &high, perms, &offset, &major, &minor, &inode,
261 path) == 8) {
262 uint64_t addr = (uintptr_t)WAI_RETURN_ADDRESS();
263 if (low <= addr && addr <= high) {
264 char* resolved;
265
266 resolved = realpath(path, buffer);
267 if (!resolved) break;
268
269 length = (int)strlen(resolved);
270#if defined(__ANDROID__) || defined(ANDROID)
271 if (length > 4 && buffer[length - 1] == 'k' &&
272 buffer[length - 2] == 'p' && buffer[length - 3] == 'a' &&
273 buffer[length - 4] == '.') {
274 int fd = open(path, O_RDONLY);
275 if (fd == -1) {
276 length = -1; // retry
277 break;
278 }
279
280 char* begin = (char*)mmap(0, offset, PROT_READ, MAP_SHARED, fd, 0);
281 if (begin == MAP_FAILED) {
282 close(fd);
283 length = -1; // retry
284 break;
285 }
286
287 char* p = begin + offset - 30; // minimum size of local file header
288 while (p >= begin) // scan backwards
289 {
290 if (*((uint32_t*)p) ==
291 0x04034b50UL) // local file header signature found
292 {
293 uint16_t length_ = *((uint16_t*)(p + 26));
294
295 if (length + 2 + length_ < (int)sizeof(buffer)) {
296 memcpy(&buffer[length], "!/", 2);
297 memcpy(&buffer[length + 2], p + 30, length_);
298 length += 2 + length_;
299 }
300
301 break;
302 }
303
304 --p;
305 }
306
307 munmap(begin, offset);
308 close(fd);
309 }
310#endif
311 if (length <= capacity) {
312 memcpy(out, resolved, length);
313
314 if (dirname_length) {
315 int i;
316
317 for (i = length - 1; i >= 0; --i) {
318 if (out[i] == '/') {
319 *dirname_length = i;
320 break;
321 }
322 }
323 }
324 }
325
326 break;
327 }
328 }
329 }
330
331 fclose(maps);
332 maps = NULL;
333
334 if (length != -1) break;
335 }
336
337 return length;
338}
339
340#elif defined(__APPLE__)
341
342#include <dlfcn.h>
343#include <limits.h>
344#include <mach-o/dyld.h>
345#include <stdbool.h>
346#include <stdlib.h>
347#include <string.h>
348
349WAI_FUNCSPEC
350int WAI_PREFIX(getExecutablePath)(char* out, int capacity,
351 int* dirname_length) {
352 char buffer1[PATH_MAX];
353 char buffer2[PATH_MAX];
354 char* path = buffer1;
355 char* resolved = NULL;
356 int length = -1;
357 bool ok;
358
359 for (ok = false; !ok; ok = true) {
360 uint32_t size = (uint32_t)sizeof(buffer1);
361 if (_NSGetExecutablePath(path, &size) == -1) {
362 path = (char*)WAI_MALLOC(size);
363 if (!_NSGetExecutablePath(path, &size)) break;
364 }
365
366 resolved = realpath(path, buffer2);
367 if (!resolved) break;
368
369 length = (int)strlen(resolved);
370 if (length <= capacity) {
371 memcpy(out, resolved, length);
372
373 if (dirname_length) {
374 int i;
375
376 for (i = length - 1; i >= 0; --i) {
377 if (out[i] == '/') {
378 *dirname_length = i;
379 break;
380 }
381 }
382 }
383 }
384 }
385
386 if (path != buffer1) WAI_FREE(path);
387
388 return ok ? length : -1;
389}
390
391WAI_NOINLINE WAI_FUNCSPEC int WAI_PREFIX(getModulePath)(char* out, int capacity,
392 int* dirname_length) {
393 char buffer[PATH_MAX];
394 char* resolved = NULL;
395 int length = -1;
396
397 for (;;) {
398 Dl_info info;
399
400 if (dladdr(WAI_RETURN_ADDRESS(), &info)) {
401 resolved = realpath(info.dli_fname, buffer);
402 if (!resolved) break;
403
404 length = (int)strlen(resolved);
405 if (length <= capacity) {
406 memcpy(out, resolved, length);
407
408 if (dirname_length) {
409 int i;
410
411 for (i = length - 1; i >= 0; --i) {
412 if (out[i] == '/') {
413 *dirname_length = i;
414 break;
415 }
416 }
417 }
418 }
419 }
420
421 break;
422 }
423
424 return length;
425}
426
427#elif defined(__QNXNTO__)
428
429#include <dlfcn.h>
430#include <limits.h>
431#include <stdbool.h>
432#include <stdio.h>
433#include <stdlib.h>
434#include <string.h>
435
436#if !defined(WAI_PROC_SELF_EXE)
437#define WAI_PROC_SELF_EXE "/proc/self/exefile"
438#endif
439
440WAI_FUNCSPEC
441int WAI_PREFIX(getExecutablePath)(char* out, int capacity,
442 int* dirname_length) {
443 char buffer1[PATH_MAX];
444 char buffer2[PATH_MAX];
445 char* resolved = NULL;
446 FILE* self_exe = NULL;
447 int length = -1;
448 bool ok;
449
450 for (ok = false; !ok; ok = true) {
451 self_exe = fopen(WAI_PROC_SELF_EXE, "r");
452 if (!self_exe) break;
453
454 if (!fgets(buffer1, sizeof(buffer1), self_exe)) break;
455
456 resolved = realpath(buffer1, buffer2);
457 if (!resolved) break;
458
459 length = (int)strlen(resolved);
460 if (length <= capacity) {
461 memcpy(out, resolved, length);
462
463 if (dirname_length) {
464 int i;
465
466 for (i = length - 1; i >= 0; --i) {
467 if (out[i] == '/') {
468 *dirname_length = i;
469 break;
470 }
471 }
472 }
473 }
474 }
475
476 fclose(self_exe);
477
478 return ok ? length : -1;
479}
480
481WAI_FUNCSPEC
482int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length) {
483 char buffer[PATH_MAX];
484 char* resolved = NULL;
485 int length = -1;
486
487 for (;;) {
488 Dl_info info;
489
490 if (dladdr(WAI_RETURN_ADDRESS(), &info)) {
491 resolved = realpath(info.dli_fname, buffer);
492 if (!resolved) break;
493
494 length = (int)strlen(resolved);
495 if (length <= capacity) {
496 memcpy(out, resolved, length);
497
498 if (dirname_length) {
499 int i;
500
501 for (i = length - 1; i >= 0; --i) {
502 if (out[i] == '/') {
503 *dirname_length = i;
504 break;
505 }
506 }
507 }
508 }
509 }
510
511 break;
512 }
513
514 return length;
515}
516
517#elif defined(__DragonFly__) || defined(__FreeBSD__) || \
518 defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)
519
520#include <dlfcn.h>
521#include <limits.h>
522#include <stdbool.h>
523#include <stdlib.h>
524#include <string.h>
525#include <sys/sysctl.h>
526#include <sys/types.h>
527
528#if defined(__OpenBSD__)
529
530#include <unistd.h>
531
532WAI_FUNCSPEC
533int WAI_PREFIX(getExecutablePath)(char* out, int capacity,
534 int* dirname_length) {
535 char buffer1[4096];
536 char buffer2[PATH_MAX];
537 char buffer3[PATH_MAX];
538 char** argv = (char**)buffer1;
539 char* resolved = NULL;
540 int length = -1;
541 bool ok;
542
543 for (ok = false; !ok; ok = true) {
544 int mib[4] = {CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV};
545 size_t size;
546
547 if (sysctl(mib, 4, NULL, &size, NULL, 0) != 0) break;
548
549 if (size > sizeof(buffer1)) {
550 argv = (char**)WAI_MALLOC(size);
551 if (!argv) break;
552 }
553
554 if (sysctl(mib, 4, argv, &size, NULL, 0) != 0) break;
555
556 if (strchr(argv[0], '/')) {
557 resolved = realpath(argv[0], buffer2);
558 if (!resolved) break;
559 } else {
560 const char* PATH = getenv("PATH");
561 if (!PATH) break;
562
563 size_t argv0_length = strlen(argv[0]);
564
565 const char* begin = PATH;
566 while (1) {
567 const char* separator = strchr(begin, ':');
568 const char* end = separator ? separator : begin + strlen(begin);
569
570 if (end - begin > 0) {
571 if (*(end - 1) == '/') --end;
572
573 if (((end - begin) + 1 + argv0_length + 1) <= sizeof(buffer2)) {
574 memcpy(buffer2, begin, end - begin);
575 buffer2[end - begin] = '/';
576 memcpy(buffer2 + (end - begin) + 1, argv[0], argv0_length + 1);
577
578 resolved = realpath(buffer2, buffer3);
579 if (resolved) break;
580 }
581 }
582
583 if (!separator) break;
584
585 begin = ++separator;
586 }
587
588 if (!resolved) break;
589 }
590
591 length = (int)strlen(resolved);
592 if (length <= capacity) {
593 memcpy(out, resolved, length);
594
595 if (dirname_length) {
596 int i;
597
598 for (i = length - 1; i >= 0; --i) {
599 if (out[i] == '/') {
600 *dirname_length = i;
601 break;
602 }
603 }
604 }
605 }
606 }
607
608 if (argv != (char**)buffer1) WAI_FREE(argv);
609
610 return ok ? length : -1;
611}
612
613#else
614
615WAI_FUNCSPEC
616int WAI_PREFIX(getExecutablePath)(char* out, int capacity,
617 int* dirname_length) {
618 char buffer1[PATH_MAX];
619 char buffer2[PATH_MAX];
620 char* path = buffer1;
621 char* resolved = NULL;
622 int length = -1;
623 bool ok;
624
625 for (ok = false; !ok; ok = true) {
626#if defined(__NetBSD__)
627 int mib[4] = {CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME};
628#else
629 int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
630#endif
631 size_t size = sizeof(buffer1);
632
633 if (sysctl(mib, 4, path, &size, NULL, 0) != 0) break;
634
635 resolved = realpath(path, buffer2);
636 if (!resolved) break;
637
638 length = (int)strlen(resolved);
639 if (length <= capacity) {
640 memcpy(out, resolved, length);
641
642 if (dirname_length) {
643 int i;
644
645 for (i = length - 1; i >= 0; --i) {
646 if (out[i] == '/') {
647 *dirname_length = i;
648 break;
649 }
650 }
651 }
652 }
653 }
654
655 return ok ? length : -1;
656}
657
658#endif
659
660WAI_NOINLINE WAI_FUNCSPEC int WAI_PREFIX(getModulePath)(char* out, int capacity,
661 int* dirname_length) {
662 char buffer[PATH_MAX];
663 char* resolved = NULL;
664 int length = -1;
665
666 for (;;) {
667 Dl_info info;
668
669 if (dladdr(WAI_RETURN_ADDRESS(), &info)) {
670 resolved = realpath(info.dli_fname, buffer);
671 if (!resolved) break;
672
673 length = (int)strlen(resolved);
674 if (length <= capacity) {
675 memcpy(out, resolved, length);
676
677 if (dirname_length) {
678 int i;
679
680 for (i = length - 1; i >= 0; --i) {
681 if (out[i] == '/') {
682 *dirname_length = i;
683 break;
684 }
685 }
686 }
687 }
688 }
689
690 break;
691 }
692
693 return length;
694}
695
696#else
697
698#error unsupported platform
699
700#endif
701
702#ifdef __cplusplus
703}
704#endif
diff --git a/vendor/whereami/whereami.h b/vendor/whereami/whereami.h new file mode 100644 index 0000000..8988f1d --- /dev/null +++ b/vendor/whereami/whereami.h
@@ -0,0 +1,67 @@
1// (‑●‑●)> dual licensed under the WTFPL v2 and MIT licenses
2// without any warranty.
3// by Gregory Pakosz (@gpakosz)
4// https://github.com/gpakosz/whereami
5
6#ifndef WHEREAMI_H
7#define WHEREAMI_H
8
9#ifdef __cplusplus
10extern "C" {
11#endif
12
13#ifndef WAI_FUNCSPEC
14#define WAI_FUNCSPEC
15#endif
16#ifndef WAI_PREFIX
17#define WAI_PREFIX(function) wai_##function
18#endif
19
20/**
21 * Returns the path to the current executable.
22 *
23 * Usage:
24 * - first call `int length = wai_getExecutablePath(NULL, 0, NULL);` to
25 * retrieve the length of the path
26 * - allocate the destination buffer with `path = (char*)malloc(length + 1);`
27 * - call `wai_getExecutablePath(path, length, NULL)` again to retrieve the
28 * path
29 * - add a terminal NUL character with `path[length] = '\0';`
30 *
31 * @param out destination buffer, optional
32 * @param capacity destination buffer capacity
33 * @param dirname_length optional recipient for the length of the dirname part
34 * of the path.
35 *
36 * @return the length of the executable path on success (without a terminal NUL
37 * character), otherwise `-1`
38 */
39WAI_FUNCSPEC
40int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length);
41
42/**
43 * Returns the path to the current module
44 *
45 * Usage:
46 * - first call `int length = wai_getModulePath(NULL, 0, NULL);` to retrieve
47 * the length of the path
48 * - allocate the destination buffer with `path = (char*)malloc(length + 1);`
49 * - call `wai_getModulePath(path, length, NULL)` again to retrieve the path
50 * - add a terminal NUL character with `path[length] = '\0';`
51 *
52 * @param out destination buffer, optional
53 * @param capacity destination buffer capacity
54 * @param dirname_length optional recipient for the length of the dirname part
55 * of the path.
56 *
57 * @return the length of the module path on success (without a terminal NUL
58 * character), otherwise `-1`
59 */
60WAI_FUNCSPEC
61int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length);
62
63#ifdef __cplusplus
64}
65#endif
66
67#endif // #ifndef WHEREAMI_H