/[zanavi_public1]/navit/intl/relocatable.c
ZANavi

Contents of /navit/intl/relocatable.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2 - (hide annotations) (download)
Fri Oct 28 21:19:04 2011 UTC (12 years, 5 months ago) by zoff99
File MIME type: text/plain
File size: 13040 byte(s)
import files
1 zoff99 2 /* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
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 "xalloc.h"
46     #endif
47    
48     #if defined _WIN32 || defined __WIN32__
49     # define WIN32_LEAN_AND_MEAN
50     # include <windows.h>
51     #endif
52    
53     #if DEPENDS_ON_LIBCHARSET
54     # include <libcharset.h>
55     #endif
56     #if DEPENDS_ON_LIBICONV && HAVE_ICONV
57     # include <iconv.h>
58     #endif
59     #if DEPENDS_ON_LIBINTL && ENABLE_NLS
60     # include <libintl.h>
61     #endif
62    
63     /* Faked cheap 'bool'. */
64     #undef bool
65     #undef false
66     #undef true
67     #define bool int
68     #define false 0
69     #define true 1
70    
71     /* Pathname support.
72     ISSLASH(C) tests whether C is a directory separator character.
73     IS_PATH_WITH_DIR(P) tests whether P contains a directory specification.
74     */
75     #if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
76     /* Win32, OS/2, DOS */
77     # define ISSLASH(C) ((C) == '/' || (C) == '\\')
78     # define HAS_DEVICE(P) \
79     ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
80     && (P)[1] == ':')
81     # define IS_PATH_WITH_DIR(P) \
82     (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
83     # define FILESYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0)
84     #else
85     /* Unix */
86     # define ISSLASH(C) ((C) == '/')
87     # define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
88     # define FILESYSTEM_PREFIX_LEN(P) 0
89     #endif
90    
91     /* Original installation prefix. */
92     static char *orig_prefix;
93     static size_t orig_prefix_len;
94     /* Current installation prefix. */
95     static char *curr_prefix;
96     static size_t curr_prefix_len;
97     /* These prefixes do not end in a slash. Anything that will be concatenated
98     to them must start with a slash. */
99    
100     /* Sets the original and the current installation prefix of this module.
101     Relocation simply replaces a pathname starting with the original prefix
102     by the corresponding pathname with the current prefix instead. Both
103     prefixes should be directory names without trailing slash (i.e. use ""
104     instead of "/"). */
105     static void
106     set_this_relocation_prefix (const char *orig_prefix_arg,
107     const char *curr_prefix_arg)
108     {
109     if (orig_prefix_arg != NULL && curr_prefix_arg != NULL
110     /* Optimization: if orig_prefix and curr_prefix are equal, the
111     relocation is a nop. */
112     && strcmp (orig_prefix_arg, curr_prefix_arg) != 0)
113     {
114     /* Duplicate the argument strings. */
115     char *memory;
116    
117     orig_prefix_len = strlen (orig_prefix_arg);
118     curr_prefix_len = strlen (curr_prefix_arg);
119     memory = (char *) xmalloc (orig_prefix_len + 1 + curr_prefix_len + 1);
120     #ifdef NO_XMALLOC
121     if (memory != NULL)
122     #endif
123     {
124     memcpy (memory, orig_prefix_arg, orig_prefix_len + 1);
125     orig_prefix = memory;
126     memory += orig_prefix_len + 1;
127     memcpy (memory, curr_prefix_arg, curr_prefix_len + 1);
128     curr_prefix = memory;
129     return;
130     }
131     }
132     orig_prefix = NULL;
133     curr_prefix = NULL;
134     /* Don't worry about wasted memory here - this function is usually only
135     called once. */
136     }
137    
138     /* Sets the original and the current installation prefix of the package.
139     Relocation simply replaces a pathname starting with the original prefix
140     by the corresponding pathname with the current prefix instead. Both
141     prefixes should be directory names without trailing slash (i.e. use ""
142     instead of "/"). */
143     void
144     set_relocation_prefix (const char *orig_prefix_arg, const char *curr_prefix_arg)
145     {
146     set_this_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
147    
148     /* Now notify all dependent libraries. */
149     #if DEPENDS_ON_LIBCHARSET
150     libcharset_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
151     #endif
152     #if DEPENDS_ON_LIBICONV && HAVE_ICONV && _LIBICONV_VERSION >= 0x0109
153     libiconv_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
154     #endif
155     #if DEPENDS_ON_LIBINTL && ENABLE_NLS && defined libintl_set_relocation_prefix
156     libintl_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
157     #endif
158     }
159    
160     #if !defined IN_LIBRARY || (defined PIC && defined INSTALLDIR)
161    
162     /* Convenience function:
163     Computes the current installation prefix, based on the original
164     installation prefix, the original installation directory of a particular
165     file, and the current pathname of this file. Returns NULL upon failure. */
166     #ifdef IN_LIBRARY
167     #define compute_curr_prefix local_compute_curr_prefix
168     static
169     #endif
170     const char *
171     compute_curr_prefix (const char *orig_installprefix,
172     const char *orig_installdir,
173     const char *curr_pathname)
174     {
175     const char *curr_installdir;
176     const char *rel_installdir;
177    
178     if (curr_pathname == NULL)
179     return NULL;
180    
181     /* Determine the relative installation directory, relative to the prefix.
182     This is simply the difference between orig_installprefix and
183     orig_installdir. */
184     if (strncmp (orig_installprefix, orig_installdir, strlen (orig_installprefix))
185     != 0)
186     /* Shouldn't happen - nothing should be installed outside $(prefix). */
187     return NULL;
188     rel_installdir = orig_installdir + strlen (orig_installprefix);
189    
190     /* Determine the current installation directory. */
191     {
192     const char *p_base = curr_pathname + FILESYSTEM_PREFIX_LEN (curr_pathname);
193     const char *p = curr_pathname + strlen (curr_pathname);
194     char *q;
195    
196     while (p > p_base)
197     {
198     p--;
199     if (ISSLASH (*p))
200     break;
201     }
202    
203     q = (char *) xmalloc (p - curr_pathname + 1);
204     #ifdef NO_XMALLOC
205     if (q == NULL)
206     return NULL;
207     #endif
208     memcpy (q, curr_pathname, p - curr_pathname);
209     q[p - curr_pathname] = '\0';
210     curr_installdir = q;
211     }
212    
213     /* Compute the current installation prefix by removing the trailing
214     rel_installdir from it. */
215     {
216     const char *rp = rel_installdir + strlen (rel_installdir);
217     const char *cp = curr_installdir + strlen (curr_installdir);
218     const char *cp_base =
219     curr_installdir + FILESYSTEM_PREFIX_LEN (curr_installdir);
220    
221     while (rp > rel_installdir && cp > cp_base)
222     {
223     bool same = false;
224     const char *rpi = rp;
225     const char *cpi = cp;
226    
227     while (rpi > rel_installdir && cpi > cp_base)
228     {
229     rpi--;
230     cpi--;
231     if (ISSLASH (*rpi) || ISSLASH (*cpi))
232     {
233     if (ISSLASH (*rpi) && ISSLASH (*cpi))
234     same = true;
235     break;
236     }
237     #if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
238     /* Win32, OS/2, DOS - case insignificant filesystem */
239     if ((*rpi >= 'a' && *rpi <= 'z' ? *rpi - 'a' + 'A' : *rpi)
240     != (*cpi >= 'a' && *cpi <= 'z' ? *cpi - 'a' + 'A' : *cpi))
241     break;
242     #else
243     if (*rpi != *cpi)
244     break;
245     #endif
246     }
247     if (!same)
248     break;
249     /* The last pathname component was the same. opi and cpi now point
250     to the slash before it. */
251     rp = rpi;
252     cp = cpi;
253     }
254    
255     if (rp > rel_installdir)
256     /* Unexpected: The curr_installdir does not end with rel_installdir. */
257     return NULL;
258    
259     {
260     size_t curr_prefix_len = cp - curr_installdir;
261     char *curr_prefix;
262    
263     curr_prefix = (char *) xmalloc (curr_prefix_len + 1);
264     #ifdef NO_XMALLOC
265     if (curr_prefix == NULL)
266     return NULL;
267     #endif
268     memcpy (curr_prefix, curr_installdir, curr_prefix_len);
269     curr_prefix[curr_prefix_len] = '\0';
270    
271     return curr_prefix;
272     }
273     }
274     }
275    
276     #endif /* !IN_LIBRARY || PIC */
277    
278     #if defined PIC && defined INSTALLDIR
279    
280     /* Full pathname of shared library, or NULL. */
281     static char *shared_library_fullname;
282    
283     #if defined _WIN32 || defined __WIN32__
284    
285     /* Determine the full pathname of the shared library when it is loaded. */
286    
287     BOOL WINAPI
288     DllMain (HINSTANCE module_handle, DWORD event, LPVOID reserved)
289     {
290     (void) reserved;
291    
292     if (event == DLL_PROCESS_ATTACH)
293     {
294     /* The DLL is being loaded into an application's address range. */
295     static char location[MAX_PATH];
296    
297     if (!GetModuleFileName (module_handle, location, sizeof (location)))
298     /* Shouldn't happen. */
299     return FALSE;
300    
301     if (!IS_PATH_WITH_DIR (location))
302     /* Shouldn't happen. */
303     return FALSE;
304    
305     shared_library_fullname = strdup (location);
306     }
307    
308     return TRUE;
309     }
310    
311     #else /* Unix */
312    
313     static void
314     find_shared_library_fullname ()
315     {
316     #if defined __linux__ && __GLIBC__ >= 2
317     /* Linux has /proc/self/maps. glibc 2 has the getline() function. */
318     FILE *fp;
319    
320     /* Open the current process' maps file. It describes one VMA per line. */
321     fp = fopen ("/proc/self/maps", "r");
322     if (fp)
323     {
324     unsigned long address = (unsigned long) &find_shared_library_fullname;
325     for (;;)
326     {
327     unsigned long start, end;
328     int c;
329    
330     if (fscanf (fp, "%lx-%lx", &start, &end) != 2)
331     break;
332     if (address >= start && address <= end - 1)
333     {
334     /* Found it. Now see if this line contains a filename. */
335     while (c = getc (fp), c != EOF && c != '\n' && c != '/')
336     continue;
337     if (c == '/')
338     {
339     size_t size;
340     int len;
341    
342     ungetc (c, fp);
343     shared_library_fullname = NULL; size = 0;
344     len = getline (&shared_library_fullname, &size, fp);
345     if (len >= 0)
346     {
347     /* Success: filled shared_library_fullname. */
348     if (len > 0 && shared_library_fullname[len - 1] == '\n')
349     shared_library_fullname[len - 1] = '\0';
350     }
351     }
352     break;
353     }
354     while (c = getc (fp), c != EOF && c != '\n')
355     continue;
356     }
357     fclose (fp);
358     }
359     #endif
360     }
361    
362     #endif /* WIN32 / Unix */
363    
364     /* Return the full pathname of the current shared library.
365     Return NULL if unknown.
366     Guaranteed to work only on Linux and Woe32. */
367     static char *
368     get_shared_library_fullname ()
369     {
370     #if !(defined _WIN32 || defined __WIN32__)
371     static bool tried_find_shared_library_fullname;
372     if (!tried_find_shared_library_fullname)
373     {
374     find_shared_library_fullname ();
375     tried_find_shared_library_fullname = true;
376     }
377     #endif
378     return shared_library_fullname;
379     }
380    
381     #endif /* PIC */
382    
383     /* Returns the pathname, relocated according to the current installation
384     directory. */
385     const char *
386     relocate (const char *pathname)
387     {
388     #if defined PIC && defined INSTALLDIR
389     static int initialized;
390    
391     /* Initialization code for a shared library. */
392     if (!initialized)
393     {
394     /* At this point, orig_prefix and curr_prefix likely have already been
395     set through the main program's set_program_name_and_installdir
396     function. This is sufficient in the case that the library has
397     initially been installed in the same orig_prefix. But we can do
398     better, to also cover the cases that 1. it has been installed
399     in a different prefix before being moved to orig_prefix and (later)
400     to curr_prefix, 2. unlike the program, it has not moved away from
401     orig_prefix. */
402     const char *orig_installprefix = INSTALLPREFIX;
403     const char *orig_installdir = INSTALLDIR;
404     const char *curr_prefix_better;
405    
406     curr_prefix_better =
407     compute_curr_prefix (orig_installprefix, orig_installdir,
408     get_shared_library_fullname ());
409     if (curr_prefix_better == NULL)
410     curr_prefix_better = curr_prefix;
411    
412     set_relocation_prefix (orig_installprefix, curr_prefix_better);
413    
414     initialized = 1;
415     }
416     #endif
417    
418     /* Note: It is not necessary to perform case insensitive comparison here,
419     even for DOS-like filesystems, because the pathname argument was
420     typically created from the same Makefile variable as orig_prefix came
421     from. */
422     if (orig_prefix != NULL && curr_prefix != NULL
423     && strncmp (pathname, orig_prefix, orig_prefix_len) == 0)
424     {
425     if (pathname[orig_prefix_len] == '\0')
426     /* pathname equals orig_prefix. */
427     return curr_prefix;
428     if (ISSLASH (pathname[orig_prefix_len]))
429     {
430     /* pathname starts with orig_prefix. */
431     const char *pathname_tail = &pathname[orig_prefix_len];
432     char *result =
433     (char *) xmalloc (curr_prefix_len + strlen (pathname_tail) + 1);
434    
435     #ifdef NO_XMALLOC
436     if (result != NULL)
437     #endif
438     {
439     memcpy (result, curr_prefix, curr_prefix_len);
440     strcpy (result + curr_prefix_len, pathname_tail);
441     return result;
442     }
443     }
444     }
445     /* Nothing to relocate. */
446     return pathname;
447     }
448    
449     #endif

   
Visit the ZANavi Wiki