Mercurial > pidgin
comparison libpurple/prefix.c @ 15373:5fe8042783c1
Rename gtk/ and libgaim/ to pidgin/ and libpurple/
author | Sean Egan <seanegan@gmail.com> |
---|---|
date | Sat, 20 Jan 2007 02:32:10 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
15372:f79e0f4df793 | 15373:5fe8042783c1 |
---|---|
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 */ | |
13 | |
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 */ | |
25 | |
26 #ifndef _PREFIX_C_ | |
27 #define _PREFIX_C_ | |
28 | |
29 #ifdef HAVE_CONFIG_H | |
30 #include "config.h" | |
31 #endif | |
32 | |
33 #ifndef BR_PTHREADS | |
34 /* Change 1 to 0 if you don't want pthread support */ | |
35 #define BR_PTHREADS 1 | |
36 #endif /* BR_PTHREADS */ | |
37 | |
38 #include <stdlib.h> | |
39 #include <stdio.h> | |
40 #include <limits.h> | |
41 #include <string.h> | |
42 #include "prefix.h" | |
43 | |
44 #ifdef __cplusplus | |
45 extern "C" { | |
46 #endif /* __cplusplus */ | |
47 | |
48 | |
49 #undef NULL | |
50 #define NULL ((void *) 0) | |
51 | |
52 #ifdef __GNUC__ | |
53 #define br_return_val_if_fail(expr,val) if (!(expr)) {fprintf (stderr, "** BinReloc (%s): assertion %s failed\n", __PRETTY_FUNCTION__, #expr); return val;} | |
54 #else | |
55 #define br_return_val_if_fail(expr,val) if (!(expr)) return val | |
56 #endif /* __GNUC__ */ | |
57 | |
58 | |
59 static br_locate_fallback_func fallback_func = NULL; | |
60 static void *fallback_data = NULL; | |
61 | |
62 | |
63 #ifdef ENABLE_BINRELOC | |
64 #include <sys/types.h> | |
65 #include <sys/stat.h> | |
66 #include <sys/param.h> | |
67 #include <unistd.h> | |
68 | |
69 | |
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) | |
103 { | |
104 char line[5000]; | |
105 FILE *f; | |
106 char *path; | |
107 | |
108 br_return_val_if_fail (symbol != NULL, NULL); | |
109 | |
110 f = fopen ("/proc/self/maps", "r"); | |
111 if (!f) { | |
112 if (fallback_func) | |
113 return fallback_func(symbol, fallback_data); | |
114 else | |
115 return NULL; | |
116 } | |
117 | |
118 while (!feof (f)) | |
119 { | |
120 unsigned long start, end; | |
121 | |
122 if (!fgets (line, sizeof (line), f)) | |
123 continue; | |
124 if (!strstr (line, " r-xp ") || !strchr (line, '/')) | |
125 continue; | |
126 | |
127 sscanf (line, "%lx-%lx ", &start, &end); | |
128 if (symbol >= (void *) start && symbol < (void *) end) | |
129 { | |
130 char *tmp; | |
131 size_t len; | |
132 | |
133 /* Extract the filename; it is always an absolute path */ | |
134 path = strchr (line, '/'); | |
135 | |
136 /* Get rid of the newline */ | |
137 tmp = strrchr (path, '\n'); | |
138 if (tmp) *tmp = 0; | |
139 | |
140 /* Get rid of "(deleted)" */ | |
141 len = strlen (path); | |
142 if (len > 10 && strcmp (path + len - 10, " (deleted)") == 0) | |
143 { | |
144 tmp = path + len - 10; | |
145 *tmp = 0; | |
146 } | |
147 | |
148 fclose(f); | |
149 return strdup (path); | |
150 } | |
151 } | |
152 | |
153 fclose (f); | |
154 return NULL; | |
155 } | |
156 | |
157 | |
158 /** | |
159 * br_locate_prefix: | |
160 * symbol: A symbol that belongs to the app/library you want to locate. | |
161 * Returns: A prefix. This string should be freed when no longer needed. | |
162 * | |
163 * Locates the full path of the app/library that symbol belongs to, and return | |
164 * the prefix of that path, or NULL on error. | |
165 * Note that symbol cannot be a pointer to a function. That will not work. | |
166 * | |
167 * Example: | |
168 * --> This application is located in /usr/bin/foo | |
169 * br_locate_prefix (&argc); --> returns: "/usr" | |
170 */ | |
171 char * | |
172 br_locate_prefix (void *symbol) | |
173 { | |
174 char *path, *prefix; | |
175 | |
176 br_return_val_if_fail (symbol != NULL, NULL); | |
177 | |
178 path = br_locate (symbol); | |
179 if (!path) return NULL; | |
180 | |
181 prefix = br_extract_prefix (path); | |
182 free (path); | |
183 return prefix; | |
184 } | |
185 | |
186 | |
187 /** | |
188 * br_prepend_prefix: | |
189 * symbol: A symbol that belongs to the app/library you want to locate. | |
190 * path: The path that you want to prepend the prefix to. | |
191 * Returns: The new path, or NULL on error. This string should be freed when no | |
192 * longer needed. | |
193 * | |
194 * Gets the prefix of the app/library that symbol belongs to. Prepend that prefix to path. | |
195 * Note that symbol cannot be a pointer to a function. That will not work. | |
196 * | |
197 * Example: | |
198 * --> The application is /usr/bin/foo | |
199 * br_prepend_prefix (&argc, "/share/foo/data.png"); --> Returns "/usr/share/foo/data.png" | |
200 */ | |
201 char * | |
202 br_prepend_prefix (void *symbol, char *path) | |
203 { | |
204 char *tmp, *newpath; | |
205 | |
206 br_return_val_if_fail (symbol != NULL, NULL); | |
207 br_return_val_if_fail (path != NULL, NULL); | |
208 | |
209 tmp = br_locate_prefix (symbol); | |
210 if (!tmp) return NULL; | |
211 | |
212 if (strcmp (tmp, "/") == 0) | |
213 newpath = strdup (path); | |
214 else | |
215 newpath = br_strcat (tmp, path); | |
216 | |
217 /* Get rid of compiler warning ("br_prepend_prefix never used") */ | |
218 if (0) br_prepend_prefix (NULL, NULL); | |
219 | |
220 free (tmp); | |
221 return newpath; | |
222 } | |
223 | |
224 #endif /* ENABLE_BINRELOC */ | |
225 | |
226 | |
227 /* Pthread stuff for thread safetiness */ | |
228 #if BR_PTHREADS | |
229 | |
230 #include <pthread.h> | |
231 | |
232 static pthread_key_t br_thread_key; | |
233 static pthread_once_t br_thread_key_once = PTHREAD_ONCE_INIT; | |
234 | |
235 | |
236 static void | |
237 br_thread_local_store_fini () | |
238 { | |
239 char *specific; | |
240 | |
241 specific = (char *) pthread_getspecific (br_thread_key); | |
242 if (specific) | |
243 { | |
244 free (specific); | |
245 pthread_setspecific (br_thread_key, NULL); | |
246 } | |
247 pthread_key_delete (br_thread_key); | |
248 br_thread_key = 0; | |
249 } | |
250 | |
251 | |
252 static void | |
253 br_str_free (void *str) | |
254 { | |
255 if (str) | |
256 free (str); | |
257 } | |
258 | |
259 | |
260 static void | |
261 br_thread_local_store_init () | |
262 { | |
263 if (pthread_key_create (&br_thread_key, br_str_free) == 0) | |
264 atexit (br_thread_local_store_fini); | |
265 } | |
266 | |
267 #else /* BR_PTHREADS */ | |
268 | |
269 static char *br_last_value = (char *) NULL; | |
270 | |
271 static void | |
272 br_free_last_value () | |
273 { | |
274 if (br_last_value) | |
275 free (br_last_value); | |
276 } | |
277 | |
278 #endif /* BR_PTHREADS */ | |
279 | |
280 | |
281 /** | |
282 * br_thread_local_store: | |
283 * str: A dynamically allocated string. | |
284 * Returns: str. This return value must not be freed. | |
285 * | |
286 * Store str in a thread-local variable and return str. The next | |
287 * you run this function, that variable is freed too. | |
288 * This function is created so you don't have to worry about freeing | |
289 * strings. Just be careful about doing this sort of thing: | |
290 * | |
291 * some_function( BR_DATADIR("/one.png"), BR_DATADIR("/two.png") ) | |
292 * | |
293 * Examples: | |
294 * char *foo; | |
295 * foo = br_thread_local_store (strdup ("hello")); --> foo == "hello" | |
296 * foo = br_thread_local_store (strdup ("world")); --> foo == "world"; "hello" is now freed. | |
297 */ | |
298 const char * | |
299 br_thread_local_store (char *str) | |
300 { | |
301 #if BR_PTHREADS | |
302 char *specific; | |
303 | |
304 pthread_once (&br_thread_key_once, br_thread_local_store_init); | |
305 | |
306 specific = (char *) pthread_getspecific (br_thread_key); | |
307 br_str_free (specific); | |
308 pthread_setspecific (br_thread_key, str); | |
309 | |
310 #else /* BR_PTHREADS */ | |
311 static int initialized = 0; | |
312 | |
313 if (!initialized) | |
314 { | |
315 atexit (br_free_last_value); | |
316 initialized = 1; | |
317 } | |
318 | |
319 if (br_last_value) | |
320 free (br_last_value); | |
321 br_last_value = str; | |
322 #endif /* BR_PTHREADS */ | |
323 | |
324 return (const char *) str; | |
325 } | |
326 | |
327 | |
328 /** | |
329 * br_strcat: | |
330 * str1: A string. | |
331 * str2: Another string. | |
332 * Returns: A newly-allocated string. This string should be freed when no longer needed. | |
333 * | |
334 * Concatenate str1 and str2 to a newly allocated string. | |
335 */ | |
336 char * | |
337 br_strcat (const char *str1, const char *str2) | |
338 { | |
339 char *result; | |
340 size_t len1, len2; | |
341 | |
342 if (!str1) str1 = ""; | |
343 if (!str2) str2 = ""; | |
344 | |
345 len1 = strlen (str1); | |
346 len2 = strlen (str2); | |
347 | |
348 result = (char *) malloc (len1 + len2 + 1); | |
349 memcpy (result, str1, len1); | |
350 memcpy (result + len1, str2, len2); | |
351 result[len1 + len2] = '\0'; | |
352 | |
353 return result; | |
354 } | |
355 | |
356 | |
357 /* Emulates glibc's strndup() */ | |
358 static char * | |
359 br_strndup (char *str, size_t size) | |
360 { | |
361 char *result = (char *) NULL; | |
362 size_t len; | |
363 | |
364 br_return_val_if_fail (str != (char *) NULL, (char *) NULL); | |
365 | |
366 len = strlen (str); | |
367 if (!len) return strdup (""); | |
368 if (size > len) size = len; | |
369 | |
370 result = (char *) calloc (sizeof (char), len + 1); | |
371 memcpy (result, str, size); | |
372 return result; | |
373 } | |
374 | |
375 | |
376 /** | |
377 * br_extract_dir: | |
378 * path: A path. | |
379 * Returns: A directory name. This string should be freed when no longer needed. | |
380 * | |
381 * Extracts the directory component of path. Similar to g_dirname() or the dirname | |
382 * commandline application. | |
383 * | |
384 * Example: | |
385 * br_extract_dir ("/usr/local/foobar"); --> Returns: "/usr/local" | |
386 */ | |
387 char * | |
388 br_extract_dir (const char *path) | |
389 { | |
390 char *end, *result; | |
391 | |
392 br_return_val_if_fail (path != (char *) NULL, (char *) NULL); | |
393 | |
394 end = strrchr (path, '/'); | |
395 if (!end) return strdup ("."); | |
396 | |
397 while (end > path && *end == '/') | |
398 end--; | |
399 result = br_strndup ((char *) path, end - path + 1); | |
400 if (!*result) | |
401 { | |
402 free (result); | |
403 return strdup ("/"); | |
404 } else | |
405 return result; | |
406 } | |
407 | |
408 | |
409 /** | |
410 * br_extract_prefix: | |
411 * path: The full path of an executable or library. | |
412 * Returns: The prefix, or NULL on error. This string should be freed when no longer needed. | |
413 * | |
414 * Extracts the prefix from path. This function assumes that your executable | |
415 * or library is installed in an LSB-compatible directory structure. | |
416 * | |
417 * Example: | |
418 * br_extract_prefix ("/usr/bin/gnome-panel"); --> Returns "/usr" | |
419 * br_extract_prefix ("/usr/local/lib/libfoo.so"); --> Returns "/usr/local" | |
420 * br_extract_prefix ("/usr/local/libfoo.so"); --> Returns "/usr" | |
421 */ | |
422 char * | |
423 br_extract_prefix (const char *path) | |
424 { | |
425 char *end, *tmp, *result; | |
426 | |
427 br_return_val_if_fail (path != (char *) NULL, (char *) NULL); | |
428 | |
429 if (!*path) return strdup ("/"); | |
430 end = strrchr (path, '/'); | |
431 if (!end) return strdup (path); | |
432 | |
433 tmp = br_strndup ((char *) path, end - path); | |
434 if (!*tmp) | |
435 { | |
436 free (tmp); | |
437 return strdup ("/"); | |
438 } | |
439 end = strrchr (tmp, '/'); | |
440 if (!end) return tmp; | |
441 | |
442 result = br_strndup (tmp, end - tmp); | |
443 free (tmp); | |
444 | |
445 if (!*result) | |
446 { | |
447 free (result); | |
448 result = strdup ("/"); | |
449 } | |
450 | |
451 return result; | |
452 } | |
453 | |
454 | |
455 /** | |
456 * br_set_fallback_function: | |
457 * func: A function to call to find the binary. | |
458 * data: User data to pass to func. | |
459 * | |
460 * Sets a function to call to find the path to the binary, in | |
461 * case "/proc/self/maps" can't be opened. The function set should | |
462 * return a string that is safe to free with free(). | |
463 */ | |
464 void | |
465 br_set_locate_fallback_func (br_locate_fallback_func func, void *data) | |
466 { | |
467 fallback_func = func; | |
468 fallback_data = data; | |
469 } | |
470 | |
471 | |
472 #ifdef __cplusplus | |
473 } | |
474 #endif /* __cplusplus */ | |
475 | |
476 #endif /* _PREFIX_C */ |