Mercurial > pidgin
comparison src/prefix.c @ 10245:c143a3fac58d
[gaim-migrate @ 11385]
Binary relocation, step one.
I had a fairly long commit message, and cvs ate it and said
Read from remote host cvs.sourceforge.net: Connection reset by peer
I'm displeased.
This is just method one, method two to follow tomorrow after I add a
way to register a fallback and try to push it upstream. That way
I don't have to put method 2 inside prefix.c.
As for as core/ui split goes, they can either each have their own copy
after the divorce is final, or the UI can use the core's. It'll work
either way, since #1 finds location of the caller, and #2 doesn't work
on libraries anyway. That's one advantage I forgot to mention, btw,
that #1 will let a library find its own location.
So, I'm sure something isn't quite right and someone will want to fix
it. So they can fix it while i implement phase two. Which won't take
long at all, but the autopackage guy is in bed, and I should be too.
committer: Tailor Script <tailor@pidgin.im>
author | Tim Ringenbach <marv@pidgin.im> |
---|---|
date | Tue, 23 Nov 2004 05:53:59 +0000 |
parents | |
children | 645eb9804040 |
comparison
equal
deleted
inserted
replaced
10244:13cb42ebb537 | 10245:c143a3fac58d |
---|---|
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 #ifdef ENABLE_BINRELOC | |
60 #include <sys/types.h> | |
61 #include <sys/stat.h> | |
62 #include <sys/param.h> | |
63 #include <unistd.h> | |
64 | |
65 | |
66 /** | |
67 * br_locate: | |
68 * symbol: A symbol that belongs to the app/library you want to locate. | |
69 * Returns: A newly allocated string containing the full path of the | |
70 * app/library that func belongs to, or NULL on error. This | |
71 * string should be freed when not when no longer needed. | |
72 * | |
73 * Finds out to which application or library symbol belongs, then locate | |
74 * the full path of that application or library. | |
75 * Note that symbol cannot be a pointer to a function. That will not work. | |
76 * | |
77 * Example: | |
78 * --> main.c | |
79 * #include "prefix.h" | |
80 * #include "libfoo.h" | |
81 * | |
82 * int main (int argc, char *argv[]) { | |
83 * printf ("Full path of this app: %s\n", br_locate (&argc)); | |
84 * libfoo_start (); | |
85 * return 0; | |
86 * } | |
87 * | |
88 * --> libfoo.c starts here | |
89 * #include "prefix.h" | |
90 * | |
91 * void libfoo_start () { | |
92 * --> "" is a symbol that belongs to libfoo (because it's called | |
93 * --> from libfoo_start()); that's why this works. | |
94 * printf ("libfoo is located in: %s\n", br_locate ("")); | |
95 * } | |
96 */ | |
97 char * | |
98 br_locate (void *symbol) | |
99 { | |
100 char line[5000]; | |
101 FILE *f; | |
102 char *path; | |
103 | |
104 br_return_val_if_fail (symbol != NULL, NULL); | |
105 | |
106 f = fopen ("/proc/self/maps", "r"); | |
107 if (!f) | |
108 return NULL; | |
109 | |
110 while (!feof (f)) | |
111 { | |
112 unsigned long start, end; | |
113 | |
114 if (!fgets (line, sizeof (line), f)) | |
115 continue; | |
116 if (!strstr (line, " r-xp ") || !strchr (line, '/')) | |
117 continue; | |
118 | |
119 sscanf (line, "%lx-%lx ", &start, &end); | |
120 if (symbol >= (void *) start && symbol < (void *) end) | |
121 { | |
122 char *tmp; | |
123 size_t len; | |
124 | |
125 /* Extract the filename; it is always an absolute path */ | |
126 path = strchr (line, '/'); | |
127 | |
128 /* Get rid of the newline */ | |
129 tmp = strrchr (path, '\n'); | |
130 if (tmp) *tmp = 0; | |
131 | |
132 /* Get rid of "(deleted)" */ | |
133 len = strlen (path); | |
134 if (len > 10 && strcmp (path + len - 10, " (deleted)") == 0) | |
135 { | |
136 tmp = path + len - 10; | |
137 *tmp = 0; | |
138 } | |
139 | |
140 fclose(f); | |
141 return strdup (path); | |
142 } | |
143 } | |
144 | |
145 fclose (f); | |
146 return NULL; | |
147 } | |
148 | |
149 | |
150 /** | |
151 * br_locate_prefix: | |
152 * symbol: A symbol that belongs to the app/library you want to locate. | |
153 * Returns: A prefix. This string should be freed when no longer needed. | |
154 * | |
155 * Locates the full path of the app/library that symbol belongs to, and return | |
156 * the prefix of that path, or NULL on error. | |
157 * Note that symbol cannot be a pointer to a function. That will not work. | |
158 * | |
159 * Example: | |
160 * --> This application is located in /usr/bin/foo | |
161 * br_locate_prefix (&argc); --> returns: "/usr" | |
162 */ | |
163 char * | |
164 br_locate_prefix (void *symbol) | |
165 { | |
166 char *path, *prefix; | |
167 | |
168 br_return_val_if_fail (symbol != NULL, NULL); | |
169 | |
170 path = br_locate (symbol); | |
171 if (!path) return NULL; | |
172 | |
173 prefix = br_extract_prefix (path); | |
174 free (path); | |
175 return prefix; | |
176 } | |
177 | |
178 | |
179 /** | |
180 * br_prepend_prefix: | |
181 * symbol: A symbol that belongs to the app/library you want to locate. | |
182 * path: The path that you want to prepend the prefix to. | |
183 * Returns: The new path, or NULL on error. This string should be freed when no | |
184 * longer needed. | |
185 * | |
186 * Gets the prefix of the app/library that symbol belongs to. Prepend that prefix to path. | |
187 * Note that symbol cannot be a pointer to a function. That will not work. | |
188 * | |
189 * Example: | |
190 * --> The application is /usr/bin/foo | |
191 * br_prepend_prefix (&argc, "/share/foo/data.png"); --> Returns "/usr/share/foo/data.png" | |
192 */ | |
193 char * | |
194 br_prepend_prefix (void *symbol, char *path) | |
195 { | |
196 char *tmp, *newpath; | |
197 | |
198 br_return_val_if_fail (symbol != NULL, NULL); | |
199 br_return_val_if_fail (path != NULL, NULL); | |
200 | |
201 tmp = br_locate_prefix (symbol); | |
202 if (!tmp) return NULL; | |
203 | |
204 if (strcmp (tmp, "/") == 0) | |
205 newpath = strdup (path); | |
206 else | |
207 newpath = br_strcat (tmp, path); | |
208 | |
209 /* Get rid of compiler warning ("br_prepend_prefix never used") */ | |
210 if (0) br_prepend_prefix (NULL, NULL); | |
211 | |
212 free (tmp); | |
213 return newpath; | |
214 } | |
215 | |
216 #endif /* ENABLE_BINRELOC */ | |
217 | |
218 | |
219 /* Pthread stuff for thread safetiness */ | |
220 #if BR_PTHREADS | |
221 | |
222 #include <pthread.h> | |
223 | |
224 static pthread_key_t br_thread_key; | |
225 static pthread_once_t br_thread_key_once = PTHREAD_ONCE_INIT; | |
226 | |
227 | |
228 static void | |
229 br_thread_local_store_fini () | |
230 { | |
231 char *specific; | |
232 | |
233 specific = (char *) pthread_getspecific (br_thread_key); | |
234 if (specific) | |
235 { | |
236 free (specific); | |
237 pthread_setspecific (br_thread_key, NULL); | |
238 } | |
239 pthread_key_delete (br_thread_key); | |
240 br_thread_key = 0; | |
241 } | |
242 | |
243 | |
244 static void | |
245 br_str_free (void *str) | |
246 { | |
247 if (str) | |
248 free (str); | |
249 } | |
250 | |
251 | |
252 static void | |
253 br_thread_local_store_init () | |
254 { | |
255 if (pthread_key_create (&br_thread_key, br_str_free) == 0) | |
256 atexit (br_thread_local_store_fini); | |
257 } | |
258 | |
259 #else /* BR_PTHREADS */ | |
260 | |
261 static char *br_last_value = (char *) NULL; | |
262 | |
263 static void | |
264 br_free_last_value () | |
265 { | |
266 if (br_last_value) | |
267 free (br_last_value); | |
268 } | |
269 | |
270 #endif /* BR_PTHREADS */ | |
271 | |
272 | |
273 /** | |
274 * br_thread_local_store: | |
275 * str: A dynamically allocated string. | |
276 * Returns: str. This return value must not be freed. | |
277 * | |
278 * Store str in a thread-local variable and return str. The next | |
279 * you run this function, that variable is freed too. | |
280 * This function is created so you don't have to worry about freeing | |
281 * strings. | |
282 * | |
283 * Example: | |
284 * char *foo; | |
285 * foo = thread_local_store (strdup ("hello")); --> foo == "hello" | |
286 * foo = thread_local_store (strdup ("world")); --> foo == "world"; "hello" is now freed. | |
287 */ | |
288 const char * | |
289 br_thread_local_store (char *str) | |
290 { | |
291 #if BR_PTHREADS | |
292 char *specific; | |
293 | |
294 pthread_once (&br_thread_key_once, br_thread_local_store_init); | |
295 | |
296 specific = (char *) pthread_getspecific (br_thread_key); | |
297 br_str_free (specific); | |
298 pthread_setspecific (br_thread_key, str); | |
299 | |
300 #else /* BR_PTHREADS */ | |
301 static int initialized = 0; | |
302 | |
303 if (!initialized) | |
304 { | |
305 atexit (br_free_last_value); | |
306 initialized = 1; | |
307 } | |
308 | |
309 if (br_last_value) | |
310 free (br_last_value); | |
311 br_last_value = str; | |
312 #endif /* BR_PTHREADS */ | |
313 | |
314 return (const char *) str; | |
315 } | |
316 | |
317 | |
318 /** | |
319 * br_strcat: | |
320 * str1: A string. | |
321 * str2: Another string. | |
322 * Returns: A newly-allocated string. This string should be freed when no longer needed. | |
323 * | |
324 * Concatenate str1 and str2 to a newly allocated string. | |
325 */ | |
326 char * | |
327 br_strcat (const char *str1, const char *str2) | |
328 { | |
329 char *result; | |
330 size_t len1, len2; | |
331 | |
332 if (!str1) str1 = ""; | |
333 if (!str2) str2 = ""; | |
334 | |
335 len1 = strlen (str1); | |
336 len2 = strlen (str2); | |
337 | |
338 result = (char *) malloc (len1 + len2 + 1); | |
339 memcpy (result, str1, len1); | |
340 memcpy (result + len1, str2, len2); | |
341 result[len1 + len2] = '\0'; | |
342 | |
343 return result; | |
344 } | |
345 | |
346 | |
347 /* Emulates glibc's strndup() */ | |
348 static char * | |
349 br_strndup (char *str, size_t size) | |
350 { | |
351 char *result = (char *) NULL; | |
352 size_t len; | |
353 | |
354 br_return_val_if_fail (str != (char *) NULL, (char *) NULL); | |
355 | |
356 len = strlen (str); | |
357 if (!len) return strdup (""); | |
358 if (size > len) size = len; | |
359 | |
360 result = (char *) calloc (sizeof (char), len + 1); | |
361 memcpy (result, str, size); | |
362 return result; | |
363 } | |
364 | |
365 | |
366 /** | |
367 * br_extract_dir: | |
368 * path: A path. | |
369 * Returns: A directory name. This string should be freed when no longer needed. | |
370 * | |
371 * Extracts the directory component of path. Similar to g_dirname() or the dirname | |
372 * commandline application. | |
373 * | |
374 * Example: | |
375 * br_extract_dir ("/usr/local/foobar"); --> Returns: "/usr/local" | |
376 */ | |
377 char * | |
378 br_extract_dir (const char *path) | |
379 { | |
380 char *end, *result; | |
381 | |
382 br_return_val_if_fail (path != (char *) NULL, (char *) NULL); | |
383 | |
384 end = strrchr (path, '/'); | |
385 if (!end) return strdup ("."); | |
386 | |
387 while (end > path && *end == '/') | |
388 end--; | |
389 result = br_strndup ((char *) path, end - path + 1); | |
390 if (!*result) | |
391 { | |
392 free (result); | |
393 return strdup ("/"); | |
394 } else | |
395 return result; | |
396 } | |
397 | |
398 | |
399 /** | |
400 * br_extract_prefix: | |
401 * path: The full path of an executable or library. | |
402 * Returns: The prefix, or NULL on error. This string should be freed when no longer needed. | |
403 * | |
404 * Extracts the prefix from path. This function assumes that your executable | |
405 * or library is installed in an LSB-compatible directory structure. | |
406 * | |
407 * Example: | |
408 * br_extract_prefix ("/usr/bin/gnome-panel"); --> Returns "/usr" | |
409 * br_extract_prefix ("/usr/local/lib/libfoo.so"); --> Returns "/usr/local" | |
410 * br_extract_prefix ("/usr/local/libfoo.so"); --> Returns "/usr" | |
411 */ | |
412 char * | |
413 br_extract_prefix (const char *path) | |
414 { | |
415 char *end, *tmp, *result; | |
416 | |
417 br_return_val_if_fail (path != (char *) NULL, (char *) NULL); | |
418 | |
419 if (!*path) return strdup ("/"); | |
420 end = strrchr (path, '/'); | |
421 if (!end) return strdup (path); | |
422 | |
423 tmp = br_strndup ((char *) path, end - path); | |
424 if (!*tmp) | |
425 { | |
426 free (tmp); | |
427 return strdup ("/"); | |
428 } | |
429 end = strrchr (tmp, '/'); | |
430 if (!end) return tmp; | |
431 | |
432 result = br_strndup (tmp, end - tmp); | |
433 free (tmp); | |
434 | |
435 if (!*result) | |
436 { | |
437 free (result); | |
438 result = strdup ("/"); | |
439 } | |
440 | |
441 return result; | |
442 } | |
443 | |
444 | |
445 #ifdef __cplusplus | |
446 } | |
447 #endif /* __cplusplus */ | |
448 | |
449 #endif /* _PREFIX_C */ |