Code

Create a new macro in path-prefix.h, WIN32_DATADIR, that works similarly to BR_DATADI...
[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 /* 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)
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;
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)
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;
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)
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;
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 ()
242     if (br_last_value)
243         free (br_last_value);
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)
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;
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)
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;
326 /* Emulates glibc's strndup() */
327 static char *
328 br_strndup (char *str, size_t size)
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;
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)
359         char *end, *result;
361         br_return_val_if_fail (path != (char*)NULL, (char*)NULL);
363         end = strrchr (path, '/');
364         if (!end) return strdup (".");
366         while (end > path && *end == '/')
367                 end--;
368         result = br_strndup ((char *) path, end - path + 1);
369         if (!*result)
370         {
371                 free (result);
372                 return strdup ("/");
373         } else
374                 return result;
378 /**
379  * br_extract_prefix:
380  * path: The full path of an executable or library.
381  * Returns: The prefix, or NULL on error. This string should be freed when no longer needed.
382  *
383  * Extracts the prefix from path. This function assumes that your executable
384  * or library is installed in an LSB-compatible directory structure.
385  *
386  * Example:
387  * br_extract_prefix ("/usr/bin/gnome-panel");       --> Returns "/usr"
388  * br_extract_prefix ("/usr/local/lib/libfoo.so");   --> Returns "/usr/local"
389  * br_extract_prefix ("/usr/local/libfoo.so");       --> Returns "/usr"
390  */
391 char *
392 br_extract_prefix (const char *path)
394         char *end, *tmp, *result;
396         br_return_val_if_fail (path != (char*)NULL, (char*)NULL);
398         if (!*path) return strdup ("/");
399         end = strrchr (path, '/');
400         if (!end) return strdup (path);
402         tmp = br_strndup ((char *) path, end - path);
403         if (!*tmp)
404         {
405                 free (tmp);
406                 return strdup ("/");
407         }
408         end = strrchr (tmp, '/');
409         if (!end) return tmp;
411         result = br_strndup (tmp, end - tmp);
412         free (tmp);
414         if (!*result)
415         {
416                 free (result);
417                 result = strdup ("/");
418         }
420         return result;
424 #ifdef __cplusplus
426 #endif /* __cplusplus */
430 #ifdef __WIN32__
432 /**
433  * Provide a similar mechanism for Win32.  Enable a macro,
434  * WIN32_DATADIR, that can look up subpaths for inkscape resources 
435  */ 
436  
437 #include <windows.h>
438 #include <glibmm/ustring.h>
440 /**
441  * Return the directory of the .exe that is currently running
442  */
443 static Glib::ustring win32_getExePath()
445     char exeName[MAX_PATH+1];
446     GetModuleFileName(NULL, exeName, MAX_PATH);
447     char *slashPos = strrchr(exeName, '\\');
448     if (slashPos)
449         *slashPos = '\0';
450     Glib::ustring s = exeName;
451     return s;
455 /**
456  * Return the relocatable version of the datadir,
457  * probably c:\inkscape 
458  */
459 static Glib::ustring win32_getDataDir()
461     Glib::ustring dir = win32_getExePath();
462     if (INKSCAPE_DATADIR  && *INKSCAPE_DATADIR &&
463             strcmp(INKSCAPE_DATADIR, ".") != 0)
464         {
465         dir += "\\";
466         dir += INKSCAPE_DATADIR;
467         }
468     return dir;
471 static Glib::ustring win32_getResourcePath(const Glib::ustring &childPath)
473     Glib::ustring dir = win32_getDataDir();
474     if (childPath.size() > 0)
475         {
476         dir += "\\";
477         dir += childPath;
478         }
479     return dir;
483 /**
484  * This is the visible utility function
485  */ 
486 char *win32_relative_path(const char *childPath)
488     static char *returnPath = NULL;
489     if (!childPath)
490         childPath = "";
491     Glib::ustring resourcePath = win32_getResourcePath(childPath);
492     if (returnPath)
493         free(returnPath);
494     returnPath = strdup(resourcePath.c_str());
495     return returnPath;
497 #endif /* __WIN32__ */
502 #endif /* _PREFIX_C */