2#if !defined(WHEREAMI_H)
10#if defined(__linux__) || defined(__CYGWIN__)
12#define _DEFAULT_SOURCE
13#elif defined(__APPLE__)
14#undef _DARWIN_C_SOURCE
15#define _DARWIN_C_SOURCE
16#define _DARWIN_BETTER_REALPATH
19#if !defined(WAI_MALLOC) || !defined(WAI_FREE) || !defined(WAI_REALLOC)
23#if !defined(WAI_MALLOC)
24#define WAI_MALLOC(size) malloc(size)
28#define WAI_FREE(p) free(p)
31#if !defined(WAI_REALLOC)
32#define WAI_REALLOC(p, size) realloc(p, size)
37#define WAI_NOINLINE __declspec(noinline)
38#elif defined(__GNUC__)
39#define WAI_NOINLINE __attribute__((noinline))
41#error unsupported compiler
46#define WAI_RETURN_ADDRESS() _ReturnAddress()
47#elif defined(__GNUC__)
48#define WAI_RETURN_ADDRESS() __builtin_extract_return_addr(__builtin_return_address(0))
50#error unsupported compiler
55#ifndef WIN32_LEAN_AND_MEAN
56#define WIN32_LEAN_AND_MEAN
59#pragma warning(push, 3)
68static int WAI_PREFIX(getModulePath_)(HMODULE module,
char* out,
int capacity,
int* dirname_length)
70 wchar_t buffer1[MAX_PATH];
71 wchar_t buffer2[MAX_PATH];
76 for (ok =
false; !ok; ok =
true)
79 int length_, length__;
81 size = GetModuleFileNameW(module, buffer1,
sizeof(buffer1) /
sizeof(buffer1[0]));
85 else if (size == (DWORD)(
sizeof(buffer1) /
sizeof(buffer1[0])))
92 path_ = (
wchar_t*)
WAI_REALLOC(path,
sizeof(
wchar_t) * size_ * 2);
97 size = GetModuleFileNameW(module, path, size_);
99 while (size == size_);
107 if (!_wfullpath(buffer2, path, MAX_PATH))
109 length_ = (int)wcslen(buffer2);
110 length__ = WideCharToMultiByte(CP_UTF8, 0, buffer2, length_ , out, capacity, NULL, NULL);
113 length__ = WideCharToMultiByte(CP_UTF8, 0, buffer2, length_, NULL, 0, NULL, NULL);
117 if (length__ <= capacity && dirname_length)
121 for (i = length__ - 1; i >= 0; --i)
137 return ok ? length : -1;
143 return WAI_PREFIX(getModulePath_)(NULL, out, capacity, dirname_length);
154#pragma warning(disable: 4054)
156 if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCTSTR)WAI_RETURN_ADDRESS(), &module))
161 length =
WAI_PREFIX(getModulePath_)(module, out, capacity, dirname_length);
167#elif defined(__linux__) || defined(__CYGWIN__) || defined(__sun) || defined(WAI_USE_PROC_SELF_EXE)
172#if defined(__linux__)
173#include <linux/limits.h>
177#ifndef __STDC_FORMAT_MACROS
178#define __STDC_FORMAT_MACROS
183#if !defined(WAI_PROC_SELF_EXE)
185#define WAI_PROC_SELF_EXE "/proc/self/path/a.out"
187#define WAI_PROC_SELF_EXE "/proc/self/exe"
194 char buffer[PATH_MAX];
195 char* resolved = NULL;
199 for (ok =
false; !ok; ok =
true)
201 resolved =
realpath(WAI_PROC_SELF_EXE, buffer);
205 length = (int)strlen(resolved);
206 if (length <= capacity)
208 memcpy(out, resolved, length);
214 for (i = length - 1; i >= 0; --i)
226 return ok ? length : -1;
229#if !defined(WAI_PROC_SELF_MAPS_RETRY)
230#define WAI_PROC_SELF_MAPS_RETRY 5
233#if !defined(WAI_PROC_SELF_MAPS)
235#define WAI_PROC_SELF_MAPS "/proc/self/map"
237#define WAI_PROC_SELF_MAPS "/proc/self/maps"
241#if defined(__ANDROID__) || defined(ANDROID)
254 for (
int r = 0; r < WAI_PROC_SELF_MAPS_RETRY; ++r)
256 maps = fopen(WAI_PROC_SELF_MAPS,
"r");
262 char buffer[PATH_MAX < 1024 ? 1024 : PATH_MAX];
266 uint32_t major, minor;
270 if (!fgets(buffer,
sizeof(buffer), maps))
273 if (sscanf(buffer,
"%" PRIx64
"-%" PRIx64
" %s %" PRIx64
" %x:%x %u %s\n", &low, &high, perms, &offset, &major, &minor, &inode, path) == 8)
275 uint64_t addr = (uintptr_t)WAI_RETURN_ADDRESS();
276 if (low <= addr && addr <= high)
284 length = (int)strlen(resolved);
285#if defined(__ANDROID__) || defined(ANDROID)
287 &&buffer[length - 1] ==
'k'
288 &&buffer[length - 2] ==
'p'
289 &&buffer[length - 3] ==
'a'
290 &&buffer[length - 4] ==
'.')
292 int fd = open(path, O_RDONLY);
299 char* begin = (
char*)mmap(0, offset, PROT_READ, MAP_SHARED, fd, 0);
300 if (begin == MAP_FAILED)
307 char* p = begin + offset - 30;
310 if (*((uint32_t*)p) == 0x04034b50UL)
312 uint16_t length_ = *((uint16_t*)(p + 26));
314 if (length + 2 + length_ < (
int)
sizeof(buffer))
316 memcpy(&buffer[length],
"!/", 2);
317 memcpy(&buffer[length + 2], p + 30, length_);
318 length += 2 + length_;
327 munmap(begin, offset);
331 if (length <= capacity)
333 memcpy(out, resolved, length);
339 for (i = length - 1; i >= 0; --i)
365#elif defined(__APPLE__)
367#include <mach-o/dyld.h>
377 char buffer1[PATH_MAX];
378 char buffer2[PATH_MAX];
379 char* path = buffer1;
380 char* resolved = NULL;
384 for (ok =
false; !ok; ok =
true)
386 uint32_t size = (uint32_t)
sizeof(buffer1);
387 if (_NSGetExecutablePath(path, &size) == -1)
390 if (!_NSGetExecutablePath(path, &size))
398 length = (int)strlen(resolved);
399 if (length <= capacity)
401 memcpy(out, resolved, length);
407 for (i = length - 1; i >= 0; --i)
422 return ok ? length : -1;
428 char buffer[PATH_MAX];
429 char* resolved = NULL;
436 if (dladdr(WAI_RETURN_ADDRESS(), &info))
438 resolved =
realpath(info.dli_fname, buffer);
442 length = (int)strlen(resolved);
443 if (length <= capacity)
445 memcpy(out, resolved, length);
451 for (i = length - 1; i >= 0; --i)
469#elif defined(__QNXNTO__)
478#if !defined(WAI_PROC_SELF_EXE)
479#define WAI_PROC_SELF_EXE "/proc/self/exefile"
485 char buffer1[PATH_MAX];
486 char buffer2[PATH_MAX];
487 char* resolved = NULL;
488 FILE* self_exe = NULL;
492 for (ok =
false; !ok; ok =
true)
494 self_exe = fopen(WAI_PROC_SELF_EXE,
"r");
498 if (!fgets(buffer1,
sizeof(buffer1), self_exe))
501 resolved =
realpath(buffer1, buffer2);
505 length = (int)strlen(resolved);
506 if (length <= capacity)
508 memcpy(out, resolved, length);
514 for (i = length - 1; i >= 0; --i)
528 return ok ? length : -1;
534 char buffer[PATH_MAX];
535 char* resolved = NULL;
542 if (dladdr(WAI_RETURN_ADDRESS(), &info))
544 resolved =
realpath(info.dli_fname, buffer);
548 length = (int)strlen(resolved);
549 if (length <= capacity)
551 memcpy(out, resolved, length);
557 for (i = length - 1; i >= 0; --i)
575#elif defined(__DragonFly__) || defined(__FreeBSD__) || \
576 defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)
581#include <sys/types.h>
582#include <sys/sysctl.h>
586#if defined(__OpenBSD__)
594 char buffer2[PATH_MAX];
595 char buffer3[PATH_MAX];
596 char** argv = (
char**)buffer1;
597 char* resolved = NULL;
601 for (ok =
false; !ok; ok =
true)
603 int mib[4] = { CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV };
606 if (sysctl(mib, 4, NULL, &size, NULL, 0) != 0)
609 if (size >
sizeof(buffer1))
616 if (sysctl(mib, 4, argv, &size, NULL, 0) != 0)
619 if (strchr(argv[0],
'/'))
621 resolved =
realpath(argv[0], buffer2);
627 const char* PATH = getenv(
"PATH");
631 size_t argv0_length = strlen(argv[0]);
633 const char* begin = PATH;
636 const char* separator = strchr(begin,
':');
637 const char* end = separator ? separator : begin + strlen(begin);
641 if (*(end -1) ==
'/')
644 if (((end - begin) + 1 + argv0_length + 1) <=
sizeof(buffer2))
646 memcpy(buffer2, begin, end - begin);
647 buffer2[end - begin] =
'/';
648 memcpy(buffer2 + (end - begin) + 1, argv[0], argv0_length + 1);
650 resolved =
realpath(buffer2, buffer3);
666 length = (int)strlen(resolved);
667 if (length <= capacity)
669 memcpy(out, resolved, length);
675 for (i = length - 1; i >= 0; --i)
687 if (argv != (
char**)buffer1)
690 return ok ? length : -1;
698 char buffer1[PATH_MAX];
699 char buffer2[PATH_MAX];
700 char* path = buffer1;
701 char* resolved = NULL;
705 for (ok =
false; !ok; ok =
true)
707#if defined(__NetBSD__)
708 int mib[4] = { CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME };
710 int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
712 size_t size =
sizeof(buffer1);
714 if (sysctl(mib, 4, path, &size, NULL, 0) != 0)
721 length = (int)strlen(resolved);
722 if (length <= capacity)
724 memcpy(out, resolved, length);
730 for (i = length - 1; i >= 0; --i)
742 return ok ? length : -1;
750 char buffer[PATH_MAX];
751 char* resolved = NULL;
758 if (dladdr(WAI_RETURN_ADDRESS(), &info))
760 resolved =
realpath(info.dli_fname, buffer);
764 length = (int)strlen(resolved);
765 if (length <= capacity)
767 memcpy(out, resolved, length);
773 for (i = length - 1; i >= 0; --i)
793#error unsupported platform
yoi::wstr realpath(const std::wstring &path)
#define WAI_REALLOC(p, size)
WAI_FUNCSPEC int WAI_PREFIX() getExecutablePath(char *out, int capacity, int *dirname_length)
WAI_FUNCSPEC int WAI_PREFIX() getModulePath(char *out, int capacity, int *dirname_length)
#define WAI_PREFIX(function)