Code

moving trunk for module inkscape
[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 <stdlib.h>
43 #include <stdio.h>
44 #include <limits.h> 
45 #include <string.h>
46 #include "prefix.h"
48 #ifdef __cplusplus
49 extern "C" {
50 #endif /* __cplusplus */
53 #undef NULL
54 #define NULL ((void *) 0)
56 #ifdef __GNUC__
57         #define br_return_val_if_fail(expr,val) if (!(expr)) {fprintf (stderr, "** BinReloc (%s): assertion %s failed\n", __PRETTY_FUNCTION__, #expr); return val;}
58 #else
59         #define br_return_val_if_fail(expr,val) if (!(expr)) return val
60 #endif /* __GNUC__ */
63 #ifdef ENABLE_BINRELOC
65 #include <sys/types.h>
66 #include <sys/stat.h>
67 #include <sys/param.h>
68 #include <unistd.h>
70 /**
71  * br_locate:
72  * symbol: A symbol that belongs to the app/library you want to locate.
73  * Returns: A newly allocated string containing the full path of the
74  *          app/library that func belongs to, or NULL on error. This
75  *          string should be freed when not when no longer needed.
76  *
77  * Finds out to which application or library symbol belongs, then locate
78  * the full path of that application or library.
79  * Note that symbol cannot be a pointer to a function. That will not work.
80  *
81  * Example:
82  * --> main.c
83  * #include "prefix.h"
84  * #include "libfoo.h"
85  *
86  * int main (int argc, char *argv[]) {
87  *      printf ("Full path of this app: %s\n", br_locate (&argc));
88  *      libfoo_start ();
89  *      return 0;
90  * }
91  *
92  * --> libfoo.c starts here
93  * #include "prefix.h"
94  *
95  * void libfoo_start () {
96  *      --> "" is a symbol that belongs to libfoo (because it's called
97  *      --> from libfoo_start()); that's why this works.
98  *      printf ("libfoo is located in: %s\n", br_locate (""));
99  * }
100  */
101 char *
102 br_locate (void *symbol)
104         char line[5000];
105         FILE *f;
106         char *path;
108         br_return_val_if_fail (symbol != NULL, NULL);
110         f = fopen ("/proc/self/maps", "r");
111         if (!f)
112                 return NULL;
114         while (!feof (f))
115         {
116                 unsigned long start, end;
118                 if (!fgets (line, sizeof (line), f))
119                         continue;
120                 if (!strstr (line, " r-xp ") || !strchr (line, '/'))
121                         continue;
123                 sscanf (line, "%lx-%lx ", &start, &end);
124                 if (symbol >= (void *) start && symbol < (void *) end)
125                 {
126                         char *tmp;
127                         size_t len;
129                         /* Extract the filename; it is always an absolute path */
130                         path = strchr (line, '/');
132                         /* Get rid of the newline */
133                         tmp = strrchr (path, '\n');
134                         if (tmp) *tmp = 0;
136                         /* Get rid of "(deleted)" */
137                         len = strlen (path);
138                         if (len > 10 && strcmp (path + len - 10, " (deleted)") == 0)
139                         {
140                                 tmp = path + len - 10;
141                                 *tmp = 0;
142                         }
144                         fclose(f);
145                         return strdup (path);
146                 }
147         }
149         fclose (f);
150         return NULL;
154 /**
155  * br_locate_prefix:
156  * symbol: A symbol that belongs to the app/library you want to locate.
157  * Returns: A prefix. This string should be freed when no longer needed.
158  *
159  * Locates the full path of the app/library that symbol belongs to, and return
160  * the prefix of that path, or NULL on error.
161  * Note that symbol cannot be a pointer to a function. That will not work.
162  *
163  * Example:
164  * --> This application is located in /usr/bin/foo
165  * br_locate_prefix (&argc);   --> returns: "/usr"
166  */
167 char *
168 br_locate_prefix (void *symbol)
170         char *path, *prefix;
172         br_return_val_if_fail (symbol != NULL, NULL);
174         path = br_locate (symbol);
175         if (!path) return NULL;
177         prefix = br_extract_prefix (path);
178         free (path);
179         return prefix;
183 /**
184  * br_prepend_prefix:
185  * symbol: A symbol that belongs to the app/library you want to locate.
186  * path: The path that you want to prepend the prefix to.
187  * Returns: The new path, or NULL on error. This string should be freed when no
188  *          longer needed.
189  *
190  * Gets the prefix of the app/library that symbol belongs to. Prepend that prefix to path.
191  * Note that symbol cannot be a pointer to a function. That will not work.
192  *
193  * Example:
194  * --> The application is /usr/bin/foo
195  * br_prepend_prefix (&argc, "/share/foo/data.png");   --> Returns "/usr/share/foo/data.png"
196  */
197 char *
198 br_prepend_prefix (void *symbol, char *path)
200         char *tmp, *newpath;
202         br_return_val_if_fail (symbol != NULL, NULL);
203         br_return_val_if_fail (path != NULL, NULL);
205         tmp = br_locate_prefix (symbol);
206         if (!tmp) return NULL;
208         if (strcmp (tmp, "/") == 0)
209                 newpath = strdup (path);
210         else
211                 newpath = br_strcat (tmp, path);
213         /* Get rid of compiler warning ("br_prepend_prefix never used") */
214         if (0) br_prepend_prefix (NULL, NULL);
216         free (tmp);
217         return newpath;
220 #endif /* ENABLE_BINRELOC */
223 /* Thread stuff for thread safetiness */
224 #if BR_THREADS
226 GPrivate* br_thread_key = (GPrivate *)NULL;
228 /*
229    We do not need local store init() or fini(), because
230    g_private_new (g_free) will take care of all of that
231    for us.  Isn't GLib wonderful?
232 */
234 #else /* !BR_THREADS */
236 static char *br_last_value = (char*)NULL;
238 static void
239 br_free_last_value ()
241     if (br_last_value)
242         free (br_last_value);
245 #endif /* BR_THREADS */
248 /**
249  * br_thread_local_store:
250  * str: A dynamically allocated string.
251  * Returns: str. This return value must not be freed.
252  *
253  * Store str in a thread-local variable and return str. The next
254  * you run this function, that variable is freed too.
255  * This function is created so you don't have to worry about freeing
256  * strings.
257  *
258  * Example:
259  * char *foo;
260  * foo = thread_local_store (strdup ("hello")); --> foo == "hello"
261  * foo = thread_local_store (strdup ("world")); --> foo == "world"; "hello" is now freed.
262  */
263 const char *
264 br_thread_local_store (char *str)
266         #if BR_THREADS
267                 if (!g_thread_supported ())
268                     {
269                     g_thread_init ((GThreadFunctions *)NULL);
270                     br_thread_key = g_private_new (g_free);
271                     }
273                 char *specific = (char *) g_private_get (br_thread_key);
274                 if (specific)
275                     free (specific);
276                 g_private_set (br_thread_key, str);
278         #else /* !BR_THREADS */
279                 static int initialized = 0;
281                 if (!initialized)
282                 {
283                         atexit (br_free_last_value);
284                         initialized = 1;
285                 }
287                 if (br_last_value)
288                         free (br_last_value);
289                 br_last_value = str;
290         #endif /* BR_THREADS */
292         return (const char *) str;
296 /**
297  * br_strcat:
298  * str1: A string.
299  * str2: Another string.
300  * Returns: A newly-allocated string. This string should be freed when no longer needed.
301  *
302  * Concatenate str1 and str2 to a newly allocated string.
303  */
304 char *
305 br_strcat (const char *str1, const char *str2)
307         char *result;
308         size_t len1, len2;
310         if (!str1) str1 = "";
311         if (!str2) str2 = "";
313         len1 = strlen (str1);
314         len2 = strlen (str2);
316         result = (char *) malloc (len1 + len2 + 1);
317         memcpy (result, str1, len1);
318         memcpy (result + len1, str2, len2);
319         result[len1 + len2] = '\0';
321         return result;
325 /* Emulates glibc's strndup() */
326 static char *
327 br_strndup (char *str, size_t size)
329         char *result = (char*)NULL;
330         size_t len;
332         br_return_val_if_fail (str != (char*)NULL, (char*)NULL);
334         len = strlen (str);
335         if (!len) return strdup ("");
336         if (size > len) size = len;
338         result = (char *) calloc (sizeof (char), len + 1);
339         memcpy (result, str, size);
340         return result;
344 /**
345  * br_extract_dir:
346  * path: A path.
347  * Returns: A directory name. This string should be freed when no longer needed.
348  *
349  * Extracts the directory component of path. Similar to g_dirname() or the dirname
350  * commandline application.
351  *
352  * Example:
353  * br_extract_dir ("/usr/local/foobar");  --> Returns: "/usr/local"
354  */
355 char *
356 br_extract_dir (const char *path)
358         char *end, *result;
360         br_return_val_if_fail (path != (char*)NULL, (char*)NULL);
362         end = strrchr (path, '/');
363         if (!end) return strdup (".");
365         while (end > path && *end == '/')
366                 end--;
367         result = br_strndup ((char *) path, end - path + 1);
368         if (!*result)
369         {
370                 free (result);
371                 return strdup ("/");
372         } else
373                 return result;
377 /**
378  * br_extract_prefix:
379  * path: The full path of an executable or library.
380  * Returns: The prefix, or NULL on error. This string should be freed when no longer needed.
381  *
382  * Extracts the prefix from path. This function assumes that your executable
383  * or library is installed in an LSB-compatible directory structure.
384  *
385  * Example:
386  * br_extract_prefix ("/usr/bin/gnome-panel");       --> Returns "/usr"
387  * br_extract_prefix ("/usr/local/lib/libfoo.so");   --> Returns "/usr/local"
388  * br_extract_prefix ("/usr/local/libfoo.so");       --> Returns "/usr"
389  */
390 char *
391 br_extract_prefix (const char *path)
393         char *end, *tmp, *result;
395         br_return_val_if_fail (path != (char*)NULL, (char*)NULL);
397         if (!*path) return strdup ("/");
398         end = strrchr (path, '/');
399         if (!end) return strdup (path);
401         tmp = br_strndup ((char *) path, end - path);
402         if (!*tmp)
403         {
404                 free (tmp);
405                 return strdup ("/");
406         }
407         end = strrchr (tmp, '/');
408         if (!end) return tmp;
410         result = br_strndup (tmp, end - tmp);
411         free (tmp);
413         if (!*result)
414         {
415                 free (result);
416                 result = strdup ("/");
417         }
419         return result;
423 #ifdef __cplusplus
425 #endif /* __cplusplus */
427 #endif /* _PREFIX_C */