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