Update.
[platform/upstream/glibc.git] / locale / programs / ld-address.c
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
36 static 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
49 static 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.  */
63 struct 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;
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
80 static void
81 address_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
89   if (lr != NULL)
90     {
91       lr->translate_strings = 1;
92       lr->return_widestr = 0;
93     }
94 }
95
96
97 void
98 address_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;
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     }
136
137   if (address->postal_fmt == NULL)
138     {
139       if (! nothing)
140         error (0, 0, _("%s: field `%s' not defined"),
141                "LC_ADDRESS", "postal_fmt");
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     {                                                                         \
177       if (verbose && ! nothing)                                               \
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     {
194       if (verbose && ! nothing)
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     {
221       if (verbose && ! nothing)
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     {
281       if (verbose && ! nothing)
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     }
297
298   if (address->country_ab2 == NULL)
299     {
300       if (verbose && ! nothing)
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     {
312       if (verbose && ! nothing)
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
324 void
325 address_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
374   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
375   iov[cnt].iov_base = (void *) address->country_num;
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.  */
412 void
413 address_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     {
441       handle_copy (ldfile, charmap, repertoire, result, tok_lc_address,
442                    LC_ADDRESS, "LC_ADDRESS", ignore_content);
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:                                                       \
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                                                                               \
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:                                                       \
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                                                                               \
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 }