1 // (‑●‑●)> released under the WTFPL v2 license, by Gregory Pakosz (@gpakosz)
2 // https://github.com/gpakosz/whereami
4 // in case you want to #include "whereami.c" in a larger compilation unit
5 #if !defined(WHEREAMI_H)
13 #if defined(__linux__)
14 // make realpath() available:
15 #define _DEFAULT_SOURCE
18 #if !defined(WAI_MALLOC) || !defined(WAI_FREE) || !defined(WAI_REALLOC)
22 #if !defined(WAI_MALLOC)
23 #define WAI_MALLOC(size) malloc(size)
26 #if !defined(WAI_FREE)
27 #define WAI_FREE(p) free(p)
30 #if !defined(WAI_REALLOC)
31 #define WAI_REALLOC(p, size) realloc(p, size)
36 #define WAI_NOINLINE __declspec(noinline)
37 #elif defined(__GNUC__)
38 #define WAI_NOINLINE __attribute__((noinline))
40 #error unsupported compiler
45 #define WAI_RETURN_ADDRESS() _ReturnAddress()
46 #elif defined(__GNUC__)
47 #define WAI_RETURN_ADDRESS() __builtin_extract_return_addr(__builtin_return_address(0))
49 #error unsupported compiler
54 #define WIN32_LEAN_AND_MEAN
56 #pragma warning(push, 3)
59 //#include <intrin.h> // not required and doesn't exist in old mingw environments
64 static int WAI_PREFIX(getModulePath_
)(HMODULE module
, char* out
, int capacity
, int* dirname_length
)
66 wchar_t buffer1
[MAX_PATH
];
67 wchar_t buffer2
[MAX_PATH
];
74 int length_
, length__
;
76 size
= GetModuleFileNameW(module
, buffer1
, sizeof(buffer1
) / sizeof(buffer1
[0]));
80 else if (size
== (DWORD
)(sizeof(buffer1
) / sizeof(buffer1
[0])))
87 path_
= (wchar_t*)WAI_REALLOC(path
, sizeof(wchar_t) * size_
* 2);
92 size
= GetModuleFileNameW(module
, path
, size_
);
94 while (size
== size_
);
102 if (!_wfullpath(buffer2
, path
, MAX_PATH
))
104 length_
= (int)wcslen(buffer2
);
105 length__
= WideCharToMultiByte(CP_UTF8
, 0, buffer2
, length_
, out
, capacity
, NULL
, NULL
);
108 length__
= WideCharToMultiByte(CP_UTF8
, 0, buffer2
, length_
, NULL
, 0, NULL
, NULL
);
112 if (length__
<= capacity
&& dirname_length
)
116 for (i
= length__
- 1; i
>= 0; --i
)
139 int WAI_PREFIX(getExecutablePath
)(char* out
, int capacity
, int* dirname_length
)
141 return WAI_PREFIX(getModulePath_
)(NULL
, out
, capacity
, dirname_length
);
144 // GetModuleHandleEx() is not available on old mingw environments. We don't need getModulePath() yet.
145 // Sacrifice it for the time being to improve backwards compatibility
148 int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
153 #if defined(_MSC_VER)
154 #pragma warning(push)
155 #pragma warning(disable: 4054)
157 if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCTSTR)WAI_RETURN_ADDRESS(), &module))
158 #if defined(_MSC_VER)
162 length = WAI_PREFIX(getModulePath_)(module, out, capacity, dirname_length);
169 #elif defined(__linux__)
174 // #include <limits.h> // not all linux distributions define PATH_MAX in limits.h because it depends on the filesystem. Therefore use...
175 #include <linux/limits.h>
176 #ifndef __STDC_FORMAT_MACROS
177 #define __STDC_FORMAT_MACROS
179 #include <inttypes.h>
181 #if !defined(WAI_PROC_SELF_EXE)
182 #define WAI_PROC_SELF_EXE "/proc/self/exe"
186 int WAI_PREFIX(getExecutablePath
)(char* out
, int capacity
, int* dirname_length
)
188 char buffer
[PATH_MAX
];
189 char* resolved
= NULL
;
194 resolved
= realpath(WAI_PROC_SELF_EXE
, buffer
);
198 length
= (int)strlen(resolved
);
199 if (length
<= capacity
)
201 memcpy(out
, resolved
, length
);
207 for (i
= length
- 1; i
>= 0; --i
)
224 #if !defined(WAI_PROC_SELF_MAPS_RETRY)
225 #define WAI_PROC_SELF_MAPS_RETRY 5
228 #if !defined(WAI_PROC_SELF_MAPS)
229 #define WAI_PROC_SELF_MAPS "/proc/self/maps"
232 #if defined(__ANDROID__) || defined(ANDROID)
234 #include <sys/mman.h>
239 int WAI_PREFIX(getModulePath
)(char* out
, int capacity
, int* dirname_length
)
245 for (i
= 0; i
< WAI_PROC_SELF_MAPS_RETRY
; ++i
)
247 maps
= fopen(WAI_PROC_SELF_MAPS
, "r");
253 char buffer
[PATH_MAX
< 1024 ? 1024 : PATH_MAX
];
257 uint32_t major
, minor
;
261 if (!fgets(buffer
, sizeof(buffer
), maps
))
264 if (sscanf(buffer
, "%" SCNx64
"-%" SCNx64
" %s %" SCNx64
" %x:%x %u %s\n", &low
, &high
, perms
, &offset
, &major
, &minor
, &inode
, path
) == 8)
266 uint64_t addr
= (uint64_t)(uintptr_t)WAI_RETURN_ADDRESS();
267 if (low
<= addr
&& addr
<= high
)
271 resolved
= realpath(path
, buffer
);
275 length
= (int)strlen(resolved
);
276 #if defined(__ANDROID__) || defined(ANDROID)
278 &&buffer
[length
- 1] == 'k'
279 &&buffer
[length
- 2] == 'p'
280 &&buffer
[length
- 3] == 'a'
281 &&buffer
[length
- 4] == '.')
283 int fd
= open(path
, O_RDONLY
);
287 begin
= (char*)mmap(0, offset
, PROT_READ
, MAP_SHARED
, fd
, 0);
290 while (p
>= begin
) // scan backwards
292 if (*((uint32_t*)p
) == 0x04034b50UL
) // local file header found
294 uint16_t length_
= *((uint16_t*)(p
+ 26));
296 if (length
+ 2 + length_
< (int)sizeof(buffer
))
298 memcpy(&buffer
[length
], "!/", 2);
299 memcpy(&buffer
[length
+ 2], p
+ 30, length_
);
300 length
+= 2 + length_
;
309 munmap(begin
, offset
);
313 if (length
<= capacity
)
315 memcpy(out
, resolved
, length
);
321 for (i
= length
- 1; i
>= 0; --i
)
346 #elif defined(__APPLE__)
348 #define _DARWIN_BETTER_REALPATH
349 #include <mach-o/dyld.h>
356 int WAI_PREFIX(getExecutablePath
)(char* out
, int capacity
, int* dirname_length
)
358 char buffer1
[PATH_MAX
];
359 char buffer2
[PATH_MAX
];
360 char* path
= buffer1
;
361 char* resolved
= NULL
;
366 uint32_t size
= (uint32_t)sizeof(buffer1
);
367 if (_NSGetExecutablePath(path
, &size
) == -1)
369 path
= (char*)WAI_MALLOC(size
);
370 if (!_NSGetExecutablePath(path
, &size
))
374 resolved
= realpath(path
, buffer2
);
378 length
= (int)strlen(resolved
);
379 if (length
<= capacity
)
381 memcpy(out
, resolved
, length
);
387 for (i
= length
- 1; i
>= 0; --i
)
409 int WAI_PREFIX(getModulePath
)(char* out
, int capacity
, int* dirname_length
)
411 char buffer
[PATH_MAX
];
412 char* resolved
= NULL
;
419 if (dladdr(WAI_RETURN_ADDRESS(), &info
))
421 resolved
= realpath(info
.dli_fname
, buffer
);
425 length
= (int)strlen(resolved
);
426 if (length
<= capacity
)
428 memcpy(out
, resolved
, length
);
434 for (i
= length
- 1; i
>= 0; --i
)
452 #elif defined(__QNXNTO__)
460 #if !defined(WAI_PROC_SELF_EXE)
461 #define WAI_PROC_SELF_EXE "/proc/self/exefile"
465 int WAI_PREFIX(getExecutablePath
)(char* out
, int capacity
, int* dirname_length
)
467 char buffer1
[PATH_MAX
];
468 char buffer2
[PATH_MAX
];
469 char* resolved
= NULL
;
470 FILE* self_exe
= NULL
;
475 self_exe
= fopen(WAI_PROC_SELF_EXE
, "r");
479 if (!fgets(buffer1
, sizeof(buffer1
), self_exe
))
482 resolved
= realpath(buffer1
, buffer2
);
486 length
= (int)strlen(resolved
);
487 if (length
<= capacity
)
489 memcpy(out
, resolved
, length
);
495 for (i
= length
- 1; i
>= 0; --i
)
515 int WAI_PREFIX(getModulePath
)(char* out
, int capacity
, int* dirname_length
)
517 char buffer
[PATH_MAX
];
518 char* resolved
= NULL
;
525 if (dladdr(WAI_RETURN_ADDRESS(), &info
))
527 resolved
= realpath(info
.dli_fname
, buffer
);
531 length
= (int)strlen(resolved
);
532 if (length
<= capacity
)
534 memcpy(out
, resolved
, length
);
540 for (i
= length
- 1; i
>= 0; --i
)
558 #elif defined(__DragonFly__) || defined(__FreeBSD__) || \
559 defined(__FreeBSD_kernel__) || defined(__NetBSD__)
564 #include <sys/types.h>
565 #include <sys/sysctl.h>
569 int WAI_PREFIX(getExecutablePath
)(char* out
, int capacity
, int* dirname_length
)
571 char buffer1
[PATH_MAX
];
572 char buffer2
[PATH_MAX
];
573 char* path
= buffer1
;
574 char* resolved
= NULL
;
579 int mib
[4] = { CTL_KERN
, KERN_PROC
, KERN_PROC_PATHNAME
, -1 };
580 size_t size
= sizeof(buffer1
);
582 if (sysctl(mib
, (u_int
)(sizeof(mib
) / sizeof(mib
[0])), path
, &size
, NULL
, 0) != 0)
585 resolved
= realpath(path
, buffer2
);
589 length
= (int)strlen(resolved
);
590 if (length
<= capacity
)
592 memcpy(out
, resolved
, length
);
598 for (i
= length
- 1; i
>= 0; --i
)
620 int WAI_PREFIX(getModulePath
)(char* out
, int capacity
, int* dirname_length
)
622 char buffer
[PATH_MAX
];
623 char* resolved
= NULL
;
630 if (dladdr(WAI_RETURN_ADDRESS(), &info
))
632 resolved
= realpath(info
.dli_fname
, buffer
);
636 length
= (int)strlen(resolved
);
637 if (length
<= capacity
)
639 memcpy(out
, resolved
, length
);
645 for (i
= length
- 1; i
>= 0; --i
)
665 #error unsupported platform