Code

Correct load order of user icons.svg icons with legacy names.
[inkscape.git] / src / prefix.cpp
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;
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)
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;
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)
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;
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 ()
235     if (br_last_value)
236         free (br_last_value);
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)
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;
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)
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;
319 /* Emulates glibc's strndup() */
320 static char *
321 br_strndup (char *str, size_t size)
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;
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)
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;
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)
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;
419 #ifdef __cplusplus
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  */ 
431  
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()
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;
451 /**
452  * Return the relocatable version of the datadir,
453  * probably c:\inkscape 
454  */
455 static Glib::ustring win32_getDataDir()
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;
467 static Glib::ustring win32_getResourcePath(const Glib::ustring &childPath)
469     Glib::ustring dir = win32_getDataDir();
470     if (childPath.size() > 0)
471         {
472         dir += "\\";
473         dir += childPath;
474         }
475     return dir;
479 /**
480  * This is the visible utility function
481  */ 
482 char *win32_relative_path(const char *childPath)
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;
493 #endif /* __WIN32__ */
498 #endif /* _PREFIX_C */