source: trunk/essentials/app-shells/bash/lib/intl/relocatable.c@ 3506

Last change on this file since 3506 was 3231, checked in by bird, 19 years ago

eol style.

  • Property svn:eol-style set to native
File size: 12.5 KB
Line 
1/* Provide relocatable packages.
2 Copyright (C) 2003 Free Software Foundation, Inc.
3 Written by Bruno Haible <[email protected]>, 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 "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. */
87static char *orig_prefix;
88static size_t orig_prefix_len;
89/* Current installation prefix. */
90static char *curr_prefix;
91static 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 "/"). */
100static void
101set_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 "/"). */
138void
139set_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
161static
162#endif
163const char *
164compute_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}