1 /* Handle aliases for locale names.
2 Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18 /* Tell glibc's <string.h> to provide a prototype for mempcpy().
19 This must come before <config.h> because <config.h> may include
20 <features.h>, and once <features.h> has been included, it's too late. */
31 #include <sys/types.h>
37 #include "intl/gettext/gettextP.h"
38 #include "util/memory.h"
39 #include "util/string.h"
41 #ifdef HAVE_FGETS_UNLOCKED
43 #define fgets(buf, len, s) fgets_unlocked (buf, len, s)
45 #ifdef HAVE_FEOF_UNLOCKED
47 #define feof(s) feof_unlocked (s)
51 const unsigned char *alias
;
52 const unsigned char *value
;
55 static unsigned char *string_space
;
56 static size_t string_space_act
;
57 static size_t string_space_max
;
58 static struct alias_map
*map
;
62 /* Prototypes for local functions. */
63 static size_t read_alias_file(const unsigned char *fname
, int fname_len
);
64 static int extend_alias_table(void);
65 static int alias_compare(const struct alias_map
* map1
,
66 const struct alias_map
* map2
);
69 _nl_expand_alias(const unsigned char *name
)
71 static const unsigned char *locale_alias_path
= LOCALEDIR
;
72 struct alias_map
*retval
;
73 const unsigned char *result
= NULL
;
77 struct alias_map item
;
82 retval
= (struct alias_map
*) bsearch(&item
, map
, nmap
,
92 /* We really found an alias. Return the value. */
94 result
= retval
->value
;
98 /* Perhaps we can find another alias file. */
100 while (added
== 0 && locale_alias_path
[0] != '\0') {
101 const unsigned char *start
;
103 while (locale_alias_path
[0] == PATH_SEPARATOR
)
105 start
= locale_alias_path
;
107 while (locale_alias_path
[0] != '\0'
108 && locale_alias_path
[0] != PATH_SEPARATOR
)
111 if (start
< locale_alias_path
)
112 added
= read_alias_file(start
,
123 read_alias_file(const unsigned char *fname
, int fname_len
)
126 unsigned char *full_fname
;
128 static const unsigned char aliasfile
[] = "/locale.alias";
130 full_fname
= (unsigned char *) fmem_alloc(fname_len
+ sizeof(aliasfile
));
131 mempcpy(mempcpy(full_fname
, fname
, fname_len
),
132 aliasfile
, sizeof(aliasfile
));
134 fp
= fopen(full_fname
, "rb");
135 fmem_free(full_fname
);
141 /* It is a reasonable approach to use a fix buffer here because
142 a) we are only interested in the first two fields
143 b) these fields must be usable as file names and so must not
146 unsigned char buf
[BUFSIZ
];
147 unsigned char *alias
;
148 unsigned char *value
;
151 if (fgets(buf
, sizeof(buf
), fp
) == NULL
)
155 /* Possibly not the whole line fits into the buffer. Ignore
156 the rest of the line. */
157 if (strchr((const char *)buf
, '\n') == NULL
) {
158 unsigned char altbuf
[BUFSIZ
];
161 if (fgets(altbuf
, sizeof(altbuf
), fp
) == NULL
)
162 /* Make sure the inner loop will be left. The outer loop
163 will exit at the `feof' test. */
165 while (strchr((const char *)altbuf
, '\n') == NULL
);
169 /* Ignore leading white space. */
172 /* A leading '#' signals a comment line. */
173 if (cp
[0] != '\0' && cp
[0] != '#') {
176 /* Terminate alias name. */
180 /* Now look for the beginning of the value. */
189 /* Terminate value. */
191 /* This has to be done to make the following test
192 for the end of line possible. We are looking for
193 the terminating '\n' which do not overwrite here. */
196 } else if (cp
[0] != '\0')
200 if (extend_alias_table())
203 alias_len
= strlen(alias
) + 1;
204 value_len
= strlen(value
) + 1;
206 if (string_space_act
+ alias_len
+ value_len
>
208 /* Increase size of memory pool. */
209 size_t new_size
= (string_space_max
215 unsigned char *new_pool
=
216 (unsigned char *) realloc(string_space
,
218 if (new_pool
== NULL
)
221 if (string_space
!= new_pool
) {
224 for (i
= 0; i
< nmap
; i
++) {
234 string_space
= new_pool
;
235 string_space_max
= new_size
;
239 memcpy(&string_space
[string_space_act
],
241 string_space_act
+= alias_len
;
244 memcpy(&string_space
[string_space_act
],
246 string_space_act
+= value_len
;
254 /* Should we test for ferror()? I think we have to silently ignore
259 qsort(map
, nmap
, sizeof(struct alias_map
),
260 (int (*)(const void *, const void *))
267 extend_alias_table(void)
270 struct alias_map
*new_map
;
272 new_size
= maxmap
== 0 ? 100 : 2 * maxmap
;
273 new_map
= (struct alias_map
*) realloc(map
, (new_size
275 sizeof(struct alias_map
)));
277 /* Simply don't extend: we don't have any more core. */
286 alias_compare(const struct alias_map
*map1
, const struct alias_map
*map2
)
288 return c_strcasecmp(map1
->alias
, map2
->alias
);