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