Mercurial > audlegacy
comparison src/intl/relocatable.c @ 2313:3149d4b1a9a9 trunk
[svn] - objective-make autodepend fixes
- move all sourcecode into src/ and adjust Makefiles accordingly
author | nenolod |
---|---|
date | Fri, 12 Jan 2007 11:43:40 -0800 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
2312:e1a5a66fb9cc | 2313:3149d4b1a9a9 |
---|---|
1 /* Provide relocatable packages. | |
2 Copyright (C) 2003 Free Software Foundation, Inc. | |
3 Written by Bruno Haible <bruno@clisp.org>, 2003. | |
4 | |
5 This program is free software; you can redistribute it and/or modify it | |
6 under the terms of the GNU Library General Public License as published | |
7 by the Free Software Foundation; either version 2, or (at your option) | |
8 any later version. | |
9 | |
10 This program is distributed in the hope that it will be useful, | |
11 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 Library General Public License for more details. | |
14 | |
15 You should have received a copy of the GNU Library General Public | |
16 License along with this program; if not, write to the Free Software | |
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, | |
18 USA. */ | |
19 | |
20 | |
21 /* Tell glibc's <stdio.h> to provide a prototype for getline(). | |
22 This must come before <config.h> because <config.h> may include | |
23 <features.h>, and once <features.h> has been included, it's too late. */ | |
24 #ifndef _GNU_SOURCE | |
25 # define _GNU_SOURCE 1 | |
26 #endif | |
27 | |
28 #ifdef HAVE_CONFIG_H | |
29 # include "config.h" | |
30 #endif | |
31 | |
32 /* Specification. */ | |
33 #include "relocatable.h" | |
34 | |
35 #if ENABLE_RELOCATABLE | |
36 | |
37 #include <stddef.h> | |
38 #include <stdio.h> | |
39 #include <stdlib.h> | |
40 #include <string.h> | |
41 | |
42 #ifdef NO_XMALLOC | |
43 # define xmalloc malloc | |
44 #else | |
45 # include "xmalloc.h" | |
46 #endif | |
47 | |
48 #if DEPENDS_ON_LIBCHARSET | |
49 # include <libcharset.h> | |
50 #endif | |
51 #if DEPENDS_ON_LIBICONV && HAVE_ICONV | |
52 # include <iconv.h> | |
53 #endif | |
54 #if DEPENDS_ON_LIBINTL && ENABLE_NLS | |
55 # include <libintl.h> | |
56 #endif | |
57 | |
58 /* Faked cheap 'bool'. */ | |
59 #undef bool | |
60 #undef false | |
61 #undef true | |
62 #define bool int | |
63 #define false 0 | |
64 #define true 1 | |
65 | |
66 /* Pathname support. | |
67 ISSLASH(C) tests whether C is a directory separator character. | |
68 IS_PATH_WITH_DIR(P) tests whether P contains a directory specification. | |
69 */ | |
70 #if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__ | |
71 /* Win32, OS/2, DOS */ | |
72 # define ISSLASH(C) ((C) == '/' || (C) == '\\') | |
73 # define HAS_DEVICE(P) \ | |
74 ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \ | |
75 && (P)[1] == ':') | |
76 # define IS_PATH_WITH_DIR(P) \ | |
77 (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P)) | |
78 # define FILESYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0) | |
79 #else | |
80 /* Unix */ | |
81 # define ISSLASH(C) ((C) == '/') | |
82 # define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL) | |
83 # define FILESYSTEM_PREFIX_LEN(P) 0 | |
84 #endif | |
85 | |
86 /* Original installation prefix. */ | |
87 static char *orig_prefix; | |
88 static size_t orig_prefix_len; | |
89 /* Current installation prefix. */ | |
90 static char *curr_prefix; | |
91 static size_t curr_prefix_len; | |
92 /* These prefixes do not end in a slash. Anything that will be concatenated | |
93 to them must start with a slash. */ | |
94 | |
95 /* Sets the original and the current installation prefix of this module. | |
96 Relocation simply replaces a pathname starting with the original prefix | |
97 by the corresponding pathname with the current prefix instead. Both | |
98 prefixes should be directory names without trailing slash (i.e. use "" | |
99 instead of "/"). */ | |
100 static void | |
101 set_this_relocation_prefix (const char *orig_prefix_arg, | |
102 const char *curr_prefix_arg) | |
103 { | |
104 if (orig_prefix_arg != NULL && curr_prefix_arg != NULL | |
105 /* Optimization: if orig_prefix and curr_prefix are equal, the | |
106 relocation is a nop. */ | |
107 && strcmp (orig_prefix_arg, curr_prefix_arg) != 0) | |
108 { | |
109 /* Duplicate the argument strings. */ | |
110 char *memory; | |
111 | |
112 orig_prefix_len = strlen (orig_prefix_arg); | |
113 curr_prefix_len = strlen (curr_prefix_arg); | |
114 memory = (char *) xmalloc (orig_prefix_len + 1 + curr_prefix_len + 1); | |
115 #ifdef NO_XMALLOC | |
116 if (memory != NULL) | |
117 #endif | |
118 { | |
119 memcpy (memory, orig_prefix_arg, orig_prefix_len + 1); | |
120 orig_prefix = memory; | |
121 memory += orig_prefix_len + 1; | |
122 memcpy (memory, curr_prefix_arg, curr_prefix_len + 1); | |
123 curr_prefix = memory; | |
124 return; | |
125 } | |
126 } | |
127 orig_prefix = NULL; | |
128 curr_prefix = NULL; | |
129 /* Don't worry about wasted memory here - this function is usually only | |
130 called once. */ | |
131 } | |
132 | |
133 /* Sets the original and the current installation prefix of the package. | |
134 Relocation simply replaces a pathname starting with the original prefix | |
135 by the corresponding pathname with the current prefix instead. Both | |
136 prefixes should be directory names without trailing slash (i.e. use "" | |
137 instead of "/"). */ | |
138 void | |
139 set_relocation_prefix (const char *orig_prefix_arg, const char *curr_prefix_arg) | |
140 { | |
141 set_this_relocation_prefix (orig_prefix_arg, curr_prefix_arg); | |
142 | |
143 /* Now notify all dependent libraries. */ | |
144 #if DEPENDS_ON_LIBCHARSET | |
145 libcharset_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg); | |
146 #endif | |
147 #if DEPENDS_ON_LIBICONV && HAVE_ICONV && _LIBICONV_VERSION >= 0x0109 | |
148 libiconv_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg); | |
149 #endif | |
150 #if DEPENDS_ON_LIBINTL && ENABLE_NLS && defined libintl_set_relocation_prefix | |
151 libintl_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg); | |
152 #endif | |
153 } | |
154 | |
155 /* Convenience function: | |
156 Computes the current installation prefix, based on the original | |
157 installation prefix, the original installation directory of a particular | |
158 file, and the current pathname of this file. Returns NULL upon failure. */ | |
159 #ifdef IN_LIBRARY | |
160 #define compute_curr_prefix local_compute_curr_prefix | |
161 static | |
162 #endif | |
163 const char * | |
164 compute_curr_prefix (const char *orig_installprefix, | |
165 const char *orig_installdir, | |
166 const char *curr_pathname) | |
167 { | |
168 const char *curr_installdir; | |
169 const char *rel_installdir; | |
170 | |
171 if (curr_pathname == NULL) | |
172 return NULL; | |
173 | |
174 /* Determine the relative installation directory, relative to the prefix. | |
175 This is simply the difference between orig_installprefix and | |
176 orig_installdir. */ | |
177 if (strncmp (orig_installprefix, orig_installdir, strlen (orig_installprefix)) | |
178 != 0) | |
179 /* Shouldn't happen - nothing should be installed outside $(prefix). */ | |
180 return NULL; | |
181 rel_installdir = orig_installdir + strlen (orig_installprefix); | |
182 | |
183 /* Determine the current installation directory. */ | |
184 { | |
185 const char *p_base = curr_pathname + FILESYSTEM_PREFIX_LEN (curr_pathname); | |
186 const char *p = curr_pathname + strlen (curr_pathname); | |
187 char *q; | |
188 | |
189 while (p > p_base) | |
190 { | |
191 p--; | |
192 if (ISSLASH (*p)) | |
193 break; | |
194 } | |
195 | |
196 q = (char *) xmalloc (p - curr_pathname + 1); | |
197 #ifdef NO_XMALLOC | |
198 if (q == NULL) | |
199 return NULL; | |
200 #endif | |
201 memcpy (q, curr_pathname, p - curr_pathname); | |
202 q[p - curr_pathname] = '\0'; | |
203 curr_installdir = q; | |
204 } | |
205 | |
206 /* Compute the current installation prefix by removing the trailing | |
207 rel_installdir from it. */ | |
208 { | |
209 const char *rp = rel_installdir + strlen (rel_installdir); | |
210 const char *cp = curr_installdir + strlen (curr_installdir); | |
211 const char *cp_base = | |
212 curr_installdir + FILESYSTEM_PREFIX_LEN (curr_installdir); | |
213 | |
214 while (rp > rel_installdir && cp > cp_base) | |
215 { | |
216 bool same = false; | |
217 const char *rpi = rp; | |
218 const char *cpi = cp; | |
219 | |
220 while (rpi > rel_installdir && cpi > cp_base) | |
221 { | |
222 rpi--; | |
223 cpi--; | |
224 if (ISSLASH (*rpi) || ISSLASH (*cpi)) | |
225 { | |
226 if (ISSLASH (*rpi) && ISSLASH (*cpi)) | |
227 same = true; | |
228 break; | |
229 } | |
230 #if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__ | |
231 /* Win32, OS/2, DOS - case insignificant filesystem */ | |
232 if ((*rpi >= 'a' && *rpi <= 'z' ? *rpi - 'a' + 'A' : *rpi) | |
233 != (*cpi >= 'a' && *cpi <= 'z' ? *cpi - 'a' + 'A' : *cpi)) | |
234 break; | |
235 #else | |
236 if (*rpi != *cpi) | |
237 break; | |
238 #endif | |
239 } | |
240 if (!same) | |
241 break; | |
242 /* The last pathname component was the same. opi and cpi now point | |
243 to the slash before it. */ | |
244 rp = rpi; | |
245 cp = cpi; | |
246 } | |
247 | |
248 if (rp > rel_installdir) | |
249 /* Unexpected: The curr_installdir does not end with rel_installdir. */ | |
250 return NULL; | |
251 | |
252 { | |
253 size_t curr_prefix_len = cp - curr_installdir; | |
254 char *curr_prefix; | |
255 | |
256 curr_prefix = (char *) xmalloc (curr_prefix_len + 1); | |
257 #ifdef NO_XMALLOC | |
258 if (curr_prefix == NULL) | |
259 return NULL; | |
260 #endif | |
261 memcpy (curr_prefix, curr_installdir, curr_prefix_len); | |
262 curr_prefix[curr_prefix_len] = '\0'; | |
263 | |
264 return curr_prefix; | |
265 } | |
266 } | |
267 } | |
268 | |
269 #if defined PIC && defined INSTALLDIR | |
270 | |
271 /* Full pathname of shared library, or NULL. */ | |
272 static char *shared_library_fullname; | |
273 | |
274 #if defined _WIN32 || defined __WIN32__ | |
275 | |
276 /* Determine the full pathname of the shared library when it is loaded. */ | |
277 | |
278 BOOL WINAPI | |
279 DllMain (HINSTANCE module_handle, DWORD event, LPVOID reserved) | |
280 { | |
281 (void) reserved; | |
282 | |
283 if (event == DLL_PROCESS_ATTACH) | |
284 { | |
285 /* The DLL is being loaded into an application's address range. */ | |
286 static char location[MAX_PATH]; | |
287 | |
288 if (!GetModuleFileName (module_handle, location, sizeof (location))) | |
289 /* Shouldn't happen. */ | |
290 return FALSE; | |
291 | |
292 if (!IS_PATH_WITH_DIR (location)) | |
293 /* Shouldn't happen. */ | |
294 return FALSE; | |
295 | |
296 shared_library_fullname = strdup (location); | |
297 } | |
298 | |
299 return TRUE; | |
300 } | |
301 | |
302 #else /* Unix */ | |
303 | |
304 static void | |
305 find_shared_library_fullname () | |
306 { | |
307 #ifdef __linux__ | |
308 FILE *fp; | |
309 | |
310 /* Open the current process' maps file. It describes one VMA per line. */ | |
311 fp = fopen ("/proc/self/maps", "r"); | |
312 if (fp) | |
313 { | |
314 unsigned long address = (unsigned long) &find_shared_library_fullname; | |
315 for (;;) | |
316 { | |
317 unsigned long start, end; | |
318 int c; | |
319 | |
320 if (fscanf (fp, "%lx-%lx", &start, &end) != 2) | |
321 break; | |
322 if (address >= start && address <= end - 1) | |
323 { | |
324 /* Found it. Now see if this line contains a filename. */ | |
325 while (c = getc (fp), c != EOF && c != '\n' && c != '/') | |
326 continue; | |
327 if (c == '/') | |
328 { | |
329 size_t size; | |
330 int len; | |
331 | |
332 ungetc (c, fp); | |
333 shared_library_fullname = NULL; size = 0; | |
334 len = getline (&shared_library_fullname, &size, fp); | |
335 if (len >= 0) | |
336 { | |
337 /* Success: filled shared_library_fullname. */ | |
338 if (len > 0 && shared_library_fullname[len - 1] == '\n') | |
339 shared_library_fullname[len - 1] = '\0'; | |
340 } | |
341 } | |
342 break; | |
343 } | |
344 while (c = getc (fp), c != EOF && c != '\n') | |
345 continue; | |
346 } | |
347 fclose (fp); | |
348 } | |
349 #endif | |
350 } | |
351 | |
352 #endif /* WIN32 / Unix */ | |
353 | |
354 /* Return the full pathname of the current shared library. | |
355 Return NULL if unknown. | |
356 Guaranteed to work only on Linux and Woe32. */ | |
357 static char * | |
358 get_shared_library_fullname () | |
359 { | |
360 #if !(defined _WIN32 || defined __WIN32__) | |
361 static bool tried_find_shared_library_fullname; | |
362 if (!tried_find_shared_library_fullname) | |
363 { | |
364 find_shared_library_fullname (); | |
365 tried_find_shared_library_fullname = true; | |
366 } | |
367 #endif | |
368 return shared_library_fullname; | |
369 } | |
370 | |
371 #endif /* PIC */ | |
372 | |
373 /* Returns the pathname, relocated according to the current installation | |
374 directory. */ | |
375 const char * | |
376 relocate (const char *pathname) | |
377 { | |
378 #if defined PIC && defined INSTALLDIR | |
379 static int initialized; | |
380 | |
381 /* Initialization code for a shared library. */ | |
382 if (!initialized) | |
383 { | |
384 /* At this point, orig_prefix and curr_prefix likely have already been | |
385 set through the main program's set_program_name_and_installdir | |
386 function. This is sufficient in the case that the library has | |
387 initially been installed in the same orig_prefix. But we can do | |
388 better, to also cover the cases that 1. it has been installed | |
389 in a different prefix before being moved to orig_prefix and (later) | |
390 to curr_prefix, 2. unlike the program, it has not moved away from | |
391 orig_prefix. */ | |
392 const char *orig_installprefix = INSTALLPREFIX; | |
393 const char *orig_installdir = INSTALLDIR; | |
394 const char *curr_prefix_better; | |
395 | |
396 curr_prefix_better = | |
397 compute_curr_prefix (orig_installprefix, orig_installdir, | |
398 get_shared_library_fullname ()); | |
399 if (curr_prefix_better == NULL) | |
400 curr_prefix_better = curr_prefix; | |
401 | |
402 set_relocation_prefix (orig_installprefix, curr_prefix_better); | |
403 | |
404 initialized = 1; | |
405 } | |
406 #endif | |
407 | |
408 /* Note: It is not necessary to perform case insensitive comparison here, | |
409 even for DOS-like filesystems, because the pathname argument was | |
410 typically created from the same Makefile variable as orig_prefix came | |
411 from. */ | |
412 if (orig_prefix != NULL && curr_prefix != NULL | |
413 && strncmp (pathname, orig_prefix, orig_prefix_len) == 0) | |
414 { | |
415 if (pathname[orig_prefix_len] == '\0') | |
416 /* pathname equals orig_prefix. */ | |
417 return curr_prefix; | |
418 if (ISSLASH (pathname[orig_prefix_len])) | |
419 { | |
420 /* pathname starts with orig_prefix. */ | |
421 const char *pathname_tail = &pathname[orig_prefix_len]; | |
422 char *result = | |
423 (char *) xmalloc (curr_prefix_len + strlen (pathname_tail) + 1); | |
424 | |
425 #ifdef NO_XMALLOC | |
426 if (result != NULL) | |
427 #endif | |
428 { | |
429 memcpy (result, curr_prefix, curr_prefix_len); | |
430 strcpy (result + curr_prefix_len, pathname_tail); | |
431 return result; | |
432 } | |
433 } | |
434 } | |
435 /* Nothing to relocate. */ | |
436 return pathname; | |
437 } | |
438 | |
439 #endif |