1 /* Copyright (C) 1995, 1996 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
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.
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.
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
17 not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. */
30 /* Undefine following line in production version. */
31 /* #define NDEBUG 1 */
35 #include "localeinfo.h"
36 #include "stringtrans.h"
38 void *xmalloc (size_t __n
);
39 void *xrealloc (void *__ptr
, size_t __n
);
42 /* The real definition of the struct for the LC_NUMERIC locale. */
43 struct locale_monetary_t
45 const char *int_curr_symbol
;
46 const char *currency_symbol
;
47 const char *mon_decimal_point
;
48 const char *mon_thousands_sep
;
50 size_t mon_grouping_max
;
51 size_t mon_grouping_act
;
52 const char *positive_sign
;
53 const char *negative_sign
;
54 signed char int_frac_digits
;
55 signed char frac_digits
;
56 signed char p_cs_precedes
;
57 signed char p_sep_by_space
;
58 signed char n_cs_precedes
;
59 signed char n_sep_by_space
;
60 signed char p_sign_posn
;
61 signed char n_sign_posn
;
65 /* The content iof the field int_curr_symbol has to be taken from
66 ISO-4217. We test for correct values. */
67 #define DEFINE_INT_CURR(str) str,
68 static const char *const valid_int_curr
[] =
70 # include "../iso-4217.def"
72 #define NR_VALID_INT_CURR ((sizeof (valid_int_curr) \
73 / sizeof (valid_int_curr[0])))
74 #undef DEFINE_INT_CURR
77 /* Prototypes for local functions. */
78 static int curr_strcmp(const char *s1
, const char **s2
);
82 monetary_startup (struct linereader
*lr
, struct localedef_t
*locale
,
83 struct charset_t
*charset
)
85 struct locale_monetary_t
*monetary
;
87 /* It is important that we always use UCS1 encoding for strings now. */
88 encoding_method
= ENC_UCS1
;
90 locale
->categories
[LC_MONETARY
].monetary
= monetary
=
91 (struct locale_monetary_t
*) xmalloc (sizeof (struct locale_monetary_t
));
93 memset (monetary
, '\0', sizeof (struct locale_monetary_t
));
95 monetary
->mon_grouping_max
= 80;
96 monetary
->mon_grouping
=
97 (char *) xmalloc (monetary
->mon_grouping_max
);
98 monetary
->mon_grouping_act
= 0;
100 monetary
->int_frac_digits
= -2;
101 monetary
->frac_digits
= -2;
102 monetary
->p_cs_precedes
= -2;
103 monetary
->p_sep_by_space
= -2;
104 monetary
->n_cs_precedes
= -2;
105 monetary
->n_sep_by_space
= -2;
106 monetary
->p_sign_posn
= -2;
107 monetary
->n_sign_posn
= -2;
112 monetary_finish (struct localedef_t
*locale
)
114 struct locale_monetary_t
*monetary
115 = locale
->categories
[LC_MONETARY
].monetary
;
117 #define TEST_ELEM(cat) \
118 if (monetary->cat == NULL) \
119 error (0, 0, _("field `%s' in category `%s' not defined"), \
122 TEST_ELEM (int_curr_symbol
);
123 TEST_ELEM (currency_symbol
);
124 TEST_ELEM (mon_decimal_point
);
125 TEST_ELEM (mon_thousands_sep
);
126 TEST_ELEM (positive_sign
);
127 TEST_ELEM (negative_sign
);
129 /* The international currency symbol must come from ISO 4217. */
130 if (monetary
->int_curr_symbol
!= NULL
)
132 if (strlen (monetary
->int_curr_symbol
) != 4)
134 value of field `int_curr_symbol' in category `LC_MONETARY' has wrong length"));
135 else if (bsearch (monetary
->int_curr_symbol
, valid_int_curr
,
136 NR_VALID_INT_CURR
, sizeof (const char *),
137 (comparison_fn_t
) curr_strcmp
) == NULL
)
139 value of field `int_curr_symbol' in category `LC_MONETARY' does \
140 not correspond to a valid name in ISO 4217"));
143 /* The decimal point must not be empty. This is not said explicitly
144 in POSIX but ANSI C (ISO/IEC 9899) says in 4.4.2.1 it has to be
146 if (monetary
->mon_decimal_point
[0] == '\0')
149 value for field `%s' in category `%s' must not be the empty string"),
150 "mon_decimal_point", "LC_MONETARY");
153 if (monetary
->mon_grouping_act
== 0)
154 error (0, 0, _("field `%s' in category `%s' not defined"),
155 "mon_grouping", "LC_MONETARY");
158 #define TEST_ELEM(cat, min, max) \
159 if (monetary->cat == -2) \
160 error (0, 0, _("field `%s' in category `%s' not defined"), \
161 #cat, "LC_MONETARY"); \
162 else if (monetary->cat < min || monetary->cat > max) \
164 value for field `%s' in category `%s' must be in range %d...%d"), \
165 #cat, "LC_MONETARY", min, max)
168 /* The following two test are not really necessary because all values
169 the variable could have are valid. */
170 TEST_ELEM (int_frac_digits
, -128, 127); /* No range check. */
171 TEST_ELEM (frac_digits
, -128, 127); /* No range check. */
173 TEST_ELEM (p_cs_precedes
, -1, 1);
174 TEST_ELEM (p_sep_by_space
, -1, 2);
175 TEST_ELEM (n_cs_precedes
, -1, 1);
176 TEST_ELEM (n_sep_by_space
, -1, 2);
177 TEST_ELEM (p_sign_posn
, -1, 4);
178 TEST_ELEM (n_sign_posn
, -1, 4);
183 monetary_output (struct localedef_t
*locale
, const char *output_path
)
185 struct locale_monetary_t
*monetary
186 = locale
->categories
[LC_MONETARY
].monetary
;
187 struct iovec iov
[2 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY
)];
188 struct locale_file data
;
189 u_int32_t idx
[_NL_ITEM_INDEX (_NL_NUM_LC_MONETARY
)];
192 if ((locale
->binary
& (1 << LC_MONETARY
)) != 0)
194 iov
[0].iov_base
= monetary
;
195 iov
[0].iov_len
= locale
->len
[LC_MONETARY
];
197 write_locale_data (output_path
, "LC_MONETARY", 1, iov
);
202 data
.magic
= LIMAGIC (LC_MONETARY
);
203 data
.n
= _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY
);
204 iov
[cnt
].iov_base
= (void *) &data
;
205 iov
[cnt
].iov_len
= sizeof (data
);
208 iov
[cnt
].iov_base
= (void *) idx
;
209 iov
[cnt
].iov_len
= sizeof (idx
);
212 idx
[cnt
- 2] = iov
[0].iov_len
+ iov
[1].iov_len
;
213 iov
[cnt
].iov_base
= (void *) (monetary
->int_curr_symbol
?: "");
214 iov
[cnt
].iov_len
= strlen (iov
[cnt
].iov_base
) + 1;
217 idx
[cnt
- 2] = idx
[cnt
- 3] + iov
[cnt
- 1].iov_len
;
218 iov
[cnt
].iov_base
= (void *) (monetary
->currency_symbol
?: "");
219 iov
[cnt
].iov_len
= strlen (iov
[cnt
].iov_base
) + 1;
222 idx
[cnt
- 2] = idx
[cnt
- 3] + iov
[cnt
- 1].iov_len
;
223 iov
[cnt
].iov_base
= (void *) (monetary
->mon_decimal_point
?: "");
224 iov
[cnt
].iov_len
= strlen (iov
[cnt
].iov_base
) + 1;
227 idx
[cnt
- 2] = idx
[cnt
- 3] + iov
[cnt
- 1].iov_len
;
228 iov
[cnt
].iov_base
= (void *) (monetary
->mon_thousands_sep
?: "");
229 iov
[cnt
].iov_len
= strlen (iov
[cnt
].iov_base
) + 1;
232 idx
[cnt
- 2] = idx
[cnt
- 3] + iov
[cnt
- 1].iov_len
;
233 iov
[cnt
].iov_base
= alloca (monetary
->mon_grouping_act
+ 1);
234 iov
[cnt
].iov_len
= monetary
->mon_grouping_act
+ 1;
235 memcpy (iov
[cnt
].iov_base
, monetary
->mon_grouping
,
236 monetary
->mon_grouping_act
);
237 ((char *) iov
[cnt
].iov_base
)[monetary
->mon_grouping_act
] = '\0';
240 idx
[cnt
- 2] = idx
[cnt
- 3] + iov
[cnt
- 1].iov_len
;
241 iov
[cnt
].iov_base
= (void *) (monetary
->positive_sign
?: "");
242 iov
[cnt
].iov_len
= strlen (iov
[cnt
].iov_base
) + 1;
245 idx
[cnt
- 2] = idx
[cnt
- 3] + iov
[cnt
- 1].iov_len
;
246 iov
[cnt
].iov_base
= (void *) (monetary
->negative_sign
?: "");
247 iov
[cnt
].iov_len
= strlen (iov
[cnt
].iov_base
) + 1;
250 idx
[cnt
- 2] = idx
[cnt
- 3] + iov
[cnt
- 1].iov_len
;
251 iov
[cnt
].iov_base
= (void *) &monetary
->int_frac_digits
;
252 iov
[cnt
].iov_len
= 1;
255 idx
[cnt
- 2] = idx
[cnt
- 3] + iov
[cnt
- 1].iov_len
;
256 iov
[cnt
].iov_base
= (void *) &monetary
->frac_digits
;
257 iov
[cnt
].iov_len
= 1;
260 idx
[cnt
- 2] = idx
[cnt
- 3] + iov
[cnt
- 1].iov_len
;
261 iov
[cnt
].iov_base
= (void *) &monetary
->p_cs_precedes
;
262 iov
[cnt
].iov_len
= 1;
265 idx
[cnt
- 2] = idx
[cnt
- 3] + iov
[cnt
- 1].iov_len
;
266 iov
[cnt
].iov_base
= (void *) &monetary
->p_sep_by_space
;
267 iov
[cnt
].iov_len
= 1;
270 idx
[cnt
- 2] = idx
[cnt
- 3] + iov
[cnt
- 1].iov_len
;
271 iov
[cnt
].iov_base
= (void *) &monetary
->n_cs_precedes
;
272 iov
[cnt
].iov_len
= 1;
275 idx
[cnt
- 2] = idx
[cnt
- 3] + iov
[cnt
- 1].iov_len
;
276 iov
[cnt
].iov_base
= (void *) &monetary
->n_sep_by_space
;
277 iov
[cnt
].iov_len
= 1;
280 idx
[cnt
- 2] = idx
[cnt
- 3] + iov
[cnt
- 1].iov_len
;
281 iov
[cnt
].iov_base
= (void *) &monetary
->p_sign_posn
;
282 iov
[cnt
].iov_len
= 1;
285 idx
[cnt
- 2] = idx
[cnt
- 3] + iov
[cnt
- 1].iov_len
;
286 iov
[cnt
].iov_base
= (void *) &monetary
->n_sign_posn
;
287 iov
[cnt
].iov_len
= 1;
289 assert (cnt
+ 1 == 2 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY
));
291 write_locale_data (output_path
, "LC_MONETARY",
292 2 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY
), iov
);
297 monetary_add (struct linereader
*lr
, struct localedef_t
*locale
,
298 enum token_t tok
, struct token
*code
,
299 struct charset_t
*charset
)
301 struct locale_monetary_t
*monetary
302 = locale
->categories
[LC_MONETARY
].monetary
;
306 #define STR_ELEM(cat) \
308 if (monetary->cat != NULL) \
310 field `%s' in category `%s' declared more than once"), \
311 #cat, "LC_MONETARY"); \
312 else if (code->val.str.start == NULL) \
314 lr_error (lr, _("unknown character in field `%s' of category `%s'"),\
315 #cat, "LC_MONETARY"); \
316 monetary->cat = ""; \
319 monetary->cat = code->val.str.start; \
322 STR_ELEM (int_curr_symbol
);
323 STR_ELEM (currency_symbol
);
324 STR_ELEM (mon_decimal_point
);
325 STR_ELEM (mon_thousands_sep
);
326 STR_ELEM (positive_sign
);
327 STR_ELEM (negative_sign
);
329 #define INT_ELEM(cat) \
331 if (monetary->cat != -2) \
333 field `%s' in category `%s' declared more than once"), \
334 #cat, "LC_MONETARY"); \
336 monetary->cat = code->val.num; \
339 INT_ELEM (int_frac_digits
);
340 INT_ELEM (frac_digits
);
341 INT_ELEM (p_cs_precedes
);
342 INT_ELEM (p_sep_by_space
);
343 INT_ELEM (n_cs_precedes
);
344 INT_ELEM (n_sep_by_space
);
345 INT_ELEM (p_sign_posn
);
346 INT_ELEM (n_sign_posn
);
348 case tok_mon_grouping
:
349 if (monetary
->mon_grouping_act
== monetary
->mon_grouping_max
)
351 monetary
->mon_grouping_max
*= 2;
352 monetary
->mon_grouping
=
353 (char *) xrealloc (monetary
->mon_grouping
,
354 monetary
->mon_grouping_max
);
356 if (monetary
->mon_grouping
[monetary
->mon_grouping_act
- 1]
359 `-1' must be last entry in `%s' field in `%s' category"),
360 "mon_grouping", "LC_MONETARY");
363 if (code
->tok
== tok_minus1
)
364 monetary
->mon_grouping
[monetary
->mon_grouping_act
++] = '\177';
365 else if (code
->val
.num
== 0)
367 values for field `%s' in category `%s' must not be zero"),
368 "mon_grouping", "LC_MONETARY");
369 else if (code
->val
.num
> 126)
371 values for field `%s' in category `%s' must be smaller than 127"),
372 "mon_grouping", "LC_MONETARY");
374 monetary
->mon_grouping
[monetary
->mon_grouping_act
++]
380 assert (! "unknown token in category `LC_MONETARY': should not happen");
386 curr_strcmp(const char *s1
, const char **s2
)
388 return strcmp (s1
, *s2
);