iconv: Bail out of the loop when an illegal sequence of bytes occurs.
[elinks/elinks-j605.git] / src / intl / gettext / localealias.c
blobc8fe2279a4f3b33393790998439aa9200c69c98d
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)
7 any later version.
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. */
21 #ifndef _GNU_SOURCE
22 #define _GNU_SOURCE 1
23 #endif
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
29 #include <ctype.h>
30 #include <stdio.h>
31 #include <sys/types.h>
32 #include <stdlib.h>
33 #include <string.h>
35 #include "elinks.h"
37 #include "intl/gettext/gettextP.h"
38 #include "util/memory.h"
39 #include "util/string.h"
41 #ifdef HAVE_FGETS_UNLOCKED
42 #undef fgets
43 #define fgets(buf, len, s) fgets_unlocked (buf, len, s)
44 #endif
45 #ifdef HAVE_FEOF_UNLOCKED
46 #undef feof
47 #define feof(s) feof_unlocked (s)
48 #endif
50 struct alias_map {
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;
59 static size_t nmap;
60 static size_t maxmap;
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);
68 const unsigned char *
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;
74 size_t added;
76 do {
77 struct alias_map item;
79 item.alias = name;
81 if (nmap > 0)
82 retval = (struct alias_map *) bsearch(&item, map, nmap,
83 sizeof(struct
84 alias_map),
85 (int (*)
86 (const void *,
87 const void *)
88 ) alias_compare);
89 else
90 retval = NULL;
92 /* We really found an alias. Return the value. */
93 if (retval != NULL) {
94 result = retval->value;
95 break;
98 /* Perhaps we can find another alias file. */
99 added = 0;
100 while (added == 0 && locale_alias_path[0] != '\0') {
101 const unsigned char *start;
103 while (locale_alias_path[0] == PATH_SEPARATOR)
104 ++locale_alias_path;
105 start = locale_alias_path;
107 while (locale_alias_path[0] != '\0'
108 && locale_alias_path[0] != PATH_SEPARATOR)
109 ++locale_alias_path;
111 if (start < locale_alias_path)
112 added = read_alias_file(start,
113 locale_alias_path -
114 start);
117 while (added != 0);
119 return result;
122 static size_t
123 read_alias_file(const unsigned char *fname, int fname_len)
125 FILE *fp;
126 unsigned char *full_fname;
127 size_t added;
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);
136 if (fp == NULL)
137 return 0;
139 added = 0;
140 while (!feof(fp)) {
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
144 be that long
146 unsigned char buf[BUFSIZ];
147 unsigned char *alias;
148 unsigned char *value;
149 unsigned char *cp;
151 if (fgets(buf, sizeof(buf), fp) == NULL)
152 /* EOF reached. */
153 break;
155 /* Possibly not the whole line fits into the buffer. Ignore
156 the rest of the line. */
157 if (strchr(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. */
164 break;
165 while (strchr(altbuf, '\n') == NULL);
168 cp = buf;
169 /* Ignore leading white space. */
170 skip_space(cp);
172 /* A leading '#' signals a comment line. */
173 if (cp[0] != '\0' && cp[0] != '#') {
174 alias = cp++;
175 skip_nonspace(cp);
176 /* Terminate alias name. */
177 if (cp[0] != '\0')
178 *cp++ = '\0';
180 /* Now look for the beginning of the value. */
181 skip_space(cp);
183 if (cp[0] != '\0') {
184 size_t alias_len;
185 size_t value_len;
187 value = cp++;
188 skip_nonspace(cp);
189 /* Terminate value. */
190 if (cp[0] == '\n') {
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. */
194 *cp++ = '\0';
195 *cp = '\n';
196 } else if (cp[0] != '\0')
197 *cp++ = '\0';
199 if (nmap >= maxmap)
200 if (extend_alias_table())
201 return added;
203 alias_len = strlen(alias) + 1;
204 value_len = strlen(value) + 1;
206 if (string_space_act + alias_len + value_len >
207 string_space_max) {
208 /* Increase size of memory pool. */
209 size_t new_size = (string_space_max
210 + (alias_len +
211 value_len >
212 1024 ? alias_len +
213 value_len :
214 1024));
215 unsigned char *new_pool =
216 (unsigned char *) realloc(string_space,
217 new_size);
218 if (new_pool == NULL)
219 return added;
221 if (string_space != new_pool) {
222 size_t i;
224 for (i = 0; i < nmap; i++) {
225 map[i].alias +=
226 new_pool -
227 string_space;
228 map[i].value +=
229 new_pool -
230 string_space;
234 string_space = new_pool;
235 string_space_max = new_size;
238 map[nmap].alias =
239 memcpy(&string_space[string_space_act],
240 alias, alias_len);
241 string_space_act += alias_len;
243 map[nmap].value =
244 memcpy(&string_space[string_space_act],
245 value, value_len);
246 string_space_act += value_len;
248 ++nmap;
249 ++added;
254 /* Should we test for ferror()? I think we have to silently ignore
255 errors. --drepper */
256 fclose(fp);
258 if (added > 0)
259 qsort(map, nmap, sizeof(struct alias_map),
260 (int (*)(const void *, const void *))
261 alias_compare);
263 return added;
266 static int
267 extend_alias_table(void)
269 size_t new_size;
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)));
276 if (new_map == NULL)
277 /* Simply don't extend: we don't have any more core. */
278 return -1;
280 map = new_map;
281 maxmap = new_size;
282 return 0;
285 static int
286 alias_compare(const struct alias_map *map1, const struct alias_map *map2)
288 return c_strcasecmp(map1->alias, map2->alias);