]> git.ipfire.org Git - thirdparty/glibc.git/blame - locale/programs/ld-address.c
Update.
[thirdparty/glibc.git] / locale / programs / ld-address.c
CommitLineData
4b10dd6c
UD
1/* Copyright (C) 1998, 1999 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 <byteswap.h>
25#include <error.h>
26#include <langinfo.h>
27#include <string.h>
28#include <sys/uio.h>
29
30#include <assert.h>
31
32#include "localeinfo.h"
33#include "locfile.h"
34
35
36static struct
37{
38 const char ab2[2];
39 const char ab3[3];
40 uint32_t num;
41} iso3166[] =
42{
43#define DEFINE_COUNTRY_CODE(Name, Ab2, Ab3, Num) \
44 { #Ab2, #Ab3, Num },
45#include "iso-3166.def"
46};
47
48
49static struct
50{
51 const char ab[2];
52 const char term[3];
53 const char lib[3];
54} iso639[] =
55{
56#define DEFINE_LANGUAGE_CODE(Name, Ab, Term, Lib) \
57 { #Ab, #Term, #Lib },
58#include "iso-639.def"
59};
60
61
62/* The real definition of the struct for the LC_ADDRESS locale. */
63struct locale_address_t
64{
65 const char *postal_fmt;
66 const char *country_name;
67 const char *country_post;
68 const char *country_ab2;
69 const char *country_ab3;
70 uint32_t country_num;
4b10dd6c
UD
71 const char *country_car;
72 const char *country_isbn;
73 const char *lang_name;
74 const char *lang_ab;
75 const char *lang_term;
76 const char *lang_lib;
77};
78
79
80static void
81address_startup (struct linereader *lr, struct localedef_t *locale,
82 int ignore_content)
83{
84 if (!ignore_content)
85 locale->categories[LC_ADDRESS].address =
86 (struct locale_address_t *) xcalloc (1,
87 sizeof (struct locale_address_t));
88
b9eb05d6
UD
89 if (lr != NULL)
90 {
91 lr->translate_strings = 1;
92 lr->return_widestr = 0;
93 }
4b10dd6c
UD
94}
95
96
97void
98address_finish (struct localedef_t *locale, struct charmap_t *charmap)
99{
100 struct locale_address_t *address = locale->categories[LC_ADDRESS].address;
101 size_t cnt;
102 int helper;
b9eb05d6
UD
103 int nothing = 0;
104
105 /* Now resolve copying and also handle completely missing definitions. */
106 if (address == NULL)
107 {
108 /* First see whether we were supposed to copy. If yes, find the
109 actual definition. */
110 if (locale->copy_name[LC_ADDRESS] != NULL)
111 {
112 /* Find the copying locale. This has to happen transitively since
113 the locale we are copying from might also copying another one. */
114 struct localedef_t *from = locale;
115
116 do
117 from = find_locale (LC_ADDRESS, from->copy_name[LC_ADDRESS],
118 from->repertoire_name, charmap);
119 while (from->categories[LC_ADDRESS].address == NULL
120 && from->copy_name[LC_ADDRESS] != NULL);
121
122 address = locale->categories[LC_ADDRESS].address
123 = from->categories[LC_ADDRESS].address;
124 }
125
126 /* If there is still no definition issue an warning and create an
127 empty one. */
128 if (address == NULL)
129 {
130 error (0, 0, _("No definition for %s category found"), "LC_ADDRESS");
131 address_startup (NULL, locale, 0);
132 address = locale->categories[LC_ADDRESS].address;
133 nothing = 1;
134 }
135 }
4b10dd6c
UD
136
137 if (address->postal_fmt == NULL)
138 {
b9eb05d6
UD
139 if (! nothing)
140 error (0, 0, _("%s: field `%s' not defined"),
141 "LC_ADDRESS", "postal_fmt");
4b10dd6c
UD
142 /* Use as the default value the value of the i18n locale. */
143 address->postal_fmt = "%a%N%f%N%d%N%b%N%s %h %e %r%N%C-%z %T%N%c%N";
144 }
145 else
146 {
147 /* We must check whether the format string contains only the
148 allowed escape sequences. */
149 const char *cp = address->postal_fmt;
150
151 if (*cp == '\0')
152 error (0, 0, _("%s: field `%s' must not be empty"),
153 "LC_ADDRESS", "postal_fmt");
154 else
155 while (*cp != '\0')
156 {
157 if (*cp == '%')
158 {
159 if (*++cp == 'R')
160 /* Romanize-flag. */
161 ++cp;
162 if (strchr ("afdbshNtreCzTc%", *cp) == NULL)
163 {
164 error (0, 0, _("\
165%s: invalid escape `%%%c' sequence in field `%s'"),
166 "LC_ADDRESS", *cp, "postal_fmt");
167 break;
168 }
169 }
170 ++cp;
171 }
172 }
173
174#define TEST_ELEM(cat) \
175 if (address->cat == NULL) \
176 { \
b9eb05d6 177 if (verbose && ! nothing) \
4b10dd6c
UD
178 error (0, 0, _("%s: field `%s' not defined"), "LC_ADDRESS", #cat); \
179 address->cat = ""; \
180 }
181
182 TEST_ELEM (country_name);
183 /* XXX Test against list of defined codes. */
184 TEST_ELEM (country_post);
185 /* XXX Test against list of defined codes. */
186 TEST_ELEM (country_car);
187 /* XXX Test against list of defined codes. */
188 TEST_ELEM (country_isbn);
189 TEST_ELEM (lang_name);
190
191 helper = 1;
192 if (address->lang_term == NULL)
193 {
b9eb05d6 194 if (verbose && ! nothing)
4b10dd6c
UD
195 error (0, 0, _("%s: field `%s' not defined"), "LC_ADDRESS",
196 "lang_term");
197 address->lang_term = "";
198 cnt = sizeof (iso639) / sizeof (iso639[0]);
199 }
200 else if (address->lang_term[0] == '\0')
201 {
202 if (verbose)
203 error (0, 0, _("%s: field `%s' must not be empty"),
204 "LC_ADDRESS", "lang_term");
205 cnt = sizeof (iso639) / sizeof (iso639[0]);
206 }
207 else
208 {
209 /* Look for this language in the table. */
210 for (cnt = 0; cnt < sizeof (iso639) / sizeof (iso639[0]); ++cnt)
211 if (strcmp (address->lang_term, iso639[cnt].term) == 0)
212 break;
213 if (cnt == sizeof (iso639) / sizeof (iso639[0]))
214 error (0, 0, _("\
215%s: terminology language code `%s' not defined"),
216 "LC_ADDRESS", address->lang_term);
217 }
218
219 if (address->lang_ab == NULL)
220 {
b9eb05d6 221 if (verbose && ! nothing)
4b10dd6c
UD
222 error (0, 0, _("%s: field `%s' not defined"), "LC_ADDRESS", "lang_ab");
223 address->lang_ab = "";
224 }
225 else if (address->lang_ab[0] == '\0')
226 {
227 if (verbose)
228 error (0, 0, _("%s: field `%s' must not be empty"),
229 "LC_ADDRESS", "lang_ab");
230 }
231 else
232 {
233 if (cnt == sizeof (iso639) / sizeof (iso639[0]))
234 {
235 helper = 2;
236 for (cnt = 0; cnt < sizeof (iso639) / sizeof (iso639[0]); ++cnt)
237 if (strcmp (address->lang_ab, iso639[cnt].ab) == 0)
238 break;
239 if (cnt == sizeof (iso639) / sizeof (iso639[0]))
240 error (0, 0, _("\
241%s: language abbreviation `%s' not defined"),
242 "LC_ADDRESS", address->lang_ab);
243 }
244 else
245 if (strcmp (iso639[cnt].ab, address->lang_ab) != 0)
246 error (0, 0, _("\
247%s: `%s' value does not match `%s' value"),
248 "LC_ADDRESS", "lang_ab", "lang_term");
249 }
250
251 if (address->lang_lib == NULL)
252 /* This is no error. */
253 address->lang_lib = address->lang_term;
254 else if (address->lang_lib[0] == '\0')
255 {
256 if (verbose)
257 error (0, 0, _("%s: field `%s' must not be empty"),
258 "LC_ADDRESS", "lang_lib");
259 }
260 else
261 {
262 if (cnt == sizeof (iso639) / sizeof (iso639[0]))
263 {
264 for (cnt = 0; cnt < sizeof (iso639) / sizeof (iso639[0]); ++cnt)
265 if (strcmp (address->lang_lib, iso639[cnt].lib) == 0)
266 break;
267 if (cnt == sizeof (iso639) / sizeof (iso639[0]))
268 error (0, 0, _("\
269%s: language abbreviation `%s' not defined"),
270 "LC_ADDRESS", address->lang_lib);
271 }
272 else
273 if (strcmp (iso639[cnt].ab, address->lang_ab) != 0)
274 error (0, 0, _("\
275%s: `%s' value does not match `%s' value"), "LC_ADDRESS", "lang_lib",
276 helper == 1 ? "lang_term" : "lang_ab");
277 }
278
279 if (address->country_num == 0)
280 {
b9eb05d6 281 if (verbose && ! nothing)
4b10dd6c
UD
282 error (0, 0, _("%s: field `%s' not defined"),
283 "LC_ADDRESS", "country_num");
284 cnt = sizeof (iso3166) / sizeof (iso3166[0]);
285 }
286 else
287 {
288 for (cnt = 0; cnt < sizeof (iso3166) / sizeof (iso3166[0]); ++cnt)
289 if (address->country_num == iso3166[cnt].num)
290 break;
291
292 if (cnt == sizeof (iso3166) / sizeof (iso3166[0]))
293 error (0, 0, _("\
294%s: numeric country code `%d' not valid"),
295 "LC_ADDRESS", address->country_num);
296 }
4b10dd6c
UD
297
298 if (address->country_ab2 == NULL)
299 {
b9eb05d6 300 if (verbose && ! nothing)
4b10dd6c
UD
301 error (0, 0, _("%s: field `%s' not defined"),
302 "LC_ADDRESS", "country_ab2");
303 address->country_ab2 = " ";
304 }
305 else if (cnt != sizeof (iso3166) / sizeof (iso3166[0])
306 && strcmp (address->country_ab2, iso3166[cnt].ab2) != 0)
307 error (0, 0, _("%s: `%s' value does not match `%s' value"),
308 "LC_ADDRESS", "country_ab2", "country_num");
309
310 if (address->country_ab3 == NULL)
311 {
b9eb05d6 312 if (verbose && ! nothing)
4b10dd6c
UD
313 error (0, 0, _("%s: field `%s' not defined"),
314 "LC_ADDRESS", "country_ab3");
315 address->country_ab3 = " ";
316 }
317 else if (cnt != sizeof (iso3166) / sizeof (iso3166[0])
318 && strcmp (address->country_ab3, iso3166[cnt].ab3) != 0)
319 error (0, 0, _("%s: `%s' value does not match `%s' value"),
320 "LC_ADDRESS", "country_ab3", "country_num");
321}
322
323
324void
325address_output (struct localedef_t *locale, struct charmap_t *charmap,
326 const char *output_path)
327{
328 struct locale_address_t *address = locale->categories[LC_ADDRESS].address;
329 struct iovec iov[2 + _NL_ITEM_INDEX (_NL_NUM_LC_ADDRESS)];
330 struct locale_file data;
331 uint32_t idx[_NL_ITEM_INDEX (_NL_NUM_LC_ADDRESS)];
332 size_t cnt = 0;
333
334 data.magic = LIMAGIC (LC_ADDRESS);
335 data.n = _NL_ITEM_INDEX (_NL_NUM_LC_ADDRESS);
336 iov[cnt].iov_base = (void *) &data;
337 iov[cnt].iov_len = sizeof (data);
338 ++cnt;
339
340 iov[cnt].iov_base = (void *) idx;
341 iov[cnt].iov_len = sizeof (idx);
342 ++cnt;
343
344 idx[cnt - 2] = iov[0].iov_len + iov[1].iov_len;
345 iov[cnt].iov_base = (void *) address->postal_fmt;
346 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
347 ++cnt;
348
349 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
350 iov[cnt].iov_base = (void *) address->country_name;
351 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
352 ++cnt;
353
354 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
355 iov[cnt].iov_base = (void *) address->country_post;
356 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
357 ++cnt;
358
359 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
360 iov[cnt].iov_base = (void *) address->country_ab2;
361 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
362 ++cnt;
363
364 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
365 iov[cnt].iov_base = (void *) address->country_ab3;
366 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
367 ++cnt;
368
369 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
370 iov[cnt].iov_base = (void *) address->country_car;
371 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
372 ++cnt;
373
4b10dd6c 374 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
4a33c2f5 375 iov[cnt].iov_base = (void *) address->country_num;
4b10dd6c
UD
376 iov[cnt].iov_len = sizeof (uint32_t);
377 ++cnt;
378
379 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
380 iov[cnt].iov_base = (void *) address->country_isbn;
381 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
382 ++cnt;
383
384 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
385 iov[cnt].iov_base = (void *) address->lang_name;
386 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
387 ++cnt;
388
389 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
390 iov[cnt].iov_base = (void *) address->lang_ab;
391 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
392 ++cnt;
393
394 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
395 iov[cnt].iov_base = (void *) address->lang_term;
396 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
397 ++cnt;
398
399 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
400 iov[cnt].iov_base = (void *) address->lang_lib;
401 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
402 ++cnt;
403
404 assert (cnt == 2 + _NL_ITEM_INDEX (_NL_NUM_LC_ADDRESS));
405
406 write_locale_data (output_path, "LC_ADDRESS",
407 2 + _NL_ITEM_INDEX (_NL_NUM_LC_ADDRESS), iov);
408}
409
410
411/* The parser for the LC_ADDRESS section of the locale definition. */
412void
413address_read (struct linereader *ldfile, struct localedef_t *result,
414 struct charmap_t *charmap, const char *repertoire_name,
415 int ignore_content)
416{
417 struct repertoire_t *repertoire = NULL;
418 struct locale_address_t *address;
419 struct token *now;
420 struct token *arg;
421 enum token_t nowtok;
422
423 /* Get the repertoire we have to use. */
424 if (repertoire_name != NULL)
425 repertoire = repertoire_read (repertoire_name);
426
427 /* The rest of the line containing `LC_ADDRESS' must be free. */
428 lr_ignore_rest (ldfile, 1);
429
430
431 do
432 {
433 now = lr_token (ldfile, charmap, NULL);
434 nowtok = now->tok;
435 }
436 while (nowtok == tok_eol);
437
438 /* If we see `copy' now we are almost done. */
439 if (nowtok == tok_copy)
440 {
b9eb05d6
UD
441 handle_copy (ldfile, charmap, repertoire, result, tok_lc_address,
442 LC_ADDRESS, "LC_ADDRESS", ignore_content);
4b10dd6c
UD
443 return;
444 }
445
446 /* Prepare the data structures. */
447 address_startup (ldfile, result, ignore_content);
448 address = result->categories[LC_ADDRESS].address;
449
450 while (1)
451 {
452 /* Of course we don't proceed beyond the end of file. */
453 if (nowtok == tok_eof)
454 break;
455
456 /* Ingore empty lines. */
457 if (nowtok == tok_eol)
458 {
459 now = lr_token (ldfile, charmap, NULL);
460 nowtok = now->tok;
461 continue;
462 }
463
464 switch (nowtok)
465 {
466#define STR_ELEM(cat) \
467 case tok_##cat: \
b9eb05d6
UD
468 /* Ignore the rest of the line if we don't need the input of \
469 this line. */ \
470 if (ignore_content) \
471 { \
472 lr_ignore_rest (ldfile, 0); \
473 break; \
474 } \
475 \
4b10dd6c
UD
476 arg = lr_token (ldfile, charmap, NULL); \
477 if (arg->tok != tok_string) \
478 goto err_label; \
479 if (address->cat != NULL) \
480 lr_error (ldfile, _("\
481%s: field `%s' declared more than once"), "LC_ADDRESS", #cat); \
482 else if (!ignore_content && arg->val.str.startmb == NULL) \
483 { \
484 lr_error (ldfile, _("\
485%s: unknown character in field `%s'"), "LC_ADDRESS", #cat); \
486 address->cat = ""; \
487 } \
488 else if (!ignore_content) \
489 address->cat = arg->val.str.startmb; \
490 break
491
492 STR_ELEM (postal_fmt);
493 STR_ELEM (country_name);
494 STR_ELEM (country_post);
495 STR_ELEM (country_ab2);
496 STR_ELEM (country_ab3);
497 STR_ELEM (country_car);
498 STR_ELEM (country_isbn);
499 STR_ELEM (lang_name);
500 STR_ELEM (lang_ab);
501 STR_ELEM (lang_term);
502 STR_ELEM (lang_lib);
503
504#define INT_ELEM(cat) \
505 case tok_##cat: \
b9eb05d6
UD
506 /* Ignore the rest of the line if we don't need the input of \
507 this line. */ \
508 if (ignore_content) \
509 { \
510 lr_ignore_rest (ldfile, 0); \
511 break; \
512 } \
513 \
4b10dd6c
UD
514 arg = lr_token (ldfile, charmap, NULL); \
515 if (arg->tok != tok_number) \
516 goto err_label; \
517 else if (address->cat != 0) \
518 lr_error (ldfile, _("\
519%s: field `%s' declared more than once"), "LC_ADDRESS", #cat); \
520 else if (!ignore_content) \
521 address->cat = arg->val.num; \
522 break
523
524 INT_ELEM (country_num);
525
526 case tok_end:
527 /* Next we assume `LC_ADDRESS'. */
528 arg = lr_token (ldfile, charmap, NULL);
529 if (arg->tok == tok_eof)
530 break;
531 if (arg->tok == tok_eol)
532 lr_error (ldfile, _("%s: incomplete `END' line"),
533 "LC_ADDRESS");
534 else if (arg->tok != tok_lc_address)
535 lr_error (ldfile, _("\
536%1$s: definition does not end with `END %1$s'"), "LC_ADDRESS");
537 lr_ignore_rest (ldfile, arg->tok == tok_lc_address);
538 return;
539
540 default:
541 err_label:
542 SYNTAX_ERROR (_("%s: syntax error"), "LC_ADDRESS");
543 }
544
545 /* Prepare for the next round. */
546 now = lr_token (ldfile, charmap, NULL);
547 nowtok = now->tok;
548 }
549
550 /* When we come here we reached the end of the file. */
551 lr_error (ldfile, _("%s: premature end of file"), "LC_ADDRESS");
552}