1 /* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
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.
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.
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
32 #include "localeinfo.h"
43 #define DEFINE_COUNTRY_CODE(Name, Ab2, Ab3, Num) \
45 #include "iso-3166.def"
56 #define DEFINE_LANGUAGE_CODE(Name, Ab, Term, Lib) \
58 #include "iso-639.def"
62 /* The real definition of the struct for the LC_ADDRESS locale. */
63 struct locale_address_t
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
;
71 const char *country_car
;
72 const char *country_isbn
;
73 const char *lang_name
;
75 const char *lang_term
;
81 address_startup (struct linereader
*lr
, struct localedef_t
*locale
,
85 locale
->categories
[LC_ADDRESS
].address
=
86 (struct locale_address_t
*) xcalloc (1,
87 sizeof (struct locale_address_t
));
91 lr
->translate_strings
= 1;
92 lr
->return_widestr
= 0;
98 address_finish (struct localedef_t
*locale
, const struct charmap_t
*charmap
)
100 struct locale_address_t
*address
= locale
->categories
[LC_ADDRESS
].address
;
105 /* Now resolve copying and also handle completely missing definitions. */
108 /* First see whether we were supposed to copy. If yes, find the
109 actual definition. */
110 if (locale
->copy_name
[LC_ADDRESS
] != NULL
)
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
;
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
);
122 address
= locale
->categories
[LC_ADDRESS
].address
123 = from
->categories
[LC_ADDRESS
].address
;
126 /* If there is still no definition issue an warning and create an
131 error (0, 0, _("No definition for %s category found"),
133 address_startup (NULL
, locale
, 0);
134 address
= locale
->categories
[LC_ADDRESS
].address
;
139 if (address
->postal_fmt
== NULL
)
142 error (0, 0, _("%s: field `%s' not defined"),
143 "LC_ADDRESS", "postal_fmt");
144 /* Use as the default value the value of the i18n locale. */
145 address
->postal_fmt
= "%a%N%f%N%d%N%b%N%s %h %e %r%N%C-%z %T%N%c%N";
149 /* We must check whether the format string contains only the
150 allowed escape sequences. */
151 const char *cp
= address
->postal_fmt
;
154 error (0, 0, _("%s: field `%s' must not be empty"),
155 "LC_ADDRESS", "postal_fmt");
164 if (strchr ("afdbshNtreCzTSc%", *cp
) == NULL
)
167 %s: invalid escape `%%%c' sequence in field `%s'"),
168 "LC_ADDRESS", *cp
, "postal_fmt");
176 #define TEST_ELEM(cat) \
177 if (address->cat == NULL) \
179 if (verbose && ! nothing) \
180 error (0, 0, _("%s: field `%s' not defined"), "LC_ADDRESS", #cat); \
184 TEST_ELEM (country_name
);
185 /* XXX Test against list of defined codes. */
186 TEST_ELEM (country_post
);
187 /* XXX Test against list of defined codes. */
188 TEST_ELEM (country_car
);
189 /* XXX Test against list of defined codes. */
190 TEST_ELEM (country_isbn
);
191 TEST_ELEM (lang_name
);
194 if (address
->lang_term
== NULL
)
196 if (verbose
&& ! nothing
)
197 error (0, 0, _("%s: field `%s' not defined"), "LC_ADDRESS",
199 address
->lang_term
= "";
200 cnt
= sizeof (iso639
) / sizeof (iso639
[0]);
202 else if (address
->lang_term
[0] == '\0')
205 error (0, 0, _("%s: field `%s' must not be empty"),
206 "LC_ADDRESS", "lang_term");
207 cnt
= sizeof (iso639
) / sizeof (iso639
[0]);
211 /* Look for this language in the table. */
212 for (cnt
= 0; cnt
< sizeof (iso639
) / sizeof (iso639
[0]); ++cnt
)
213 if (strcmp (address
->lang_term
, iso639
[cnt
].term
) == 0)
215 if (cnt
== sizeof (iso639
) / sizeof (iso639
[0]))
217 %s: terminology language code `%s' not defined"),
218 "LC_ADDRESS", address
->lang_term
);
221 if (address
->lang_ab
== NULL
)
223 if (verbose
&& ! nothing
)
224 error (0, 0, _("%s: field `%s' not defined"), "LC_ADDRESS", "lang_ab");
225 address
->lang_ab
= "";
227 else if (address
->lang_ab
[0] == '\0')
230 error (0, 0, _("%s: field `%s' must not be empty"),
231 "LC_ADDRESS", "lang_ab");
235 if (cnt
== sizeof (iso639
) / sizeof (iso639
[0]))
238 for (cnt
= 0; cnt
< sizeof (iso639
) / sizeof (iso639
[0]); ++cnt
)
239 if (strcmp (address
->lang_ab
, iso639
[cnt
].ab
) == 0)
241 if (cnt
== sizeof (iso639
) / sizeof (iso639
[0]))
243 %s: language abbreviation `%s' not defined"),
244 "LC_ADDRESS", address
->lang_ab
);
247 if (strcmp (iso639
[cnt
].ab
, address
->lang_ab
) != 0)
249 %s: `%s' value does not match `%s' value"),
250 "LC_ADDRESS", "lang_ab", "lang_term");
253 if (address
->lang_lib
== NULL
)
254 /* This is no error. */
255 address
->lang_lib
= address
->lang_term
;
256 else if (address
->lang_lib
[0] == '\0')
259 error (0, 0, _("%s: field `%s' must not be empty"),
260 "LC_ADDRESS", "lang_lib");
264 if (cnt
== sizeof (iso639
) / sizeof (iso639
[0]))
266 for (cnt
= 0; cnt
< sizeof (iso639
) / sizeof (iso639
[0]); ++cnt
)
267 if (strcmp (address
->lang_lib
, iso639
[cnt
].lib
) == 0)
269 if (cnt
== sizeof (iso639
) / sizeof (iso639
[0]))
271 %s: language abbreviation `%s' not defined"),
272 "LC_ADDRESS", address
->lang_lib
);
275 if (strcmp (iso639
[cnt
].ab
, address
->lang_ab
) != 0)
277 %s: `%s' value does not match `%s' value"), "LC_ADDRESS", "lang_lib",
278 helper
== 1 ? "lang_term" : "lang_ab");
281 if (address
->country_num
== 0)
283 if (verbose
&& ! nothing
)
284 error (0, 0, _("%s: field `%s' not defined"),
285 "LC_ADDRESS", "country_num");
286 cnt
= sizeof (iso3166
) / sizeof (iso3166
[0]);
290 for (cnt
= 0; cnt
< sizeof (iso3166
) / sizeof (iso3166
[0]); ++cnt
)
291 if (address
->country_num
== iso3166
[cnt
].num
)
294 if (cnt
== sizeof (iso3166
) / sizeof (iso3166
[0]))
296 %s: numeric country code `%d' not valid"),
297 "LC_ADDRESS", address
->country_num
);
300 if (address
->country_ab2
== NULL
)
302 if (verbose
&& ! nothing
)
303 error (0, 0, _("%s: field `%s' not defined"),
304 "LC_ADDRESS", "country_ab2");
305 address
->country_ab2
= " ";
307 else if (cnt
!= sizeof (iso3166
) / sizeof (iso3166
[0])
308 && strcmp (address
->country_ab2
, iso3166
[cnt
].ab2
) != 0)
309 error (0, 0, _("%s: `%s' value does not match `%s' value"),
310 "LC_ADDRESS", "country_ab2", "country_num");
312 if (address
->country_ab3
== NULL
)
314 if (verbose
&& ! nothing
)
315 error (0, 0, _("%s: field `%s' not defined"),
316 "LC_ADDRESS", "country_ab3");
317 address
->country_ab3
= " ";
319 else if (cnt
!= sizeof (iso3166
) / sizeof (iso3166
[0])
320 && strcmp (address
->country_ab3
, iso3166
[cnt
].ab3
) != 0)
321 error (0, 0, _("%s: `%s' value does not match `%s' value"),
322 "LC_ADDRESS", "country_ab3", "country_num");
327 address_output (struct localedef_t
*locale
, const struct charmap_t
*charmap
,
328 const char *output_path
)
330 struct locale_address_t
*address
= locale
->categories
[LC_ADDRESS
].address
;
331 struct iovec iov
[3 + _NL_ITEM_INDEX (_NL_NUM_LC_ADDRESS
)];
332 struct locale_file data
;
333 uint32_t idx
[_NL_ITEM_INDEX (_NL_NUM_LC_ADDRESS
)];
336 data
.magic
= LIMAGIC (LC_ADDRESS
);
337 data
.n
= _NL_ITEM_INDEX (_NL_NUM_LC_ADDRESS
);
338 iov
[cnt
].iov_base
= (void *) &data
;
339 iov
[cnt
].iov_len
= sizeof (data
);
342 iov
[cnt
].iov_base
= (void *) idx
;
343 iov
[cnt
].iov_len
= sizeof (idx
);
346 idx
[cnt
- 2] = iov
[0].iov_len
+ iov
[1].iov_len
;
347 iov
[cnt
].iov_base
= (void *) address
->postal_fmt
;
348 iov
[cnt
].iov_len
= strlen (iov
[cnt
].iov_base
) + 1;
351 idx
[cnt
- 2] = idx
[cnt
- 3] + iov
[cnt
- 1].iov_len
;
352 iov
[cnt
].iov_base
= (void *) address
->country_name
;
353 iov
[cnt
].iov_len
= strlen (iov
[cnt
].iov_base
) + 1;
356 idx
[cnt
- 2] = idx
[cnt
- 3] + iov
[cnt
- 1].iov_len
;
357 iov
[cnt
].iov_base
= (void *) address
->country_post
;
358 iov
[cnt
].iov_len
= strlen (iov
[cnt
].iov_base
) + 1;
361 idx
[cnt
- 2] = idx
[cnt
- 3] + iov
[cnt
- 1].iov_len
;
362 iov
[cnt
].iov_base
= (void *) address
->country_ab2
;
363 iov
[cnt
].iov_len
= strlen (iov
[cnt
].iov_base
) + 1;
366 idx
[cnt
- 2] = idx
[cnt
- 3] + iov
[cnt
- 1].iov_len
;
367 iov
[cnt
].iov_base
= (void *) address
->country_ab3
;
368 iov
[cnt
].iov_len
= strlen (iov
[cnt
].iov_base
) + 1;
371 idx
[cnt
- 2] = idx
[cnt
- 3] + iov
[cnt
- 1].iov_len
;
372 iov
[cnt
].iov_base
= (void *) address
->country_car
;
373 iov
[cnt
].iov_len
= strlen (iov
[cnt
].iov_base
) + 1;
376 idx
[cnt
- 2] = idx
[cnt
- 3] + iov
[cnt
- 1].iov_len
;
378 /* Align following data */
379 iov
[cnt
].iov_base
= (void *) "\0\0";
380 iov
[cnt
].iov_len
= ((idx
[cnt
- 2] + 3) & ~3) - idx
[cnt
- 2];
381 idx
[cnt
- 2] = (idx
[cnt
- 2] + 3) & ~3;
384 iov
[cnt
].iov_base
= (void *) &address
->country_num
;
385 iov
[cnt
].iov_len
= sizeof (uint32_t);
388 idx
[cnt
- 3] = idx
[cnt
- 4] + iov
[cnt
- 1].iov_len
;
389 iov
[cnt
].iov_base
= (void *) address
->country_isbn
;
390 iov
[cnt
].iov_len
= strlen (iov
[cnt
].iov_base
) + 1;
393 idx
[cnt
- 3] = idx
[cnt
- 4] + iov
[cnt
- 1].iov_len
;
394 iov
[cnt
].iov_base
= (void *) address
->lang_name
;
395 iov
[cnt
].iov_len
= strlen (iov
[cnt
].iov_base
) + 1;
398 idx
[cnt
- 3] = idx
[cnt
- 4] + iov
[cnt
- 1].iov_len
;
399 iov
[cnt
].iov_base
= (void *) address
->lang_ab
;
400 iov
[cnt
].iov_len
= strlen (iov
[cnt
].iov_base
) + 1;
403 idx
[cnt
- 3] = idx
[cnt
- 4] + iov
[cnt
- 1].iov_len
;
404 iov
[cnt
].iov_base
= (void *) address
->lang_term
;
405 iov
[cnt
].iov_len
= strlen (iov
[cnt
].iov_base
) + 1;
408 idx
[cnt
- 3] = idx
[cnt
- 4] + iov
[cnt
- 1].iov_len
;
409 iov
[cnt
].iov_base
= (void *) address
->lang_lib
;
410 iov
[cnt
].iov_len
= strlen (iov
[cnt
].iov_base
) + 1;
413 idx
[cnt
- 3] = idx
[cnt
- 4] + iov
[cnt
- 1].iov_len
;
414 iov
[cnt
].iov_base
= (void *) charmap
->code_set_name
;
415 iov
[cnt
].iov_len
= strlen (iov
[cnt
].iov_base
) + 1;
418 assert (cnt
== 3 + _NL_ITEM_INDEX (_NL_NUM_LC_ADDRESS
));
420 write_locale_data (output_path
, "LC_ADDRESS",
421 3 + _NL_ITEM_INDEX (_NL_NUM_LC_ADDRESS
), iov
);
425 /* The parser for the LC_ADDRESS section of the locale definition. */
427 address_read (struct linereader
*ldfile
, struct localedef_t
*result
,
428 const struct charmap_t
*charmap
, const char *repertoire_name
,
431 struct locale_address_t
*address
;
436 /* The rest of the line containing `LC_ADDRESS' must be free. */
437 lr_ignore_rest (ldfile
, 1);
442 now
= lr_token (ldfile
, charmap
, result
, NULL
, verbose
);
445 while (nowtok
== tok_eol
);
447 /* If we see `copy' now we are almost done. */
448 if (nowtok
== tok_copy
)
450 handle_copy (ldfile
, charmap
, repertoire_name
, result
, tok_lc_address
,
451 LC_ADDRESS
, "LC_ADDRESS", ignore_content
);
455 /* Prepare the data structures. */
456 address_startup (ldfile
, result
, ignore_content
);
457 address
= result
->categories
[LC_ADDRESS
].address
;
461 /* Of course we don't proceed beyond the end of file. */
462 if (nowtok
== tok_eof
)
465 /* Ignore empty lines. */
466 if (nowtok
== tok_eol
)
468 now
= lr_token (ldfile
, charmap
, result
, NULL
, verbose
);
475 #define STR_ELEM(cat) \
477 /* Ignore the rest of the line if we don't need the input of \
479 if (ignore_content) \
481 lr_ignore_rest (ldfile, 0); \
485 arg = lr_token (ldfile, charmap, result, NULL, verbose); \
486 if (arg->tok != tok_string) \
488 if (address->cat != NULL) \
489 lr_error (ldfile, _("\
490 %s: field `%s' declared more than once"), "LC_ADDRESS", #cat); \
491 else if (!ignore_content && arg->val.str.startmb == NULL) \
493 lr_error (ldfile, _("\
494 %s: unknown character in field `%s'"), "LC_ADDRESS", #cat); \
497 else if (!ignore_content) \
498 address->cat = arg->val.str.startmb; \
501 STR_ELEM (postal_fmt
);
502 STR_ELEM (country_name
);
503 STR_ELEM (country_post
);
504 STR_ELEM (country_ab2
);
505 STR_ELEM (country_ab3
);
506 STR_ELEM (country_car
);
507 STR_ELEM (lang_name
);
509 STR_ELEM (lang_term
);
512 #define INT_STR_ELEM(cat) \
514 /* Ignore the rest of the line if we don't need the input of \
516 if (ignore_content) \
518 lr_ignore_rest (ldfile, 0); \
522 arg = lr_token (ldfile, charmap, result, NULL, verbose); \
523 if (arg->tok != tok_string && arg->tok != tok_number) \
525 if (address->cat != NULL) \
526 lr_error (ldfile, _("\
527 %s: field `%s' declared more than once"), "LC_ADDRESS", #cat); \
528 else if (!ignore_content && arg->tok == tok_string \
529 && arg->val.str.startmb == NULL) \
531 lr_error (ldfile, _("\
532 %s: unknown character in field `%s'"), "LC_ADDRESS", #cat); \
535 else if (!ignore_content) \
537 if (arg->tok == tok_string) \
538 address->cat = arg->val.str.startmb; \
541 char *numbuf = (char *) xmalloc (11); \
542 snprintf (numbuf, 11, "%ld", arg->val.num); \
543 address->cat = numbuf; \
548 INT_STR_ELEM (country_isbn
);
550 #define INT_ELEM(cat) \
552 /* Ignore the rest of the line if we don't need the input of \
554 if (ignore_content) \
556 lr_ignore_rest (ldfile, 0); \
560 arg = lr_token (ldfile, charmap, result, NULL, verbose); \
561 if (arg->tok != tok_number) \
563 else if (address->cat != 0) \
564 lr_error (ldfile, _("\
565 %s: field `%s' declared more than once"), "LC_ADDRESS", #cat); \
566 else if (!ignore_content) \
567 address->cat = arg->val.num; \
570 INT_ELEM (country_num
);
573 /* Next we assume `LC_ADDRESS'. */
574 arg
= lr_token (ldfile
, charmap
, result
, NULL
, verbose
);
575 if (arg
->tok
== tok_eof
)
577 if (arg
->tok
== tok_eol
)
578 lr_error (ldfile
, _("%s: incomplete `END' line"),
580 else if (arg
->tok
!= tok_lc_address
)
581 lr_error (ldfile
, _("\
582 %1$s: definition does not end with `END %1$s'"), "LC_ADDRESS");
583 lr_ignore_rest (ldfile
, arg
->tok
== tok_lc_address
);
588 SYNTAX_ERROR (_("%s: syntax error"), "LC_ADDRESS");
591 /* Prepare for the next round. */
592 now
= lr_token (ldfile
, charmap
, result
, NULL
, verbose
);
596 /* When we come here we reached the end of the file. */
597 lr_error (ldfile
, _("%s: premature end of file"), "LC_ADDRESS");