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 /* PLEASE NOTE: We use GThreads now for portability */
35 /* @see http://developer.gnome.org/doc/API/2.0/glib/glib-Threads.html */
36 #ifndef BR_THREADS
37 /* Change 1 to 0 if you don't want thread support */
38 #define BR_THREADS 1
39 #include <glib.h> //for GThreads
40 #endif /* BR_THREADS */
42 #include <cstdlib>
43 #include <cstdio>
44 #include <cstring>
45 #include <limits.h>
46 #include "prefix.h"
49 #ifdef __cplusplus
50 extern "C" {
51 #endif /* __cplusplus */
54 #undef NULL
55 #define NULL ((void *) 0)
57 #ifdef __GNUC__
58 #define br_return_val_if_fail(expr,val) if (!(expr)) {fprintf (stderr, "** BinReloc (%s): assertion %s failed\n", __PRETTY_FUNCTION__, #expr); return val;}
59 #else
60 #define br_return_val_if_fail(expr,val) if (!(expr)) return val
61 #endif /* __GNUC__ */
64 #ifdef ENABLE_BINRELOC
66 #include <sys/types.h>
67 #include <sys/stat.h>
68 #include <sys/param.h>
69 #include <unistd.h>
71 /**
72 * br_locate:
73 * symbol: A symbol that belongs to the app/library you want to locate.
74 * Returns: A newly allocated string containing the full path of the
75 * app/library that func belongs to, or NULL on error. This
76 * string should be freed when not when no longer needed.
77 *
78 * Finds out to which application or library symbol belongs, then locate
79 * the full path of that application or library.
80 * Note that symbol cannot be a pointer to a function. That will not work.
81 *
82 * Example:
83 * --> main.c
84 * #include "prefix.h"
85 * #include "libfoo.h"
86 *
87 * int main (int argc, char *argv[]) {
88 * printf ("Full path of this app: %s\n", br_locate (&argc));
89 * libfoo_start ();
90 * return 0;
91 * }
92 *
93 * --> libfoo.c starts here
94 * #include "prefix.h"
95 *
96 * void libfoo_start () {
97 * --> "" is a symbol that belongs to libfoo (because it's called
98 * --> from libfoo_start()); that's why this works.
99 * printf ("libfoo is located in: %s\n", br_locate (""));
100 * }
101 */
102 char *
103 br_locate (void *symbol)
104 {
105 char line[5000];
106 FILE *f;
107 char *path;
109 br_return_val_if_fail (symbol != NULL, NULL);
111 f = fopen ("/proc/self/maps", "r");
112 if (!f)
113 return NULL;
115 while (!feof (f))
116 {
117 unsigned long start, end;
119 if (!fgets (line, sizeof (line), f))
120 continue;
121 if (!strstr (line, " r-xp ") || !strchr (line, '/'))
122 continue;
124 sscanf (line, "%lx-%lx ", &start, &end);
125 if (symbol >= (void *) start && symbol < (void *) end)
126 {
127 char *tmp;
128 size_t len;
130 /* Extract the filename; it is always an absolute path */
131 path = strchr (line, '/');
133 /* Get rid of the newline */
134 tmp = strrchr (path, '\n');
135 if (tmp) *tmp = 0;
137 /* Get rid of "(deleted)" */
138 len = strlen (path);
139 if (len > 10 && strcmp (path + len - 10, " (deleted)") == 0)
140 {
141 tmp = path + len - 10;
142 *tmp = 0;
143 }
145 fclose(f);
146 return strdup (path);
147 }
148 }
150 fclose (f);
151 return NULL;
152 }
155 /**
156 * br_locate_prefix:
157 * symbol: A symbol that belongs to the app/library you want to locate.
158 * Returns: A prefix. This string should be freed when no longer needed.
159 *
160 * Locates the full path of the app/library that symbol belongs to, and return
161 * the prefix of that path, or NULL on error.
162 * Note that symbol cannot be a pointer to a function. That will not work.
163 *
164 * Example:
165 * --> This application is located in /usr/bin/foo
166 * br_locate_prefix (&argc); --> returns: "/usr"
167 */
168 char *
169 br_locate_prefix (void *symbol)
170 {
171 char *path, *prefix;
173 br_return_val_if_fail (symbol != NULL, NULL);
175 path = br_locate (symbol);
176 if (!path) return NULL;
178 prefix = br_extract_prefix (path);
179 free (path);
180 return prefix;
181 }
184 /**
185 * br_prepend_prefix:
186 * symbol: A symbol that belongs to the app/library you want to locate.
187 * path: The path that you want to prepend the prefix to.
188 * Returns: The new path, or NULL on error. This string should be freed when no
189 * longer needed.
190 *
191 * Gets the prefix of the app/library that symbol belongs to. Prepend that prefix to path.
192 * Note that symbol cannot be a pointer to a function. That will not work.
193 *
194 * Example:
195 * --> The application is /usr/bin/foo
196 * br_prepend_prefix (&argc, "/share/foo/data.png"); --> Returns "/usr/share/foo/data.png"
197 */
198 char *
199 br_prepend_prefix (void *symbol, char *path)
200 {
201 char *tmp, *newpath;
203 br_return_val_if_fail (symbol != NULL, NULL);
204 br_return_val_if_fail (path != NULL, NULL);
206 tmp = br_locate_prefix (symbol);
207 if (!tmp) return NULL;
209 if (strcmp (tmp, "/") == 0)
210 newpath = strdup (path);
211 else
212 newpath = br_strcat (tmp, path);
214 /* Get rid of compiler warning ("br_prepend_prefix never used") */
215 if (0) br_prepend_prefix (NULL, NULL);
217 free (tmp);
218 return newpath;
219 }
221 #endif /* ENABLE_BINRELOC */
224 /* Thread stuff for thread safetiness */
225 #if BR_THREADS
227 GPrivate* br_thread_key = (GPrivate *)NULL;
229 /*
230 We do not need local store init() or fini(), because
231 g_private_new (g_free) will take care of all of that
232 for us. Isn't GLib wonderful?
233 */
235 #else /* !BR_THREADS */
237 static char *br_last_value = (char*)NULL;
239 static void
240 br_free_last_value ()
241 {
242 if (br_last_value)
243 free (br_last_value);
244 }
246 #endif /* BR_THREADS */
249 /**
250 * br_thread_local_store:
251 * str: A dynamically allocated string.
252 * Returns: str. This return value must not be freed.
253 *
254 * Store str in a thread-local variable and return str. The next
255 * you run this function, that variable is freed too.
256 * This function is created so you don't have to worry about freeing
257 * strings.
258 *
259 * Example:
260 * char *foo;
261 * foo = thread_local_store (strdup ("hello")); --> foo == "hello"
262 * foo = thread_local_store (strdup ("world")); --> foo == "world"; "hello" is now freed.
263 */
264 const char *
265 br_thread_local_store (char *str)
266 {
267 #if BR_THREADS
268 if (!g_thread_supported ())
269 {
270 g_thread_init ((GThreadFunctions *)NULL);
271 br_thread_key = g_private_new (g_free);
272 }
274 char *specific = (char *) g_private_get (br_thread_key);
275 if (specific)
276 free (specific);
277 g_private_set (br_thread_key, str);
279 #else /* !BR_THREADS */
280 static int initialized = 0;
282 if (!initialized)
283 {
284 atexit (br_free_last_value);
285 initialized = 1;
286 }
288 if (br_last_value)
289 free (br_last_value);
290 br_last_value = str;
291 #endif /* BR_THREADS */
293 return (const char *) str;
294 }
297 /**
298 * br_strcat:
299 * str1: A string.
300 * str2: Another string.
301 * Returns: A newly-allocated string. This string should be freed when no longer needed.
302 *
303 * Concatenate str1 and str2 to a newly allocated string.
304 */
305 char *
306 br_strcat (const char *str1, const char *str2)
307 {
308 char *result;
309 size_t len1, len2;
311 if (!str1) str1 = "";
312 if (!str2) str2 = "";
314 len1 = strlen (str1);
315 len2 = strlen (str2);
317 result = (char *) malloc (len1 + len2 + 1);
318 memcpy (result, str1, len1);
319 memcpy (result + len1, str2, len2);
320 result[len1 + len2] = '\0';
322 return result;
323 }
326 /* Emulates glibc's strndup() */
327 static char *
328 br_strndup (char *str, size_t size)
329 {
330 char *result = (char*)NULL;
331 size_t len;
333 br_return_val_if_fail (str != (char*)NULL, (char*)NULL);
335 len = strlen (str);
336 if (!len) return strdup ("");
337 if (size > len) size = len;
339 result = (char *) calloc (sizeof (char), len + 1);
340 memcpy (result, str, size);
341 return result;
342 }
345 /**
346 * br_extract_dir:
347 * path: A path.
348 * Returns: A directory name. This string should be freed when no longer needed.
349 *
350 * Extracts the directory component of path. Similar to g_dirname() or the dirname
351 * commandline application.
352 *
353 * Example:
354 * br_extract_dir ("/usr/local/foobar"); --> Returns: "/usr/local"
355 */
356 char *
357 br_extract_dir (const char *path)
358 {
359 const char *end;
360 char *result;
362 br_return_val_if_fail (path != (char*)NULL, (char*)NULL);
364 end = strrchr (path, '/');
365 if (!end) return strdup (".");
367 while (end > path && *end == '/')
368 end--;
369 result = br_strndup ((char *) path, end - path + 1);
370 if (!*result)
371 {
372 free (result);
373 return strdup ("/");
374 } else
375 return result;
376 }
379 /**
380 * br_extract_prefix:
381 * path: The full path of an executable or library.
382 * Returns: The prefix, or NULL on error. This string should be freed when no longer needed.
383 *
384 * Extracts the prefix from path. This function assumes that your executable
385 * or library is installed in an LSB-compatible directory structure.
386 *
387 * Example:
388 * br_extract_prefix ("/usr/bin/gnome-panel"); --> Returns "/usr"
389 * br_extract_prefix ("/usr/local/lib/libfoo.so"); --> Returns "/usr/local"
390 * br_extract_prefix ("/usr/local/libfoo.so"); --> Returns "/usr"
391 */
392 char *
393 br_extract_prefix (const char *path)
394 {
395 const char *end;
396 char *tmp, *result;
398 br_return_val_if_fail (path != (char*)NULL, (char*)NULL);
400 if (!*path) return strdup ("/");
401 end = strrchr (path, '/');
402 if (!end) return strdup (path);
404 tmp = br_strndup ((char *) path, end - path);
405 if (!*tmp)
406 {
407 free (tmp);
408 return strdup ("/");
409 }
410 end = strrchr (tmp, '/');
411 if (!end) return tmp;
413 result = br_strndup (tmp, end - tmp);
414 free (tmp);
416 if (!*result)
417 {
418 free (result);
419 result = strdup ("/");
420 }
422 return result;
423 }
426 #ifdef __cplusplus
427 }
428 #endif /* __cplusplus */
432 #ifdef __WIN32__
434 /**
435 * Provide a similar mechanism for Win32. Enable a macro,
436 * WIN32_DATADIR, that can look up subpaths for inkscape resources
437 */
439 #include <windows.h>
440 #include <glibmm/ustring.h>
442 /**
443 * Return the directory of the .exe that is currently running
444 */
445 static Glib::ustring win32_getExePath()
446 {
447 char exeName[MAX_PATH+1];
448 GetModuleFileName(NULL, exeName, MAX_PATH);
449 char *slashPos = strrchr(exeName, '\\');
450 if (slashPos)
451 *slashPos = '\0';
452 Glib::ustring s = exeName;
453 return s;
454 }
457 /**
458 * Return the relocatable version of the datadir,
459 * probably c:\inkscape
460 */
461 static Glib::ustring win32_getDataDir()
462 {
463 Glib::ustring dir = win32_getExePath();
464 if (INKSCAPE_DATADIR && *INKSCAPE_DATADIR &&
465 strcmp(INKSCAPE_DATADIR, ".") != 0)
466 {
467 dir += "\\";
468 dir += INKSCAPE_DATADIR;
469 }
470 return dir;
471 }
473 static Glib::ustring win32_getResourcePath(const Glib::ustring &childPath)
474 {
475 Glib::ustring dir = win32_getDataDir();
476 if (childPath.size() > 0)
477 {
478 dir += "\\";
479 dir += childPath;
480 }
481 return dir;
482 }
485 /**
486 * This is the visible utility function
487 */
488 char *win32_relative_path(const char *childPath)
489 {
490 static char *returnPath = NULL;
491 if (!childPath)
492 childPath = "";
493 Glib::ustring resourcePath = win32_getResourcePath(childPath);
494 if (returnPath)
495 free(returnPath);
496 returnPath = strdup(resourcePath.c_str());
497 return returnPath;
498 }
499 #endif /* __WIN32__ */
504 #endif /* _PREFIX_C */