1 /*
2 * BinReloc - a library for creating relocatable executables
3 * Written by: Mike Hearn <mike@theoretic.com>
4 * Hongli Lai <h.lai@chello.nl>
5 * http://autopackage.org/
6 *
7 * This source code is public domain. You can relicense this code
8 * under whatever license you want.
9 *
10 * NOTE: if you're using C++ and are getting "undefined reference
11 * to br_*", try renaming prefix.c to prefix.cpp
12 */
14 /* WARNING, BEFORE YOU MODIFY PREFIX.C:
15 *
16 * If you make changes to any of the functions in prefix.c, you MUST
17 * change the BR_NAMESPACE macro (in prefix.h).
18 * This way you can avoid symbol table conflicts with other libraries
19 * that also happen to use BinReloc.
20 *
21 * Example:
22 * #define BR_NAMESPACE(funcName) foobar_ ## funcName
23 * --> expands br_locate to foobar_br_locate
24 */
26 #ifndef _PREFIX_C_
27 #define _PREFIX_C_
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
34 #include <glib.h>
35 #include <cstdlib>
36 #include <cstdio>
37 #include <cstring>
38 #include <limits.h>
39 #include "prefix.h"
42 #ifdef __cplusplus
43 extern "C" {
44 #endif /* __cplusplus */
47 #undef NULL
48 #define NULL ((void *) 0)
50 #ifdef __GNUC__
51 #define br_return_val_if_fail(expr,val) if (!(expr)) {fprintf (stderr, "** BinReloc (%s): assertion %s failed\n", __PRETTY_FUNCTION__, #expr); return val;}
52 #else
53 #define br_return_val_if_fail(expr,val) if (!(expr)) return val
54 #endif /* __GNUC__ */
57 #ifdef ENABLE_BINRELOC
59 #include <sys/types.h>
60 #include <sys/stat.h>
61 #include <sys/param.h>
62 #include <unistd.h>
64 /**
65 * br_locate:
66 * symbol: A symbol that belongs to the app/library you want to locate.
67 * Returns: A newly allocated string containing the full path of the
68 * app/library that func belongs to, or NULL on error. This
69 * string should be freed when not when no longer needed.
70 *
71 * Finds out to which application or library symbol belongs, then locate
72 * the full path of that application or library.
73 * Note that symbol cannot be a pointer to a function. That will not work.
74 *
75 * Example:
76 * --> main.c
77 * #include "prefix.h"
78 * #include "libfoo.h"
79 *
80 * int main (int argc, char *argv[]) {
81 * printf ("Full path of this app: %s\n", br_locate (&argc));
82 * libfoo_start ();
83 * return 0;
84 * }
85 *
86 * --> libfoo.c starts here
87 * #include "prefix.h"
88 *
89 * void libfoo_start () {
90 * --> "" is a symbol that belongs to libfoo (because it's called
91 * --> from libfoo_start()); that's why this works.
92 * printf ("libfoo is located in: %s\n", br_locate (""));
93 * }
94 */
95 char *
96 br_locate (void *symbol)
97 {
98 char line[5000];
99 FILE *f;
100 char *path;
102 br_return_val_if_fail (symbol != NULL, NULL);
104 f = fopen ("/proc/self/maps", "r");
105 if (!f)
106 return NULL;
108 while (!feof (f))
109 {
110 unsigned long start, end;
112 if (!fgets (line, sizeof (line), f))
113 continue;
114 if (!strstr (line, " r-xp ") || !strchr (line, '/'))
115 continue;
117 sscanf (line, "%lx-%lx ", &start, &end);
118 if (symbol >= (void *) start && symbol < (void *) end)
119 {
120 char *tmp;
121 size_t len;
123 /* Extract the filename; it is always an absolute path */
124 path = strchr (line, '/');
126 /* Get rid of the newline */
127 tmp = strrchr (path, '\n');
128 if (tmp) *tmp = 0;
130 /* Get rid of "(deleted)" */
131 len = strlen (path);
132 if (len > 10 && strcmp (path + len - 10, " (deleted)") == 0)
133 {
134 tmp = path + len - 10;
135 *tmp = 0;
136 }
138 fclose(f);
139 return strdup (path);
140 }
141 }
143 fclose (f);
144 return NULL;
145 }
148 /**
149 * br_locate_prefix:
150 * symbol: A symbol that belongs to the app/library you want to locate.
151 * Returns: A prefix. This string should be freed when no longer needed.
152 *
153 * Locates the full path of the app/library that symbol belongs to, and return
154 * the prefix of that path, or NULL on error.
155 * Note that symbol cannot be a pointer to a function. That will not work.
156 *
157 * Example:
158 * --> This application is located in /usr/bin/foo
159 * br_locate_prefix (&argc); --> returns: "/usr"
160 */
161 char *
162 br_locate_prefix (void *symbol)
163 {
164 char *path, *prefix;
166 br_return_val_if_fail (symbol != NULL, NULL);
168 path = br_locate (symbol);
169 if (!path) return NULL;
171 prefix = br_extract_prefix (path);
172 free (path);
173 return prefix;
174 }
177 /**
178 * br_prepend_prefix:
179 * symbol: A symbol that belongs to the app/library you want to locate.
180 * path: The path that you want to prepend the prefix to.
181 * Returns: The new path, or NULL on error. This string should be freed when no
182 * longer needed.
183 *
184 * Gets the prefix of the app/library that symbol belongs to. Prepend that prefix to path.
185 * Note that symbol cannot be a pointer to a function. That will not work.
186 *
187 * Example:
188 * --> The application is /usr/bin/foo
189 * br_prepend_prefix (&argc, "/share/foo/data.png"); --> Returns "/usr/share/foo/data.png"
190 */
191 char *
192 br_prepend_prefix (void *symbol, char *path)
193 {
194 char *tmp, *newpath;
196 br_return_val_if_fail (symbol != NULL, NULL);
197 br_return_val_if_fail (path != NULL, NULL);
199 tmp = br_locate_prefix (symbol);
200 if (!tmp) return NULL;
202 if (strcmp (tmp, "/") == 0)
203 newpath = strdup (path);
204 else
205 newpath = br_strcat (tmp, path);
207 /* Get rid of compiler warning ("br_prepend_prefix never used") */
208 if (0) br_prepend_prefix (NULL, NULL);
210 free (tmp);
211 return newpath;
212 }
214 #endif /* ENABLE_BINRELOC */
217 /* Thread stuff for thread safetiness */
218 #if BR_THREADS
220 GPrivate* br_thread_key = (GPrivate *)NULL;
222 /*
223 We do not need local store init() or fini(), because
224 g_private_new (g_free) will take care of all of that
225 for us. Isn't GLib wonderful?
226 */
228 #else /* !BR_THREADS */
230 static char *br_last_value = (char*)NULL;
232 static void
233 br_free_last_value ()
234 {
235 if (br_last_value)
236 free (br_last_value);
237 }
239 #endif /* BR_THREADS */
242 /**
243 * br_thread_local_store:
244 * str: A dynamically allocated string.
245 * Returns: str. This return value must not be freed.
246 *
247 * Store str in a thread-local variable and return str. The next
248 * you run this function, that variable is freed too.
249 * This function is created so you don't have to worry about freeing
250 * strings.
251 *
252 * Example:
253 * char *foo;
254 * foo = thread_local_store (strdup ("hello")); --> foo == "hello"
255 * foo = thread_local_store (strdup ("world")); --> foo == "world"; "hello" is now freed.
256 */
257 const char *
258 br_thread_local_store (char *str)
259 {
260 #if BR_THREADS
261 if (!g_thread_supported ())
262 {
263 g_thread_init ((GThreadFunctions *)NULL);
264 br_thread_key = g_private_new (g_free);
265 }
267 char *specific = (char *) g_private_get (br_thread_key);
268 if (specific)
269 free (specific);
270 g_private_set (br_thread_key, str);
272 #else /* !BR_THREADS */
273 static int initialized = 0;
275 if (!initialized)
276 {
277 atexit (br_free_last_value);
278 initialized = 1;
279 }
281 if (br_last_value)
282 free (br_last_value);
283 br_last_value = str;
284 #endif /* BR_THREADS */
286 return (const char *) str;
287 }
290 /**
291 * br_strcat:
292 * str1: A string.
293 * str2: Another string.
294 * Returns: A newly-allocated string. This string should be freed when no longer needed.
295 *
296 * Concatenate str1 and str2 to a newly allocated string.
297 */
298 char *
299 br_strcat (const char *str1, const char *str2)
300 {
301 char *result;
302 size_t len1, len2;
304 if (!str1) str1 = "";
305 if (!str2) str2 = "";
307 len1 = strlen (str1);
308 len2 = strlen (str2);
310 result = (char *) malloc (len1 + len2 + 1);
311 memcpy (result, str1, len1);
312 memcpy (result + len1, str2, len2);
313 result[len1 + len2] = '\0';
315 return result;
316 }
319 /* Emulates glibc's strndup() */
320 static char *
321 br_strndup (char *str, size_t size)
322 {
323 char *result = (char*)NULL;
324 size_t len;
326 br_return_val_if_fail (str != (char*)NULL, (char*)NULL);
328 len = strlen (str);
329 if (!len) return strdup ("");
330 if (size > len) size = len;
332 result = (char *) calloc (sizeof (char), len + 1);
333 memcpy (result, str, size);
334 return result;
335 }
338 /**
339 * br_extract_dir:
340 * path: A path.
341 * Returns: A directory name. This string should be freed when no longer needed.
342 *
343 * Extracts the directory component of path. Similar to g_dirname() or the dirname
344 * commandline application.
345 *
346 * Example:
347 * br_extract_dir ("/usr/local/foobar"); --> Returns: "/usr/local"
348 */
349 char *
350 br_extract_dir (const char *path)
351 {
352 const char *end;
353 char *result;
355 br_return_val_if_fail (path != (char*)NULL, (char*)NULL);
357 end = strrchr (path, '/');
358 if (!end) return strdup (".");
360 while (end > path && *end == '/')
361 end--;
362 result = br_strndup ((char *) path, end - path + 1);
363 if (!*result)
364 {
365 free (result);
366 return strdup ("/");
367 } else
368 return result;
369 }
372 /**
373 * br_extract_prefix:
374 * path: The full path of an executable or library.
375 * Returns: The prefix, or NULL on error. This string should be freed when no longer needed.
376 *
377 * Extracts the prefix from path. This function assumes that your executable
378 * or library is installed in an LSB-compatible directory structure.
379 *
380 * Example:
381 * br_extract_prefix ("/usr/bin/gnome-panel"); --> Returns "/usr"
382 * br_extract_prefix ("/usr/local/lib/libfoo.so"); --> Returns "/usr/local"
383 * br_extract_prefix ("/usr/local/libfoo.so"); --> Returns "/usr"
384 */
385 char *
386 br_extract_prefix (const char *path)
387 {
388 const char *end;
389 char *tmp, *result;
391 br_return_val_if_fail (path != (char*)NULL, (char*)NULL);
393 if (!*path) return strdup ("/");
394 end = strrchr (path, '/');
395 if (!end) return strdup (path);
397 tmp = br_strndup ((char *) path, end - path);
398 if (!*tmp)
399 {
400 free (tmp);
401 return strdup ("/");
402 }
403 end = strrchr (tmp, '/');
404 if (!end) return tmp;
406 result = br_strndup (tmp, end - tmp);
407 free (tmp);
409 if (!*result)
410 {
411 free (result);
412 result = strdup ("/");
413 }
415 return result;
416 }
419 #ifdef __cplusplus
420 }
421 #endif /* __cplusplus */
425 #ifdef __WIN32__
427 /**
428 * Provide a similar mechanism for Win32. Enable a macro,
429 * WIN32_DATADIR, that can look up subpaths for inkscape resources
430 */
432 #include <windows.h>
433 #include <glibmm/ustring.h>
435 /**
436 * Return the directory of the .exe that is currently running
437 */
438 Glib::ustring win32_getExePath()
439 {
440 gunichar2 path[2048];
441 GetModuleFileNameW(0, (WCHAR*) path, 2048);
442 gchar *exe = g_utf16_to_utf8(path, -1, 0,0,0);
443 gchar *dir = g_path_get_dirname(exe);
444 Glib::ustring ret = dir;
445 g_free(dir);
446 g_free(exe);
447 return ret;
448 }
451 /**
452 * Return the relocatable version of the datadir,
453 * probably c:\inkscape
454 */
455 static Glib::ustring win32_getDataDir()
456 {
457 Glib::ustring dir = win32_getExePath();
458 if (INKSCAPE_DATADIR && *INKSCAPE_DATADIR &&
459 strcmp(INKSCAPE_DATADIR, ".") != 0)
460 {
461 dir += "\\";
462 dir += INKSCAPE_DATADIR;
463 }
464 return dir;
465 }
467 static Glib::ustring win32_getResourcePath(const Glib::ustring &childPath)
468 {
469 Glib::ustring dir = win32_getDataDir();
470 if (childPath.size() > 0)
471 {
472 dir += "\\";
473 dir += childPath;
474 }
475 return dir;
476 }
479 /**
480 * This is the visible utility function
481 */
482 char *win32_relative_path(const char *childPath)
483 {
484 static char *returnPath = 0;
485 if (!childPath)
486 childPath = "";
487 Glib::ustring resourcePath = win32_getResourcePath(childPath);
488 if (returnPath)
489 free(returnPath);
490 returnPath = strdup(resourcePath.c_str());
491 return returnPath;
492 }
493 #endif /* __WIN32__ */
498 #endif /* _PREFIX_C */