blob: 29fa33526cf5eda21ad130c9ad3af8ed4bb5d266 [file] [log] [blame]
/*
.Some useful path tools.
.ASCII only for now.
.Written by Ray Donnelly in 2014.
.Licensed under CC0 (and anything.
.else you need to license it under).
.No warranties whatsoever.
.email: <mingw.android@gmail.com>.
*/
#include <stdlib.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#if defined(__linux__) || defined(__CYGWIN__) || defined(__MSYS__)
#include <alloca.h>
#endif
#include <unistd.h>
/* If you don't define this, then get_executable_path()
can only use argv[0] which will often not work well */
#define IMPLEMENT_SYS_GET_EXECUTABLE_PATH
#if defined(IMPLEMENT_SYS_GET_EXECUTABLE_PATH)
#if defined(__linux__) || defined(__CYGWIN__) || defined(__MSYS__)
/* Nothing needed, unistd.h is enough. */
#elif defined(__APPLE__)
#include <mach-o/dyld.h>
#elif defined(_WIN32)
// widl can't include the normal Windows headers due to providing its own winnt.h (and others).
#ifdef __x86_64__
__attribute__((dllimport)) long GetModuleFileNameA (long hModule, void* lpFilename, long nSize);
#else
__attribute__((dllimport)) long __attribute__((__stdcall__)) GetModuleFileNameA (long hModule, void* lpFilename, long nSize);
#endif
#endif
#else
#define PATH_MAX 260
#endif /* defined(IMPLEMENT_SYS_GET_EXECUTABLE_PATH) */
#include "pathtools.h"
int
get_executable_path(char const * argv0, char * result, ssize_t max_size)
{
char * system_result = (char *) alloca (max_size);
ssize_t system_result_size = -1;
ssize_t result_size = -1;
if (system_result != NULL)
{
#if defined(IMPLEMENT_SYS_GET_EXECUTABLE_PATH)
#if defined(__linux__) || defined(__CYGWIN__) || defined(__MSYS__)
system_result_size = readlink("/proc/self/exe", system_result, max_size);
#elif defined(__APPLE__)
uint32_t bufsize = (uint32_t)max_size;
if (_NSGetExecutablePath(system_result, &bufsize) == 0)
{
system_result_size = strlen (system_result);
}
#elif defined(_WIN32)
unsigned long bufsize = (unsigned long)max_size;
system_result_size = GetModuleFileNameA(0, system_result, bufsize);
if (system_result_size == 0 || system_result_size == (ssize_t)bufsize)
{
/* Error, possibly not enough space. */
system_result_size = -1;
}
else
{
/* Early conversion to unix slashes instead of more changes
everywhere else .. */
char * winslash;
system_result[system_result_size] = '\0';
while ((winslash = strchr (system_result, '\\')) != NULL)
{
*winslash = '/';
}
}
#else
#warning "Don't know how to get executable path on this system"
#endif
#endif /* defined(IMPLEMENT_SYS_GET_EXECUTABLE_PATH) */
}
/* Use argv0 as a default in-case of failure */
if (system_result_size != -1)
{
strncpy (result, system_result, system_result_size);
result[system_result_size] = '\0';
}
else
{
if (argv0 != NULL)
{
strncpy (result, argv0, max_size);
char *slash;
while ((slash = strchr(result, '\\')) != NULL) {
*slash++ = '/';
}
result[max_size-1] = '\0';
}
else
{
result[0] = '\0';
}
}
result_size = strlen (result);
return result_size;
}