]> git.ipfire.org Git - thirdparty/glibc.git/blob - locale/programs/repertoire.c
Update.
[thirdparty/glibc.git] / locale / programs / repertoire.c
1 /* Copyright (C) 1998 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
9
10 The GNU C Library 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 the GNU C Library; see the file COPYING.LIB. If not,
17 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. */
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #include <errno.h>
25 #include <error.h>
26 #include <limits.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30
31 #include "linereader.h"
32 #include "charset.h"
33 #include "repertoire.h"
34 #include "simple-hash.h"
35
36
37 extern void *xmalloc (size_t __n);
38
39
40 /* Simple keyword hashing for the repertoiremap. */
41 static struct repertoire_t *parse_repertoiremap (const char *filename);
42 static const struct keyword_t *repertoiremap_hash (const char *str, int len);
43
44
45 struct repertoire_t *
46 repertoire_read (const char *filename)
47 {
48 const char *pathnfile;
49 struct repertoire_t *result = NULL;
50
51 if (euidaccess (filename, R_OK) >= 0)
52 pathnfile = filename;
53 else if (filename[0] != '/')
54 {
55 char *cp = xmalloc (strlen (filename) + sizeof CHARMAP_PATH + 1);
56 stpcpy (stpcpy (stpcpy (cp, CHARMAP_PATH), "/"), filename);
57
58 pathnfile = (const char *) cp;
59 }
60 else
61 pathnfile = NULL;
62
63 if (pathnfile != NULL)
64 {
65 result = parse_repertoiremap (pathnfile);
66
67 if (result == NULL && !be_quiet)
68 error (0, errno, _("repertoire map file `%s' not found"), filename);
69 }
70
71 return result;
72 }
73
74
75 static struct repertoire_t *
76 parse_repertoiremap (const char *filename)
77 {
78 struct linereader *cmfile;
79 struct repertoire_t *result;
80 int state;
81 char *from_name = NULL;
82 char *to_name = NULL;
83
84 /* Determine path. */
85 cmfile = lr_open (filename, repertoiremap_hash);
86 if (cmfile == NULL)
87 {
88 if (strchr (filename, '/') == NULL)
89 {
90 /* Look in the systems charmap directory. */
91 char *buf = xmalloc (strlen (filename) + 1
92 + sizeof (REPERTOIREMAP_PATH));
93
94 stpcpy (stpcpy (stpcpy (buf, REPERTOIREMAP_PATH), "/"), filename);
95 cmfile = lr_open (buf, repertoiremap_hash);
96
97 if (cmfile == NULL)
98 free (buf);
99 }
100
101 if (cmfile == NULL)
102 return NULL;
103 }
104
105 /* Allocate room for result. */
106 result = (struct repertoire_t *) xmalloc (sizeof (struct repertoire_t));
107 memset (result, '\0', sizeof (struct repertoire_t));
108
109 #define obstack_chunk_alloc malloc
110 #define obstack_chunk_free free
111 obstack_init (&result->mem_pool);
112
113 if (init_hash (&result->char_table, 256))
114 {
115 free (result);
116 return NULL;
117 }
118
119 /* We use a state machine to describe the charmap description file
120 format. */
121 state = 1;
122 while (1)
123 {
124 /* What's on? */
125 struct token *now = lr_token (cmfile, NULL);
126 enum token_t nowtok = now->tok;
127 struct token *arg;
128
129 if (nowtok == tok_eof)
130 break;
131
132 switch (state)
133 {
134 case 1:
135 /* We haven't yet read any character definition. This is where
136 we accept escape_char and comment_char definitions. */
137 if (nowtok == tok_eol)
138 /* Ignore empty lines. */
139 continue;
140
141 if (nowtok == tok_escape_char || nowtok == tok_comment_char)
142 {
143 /* We know that we need an argument. */
144 arg = lr_token (cmfile, NULL);
145
146 if (arg->tok != tok_ident)
147 {
148 lr_error (cmfile, _("syntax error in prolog: %s"),
149 _("bad argument"));
150
151 lr_ignore_rest (cmfile, 0);
152 continue;
153 }
154
155 if (arg->val.str.len != 1)
156 {
157 lr_error (cmfile, _("\
158 argument to <%s> must be a single character"),
159 nowtok == tok_escape_char ? "escape_char"
160 : "comment_char");
161
162 lr_ignore_rest (cmfile, 0);
163 continue;
164 }
165
166 if (nowtok == tok_escape_char)
167 cmfile->escape_char = *arg->val.str.start;
168 else
169 cmfile->comment_char = *arg->val.str.start;
170
171 lr_ignore_rest (cmfile, 1);
172 continue;
173 }
174
175 if (nowtok == tok_charids)
176 {
177 lr_ignore_rest (cmfile, 1);
178
179 state = 2;
180 continue;
181 }
182
183 /* Otherwise we start reading the character definitions. */
184 state = 2;
185 /* FALLTHROUGH */
186
187 case 2:
188 /* We are now are in the body. Each line
189 must have the format "%s %s %s\n" or "%s...%s %s %s\n". */
190 if (nowtok == tok_eol)
191 /* Ignore empty lines. */
192 continue;
193
194 if (nowtok == tok_end)
195 {
196 state = 90;
197 continue;
198 }
199
200 if (nowtok != tok_bsymbol)
201 {
202 lr_error (cmfile,
203 _("syntax error in repertoire map definition: %s"),
204 _("no symbolic name given"));
205
206 lr_ignore_rest (cmfile, 0);
207 continue;
208 }
209
210 /* If the previous line was not completely correct free the
211 used memory. */
212 if (from_name != NULL)
213 obstack_free (&result->mem_pool, from_name);
214
215 from_name = (char *) obstack_copy0 (&result->mem_pool,
216 now->val.str.start,
217 now->val.str.len);
218 to_name = NULL;
219
220 state = 3;
221 continue;
222
223 case 3:
224 /* We have two possibilities: We can see an ellipsis or an
225 encoding value. */
226 if (nowtok == tok_ellipsis)
227 {
228 state = 4;
229 continue;
230 }
231 /* FALLTHROUGH */
232
233 case 5:
234 /* We expect a value of the form <Uxxxx> or <Uxxxxxxxx> where
235 the xxx mean a hexadecimal value. */
236 state = 2;
237
238 errno = 0;
239 if (nowtok != tok_ucs2 && nowtok != tok_ucs4)
240 {
241 lr_error (cmfile,
242 _("syntax error in repertoire map definition: %s"),
243 _("no <Uxxxx> or <Uxxxxxxxx> value given"));
244
245 lr_ignore_rest (cmfile, 0);
246 continue;
247 }
248
249 /* We've found a new valid definition. */
250 charset_new_char (cmfile, &result->char_table, 4,
251 now->val.charcode.val, from_name, to_name);
252
253 /* Ignore the rest of the line. */
254 lr_ignore_rest (cmfile, 0);
255
256 from_name = NULL;
257 to_name = NULL;
258
259 continue;
260
261 case 4:
262 if (nowtok != tok_bsymbol)
263 {
264 lr_error (cmfile,
265 _("syntax error in repertoire map definition: %s"),
266 _("no symbolic name given for end of range"));
267
268 lr_ignore_rest (cmfile, 0);
269 state = 2;
270 continue;
271 }
272
273 /* Copy the to-name in a safe place. */
274 to_name = (char *) obstack_copy0 (&result->mem_pool,
275 cmfile->token.val.str.start,
276 cmfile->token.val.str.len);
277
278 state = 5;
279 continue;
280
281 case 90:
282 if (nowtok != tok_charids)
283 lr_error (cmfile, _("\
284 `%1$s' definition does not end with `END %1$s'"), "CHARIDS");
285
286 lr_ignore_rest (cmfile, nowtok == tok_charids);
287 break;
288 }
289
290 break;
291 }
292
293 if (state != 2 && state != 90 && !be_quiet)
294 error (0, 0, _("%s: premature end of file"), cmfile->fname);
295
296 lr_close (cmfile);
297
298 return result;
299 }
300
301
302 static const struct keyword_t *
303 repertoiremap_hash (const char *str, int len)
304 {
305 static const struct keyword_t wordlist[0] =
306 {
307 {"escape_char", tok_escape_char, 1},
308 {"comment_char", tok_comment_char, 1},
309 {"CHARIDS", tok_charids, 0},
310 {"END", tok_end, 0},
311 };
312
313 if (len == 11 && memcmp (wordlist[0].name, str, 11) == 0)
314 return &wordlist[0];
315 if (len == 12 && memcmp (wordlist[1].name, str, 12) == 0)
316 return &wordlist[1];
317 if (len == 7 && memcmp (wordlist[2].name, str, 7) == 0)
318 return &wordlist[2];
319 if (len == 3 && memcmp (wordlist[3].name, str, 3) == 0)
320 return &wordlist[3];
321
322 return NULL;
323 }