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