Graphviz 14.1.2~dev.20260123.1158
Loading...
Searching...
No Matches
gv_find_me.c
Go to the documentation of this file.
1#ifndef NO_CONFIG // defined by ../../tests/test_gv_find_me.c
2#include "config.h"
3#endif
4
5#include <assert.h>
6#include <stdbool.h>
7#include <stdint.h>
8#include <stdlib.h>
9#include <util/gv_find_me.h>
10
11#ifdef __APPLE__
12#include <mach-o/dyld.h>
13#endif
14
15#ifdef __FreeBSD__
16#include <sys/sysctl.h>
17#include <sys/types.h>
18#endif
19
20#if defined(_WIN32) && !defined(__CYGWIN__)
21#include <windows.h>
22#endif
23
24#if !defined(_WIN32)
25#include <unistd.h>
26#endif
27
28#ifndef _WIN32
30static char *readln(const char *path) {
31
32 char *resolved = NULL;
33 size_t size = 0;
34
35 while (true) {
36
37 // expand target buffer
38 {
39 char *const r = realloc(resolved, size == 0 ? 1024 : (size * 2));
40 if (r == NULL) {
41 // failed, out-of-memory
42 free(resolved);
43 return NULL;
44 }
45 resolved = r;
46 size = size == 0 ? 1024 : (size * 2);
47 }
48
49 // attempt to resolve
50 {
51 const ssize_t written = readlink(path, resolved, size);
52 if (written < 0) {
53 break;
54 }
55 if ((size_t)written < size) {
56 // success
57 resolved[written] = '\0';
58 return resolved;
59 }
60 }
61 }
62
63 // failed
64 free(resolved);
65 return NULL;
66}
67#endif
68
69char *gv_find_me(void) {
70
71 // macOS
72#ifdef __APPLE__
73 {
74 // determine how many bytes we will need to allocate
75 uint32_t buf_size = 0;
76 const int rc = _NSGetExecutablePath(NULL, &buf_size);
77 assert(rc != 0);
78 assert(buf_size > 0);
79
80 char *path = calloc(1, buf_size);
81 if (path == NULL) {
82 // failed, out-of-memory
83 return NULL;
84 }
85
86 // retrieve the actual path
87 if (_NSGetExecutablePath(path, &buf_size) < 0) {
88 free(path);
89 return NULL;
90 }
91
92 // try to resolve any levels of symlinks if possible
93 while (true) {
94 char *const buf = readln(path);
95 if (buf == NULL)
96 return path;
97
98 free(path);
99 path = buf;
100 }
101 }
102#elif defined(_WIN32)
103 {
104 char *path = NULL;
105 DWORD path_size = 0;
106 int rc = 0;
107
108 do {
109 {
110 const DWORD size = path_size == 0 ? 1024 : (path_size * 2);
111 char *const p = realloc(path, size);
112 if (p == NULL) {
113 // failed, out-of-memory
114 free(path);
115 return NULL;
116 }
117 path = p;
118 path_size = size;
119 }
120
121 rc = GetModuleFileNameA(NULL, path, path_size);
122 if (rc == 0) {
123 free(path);
124 return NULL;
125 }
126
127 } while ((DWORD)rc == path_size);
128
129 // the Windows APIs return '\'-separated directory components, but MinGW
130 // uses '/' as the canonical directory separator, so convert these
131#ifdef __MINGW32__
132 for (size_t i = 0; path[i] != '\0'; ++i) {
133 if (path[i] == '\\') {
134 path[i] = '/';
135 }
136 }
137#endif
138
139 return path;
140 }
141#else
142
143 // Linux, Cygwin
144 char *path = readln("/proc/self/exe");
145 if (path != NULL)
146 return path;
147
148 // DragonFly BSD, FreeBSD
149 path = readln("/proc/curproc/file");
150 if (path != NULL)
151 return path;
152
153 // NetBSD
154 path = readln("/proc/curproc/exe");
155 if (path != NULL)
156 return path;
157
158// /proc-less FreeBSD
159#ifdef __FreeBSD__
160 {
161 int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
162 static const size_t MIB_LENGTH = sizeof(mib) / sizeof(mib[0]);
163
164 do {
165 // determine how long the path is
166 size_t buf_size = 0;
167 if (sysctl(mib, MIB_LENGTH, NULL, &buf_size, NULL, 0) < 0) {
168 break;
169 }
170 assert(buf_size > 0);
171
172 // make enough space for the target path
173 char *buf = calloc(1, buf_size);
174 if (buf == NULL) {
175 // failed, out-of-memory
176 return NULL;
177 }
178
179 // resolve it
180 if (sysctl(mib, MIB_LENGTH, buf, &buf_size, NULL, 0) == 0) {
181 return buf;
182 }
183 free(buf);
184 } while (0);
185 }
186#endif
187#endif
188
189 return NULL;
190}
void free(void *)
node NULL
Definition grammar.y:181
char * gv_find_me(void)
Definition gv_find_me.c:69
static char * readln(const char *path)
readlink-alike but dynamically allocates
Definition gv_find_me.c:30
platform abstraction for finding the path to yourself
Definition types.h:81