Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
monetary.cpp
Go to the documentation of this file.
1
29#include "def.h" // for Def
30#include "diagnostic.h" // for issue_diag()
31#include "path.h" // for get_pathname()
32#include "scanner.h" // for scanner
33
34#include <cassert> // for assert()
35#include <climits> // for CHAR_MAX, CHAR_MIN
36#include <cstdlib> // for strtol()
37#include <fstream> // for ofstream
38#include <locale> // for money_base
39
40
41static const char lc_name[] = "LC_MONETARY";
42
43
44void Def::process_monetary ()
45{
46 issue_diag (I_STAGE, false, 0, "processing %s section\n", lc_name);
47
48 // nesting level
49 int nesting_level = 0;
50
51 mon_def_found_ = true;
52
53 while ((next = scanner_.next_token ()).token != Scanner::tok_monetary) {
54
55 // set to point to the integer represented as an ordinary char
56 // corresponding to p_cs_precedes, p_sep_by_space, p_sign_posn,
57 // or one of the n_ (or int_ versions) of the same
58 char *pcharint = 0;
59
60 typedef unsigned char UChar;
61 long maxval = long (UChar (CHAR_MAX)); // maximum allowed value
62
63 switch (next.token) {
64
66 next = scanner_.next_token();
67 if (next.token == Scanner::tok_monetary) {
68 // end of monetary block
69 if (nesting_level == 0)
70 return;
71
72 nesting_level--;
73 scanner_.close ();
74 }
75 else
76 issue_diag (E_SYNTAX, true, &next,
77 "wrong section name in END directive\n");
78
79 break;
80
81 case Scanner::tok_copy: {
82 next = scanner_.next_token();
83 if (next.token != Scanner::tok_string)
84 issue_diag (E_SYNTAX, true, &next,
85 "expected string following \"copy\" directive\n");
86
87 // bump up the nesting level
88 nesting_level++;
89
90 issue_diag (I_STAGE, false, 0, "processing copy directive\n");
91
92 // open the file
93 scanner_.open (get_pathname (strip_quotes (next.name), next.file));
94
95 // get comment char and escape char;
96 // these informations are stored by the scanner
97 while ((next = scanner_.next_token ()).token
99 // the LC_IDENTIFICATION section may also have a
100 // LC_MONETARY token that will mess up the parsing
101 if (next.token == Scanner::tok_ident) {
102 while ((next = scanner_.next_token()).token
103 != Scanner::tok_end );
104 next = scanner_.next_token();
105 }
106 }
107 break;
108 }
109
111 next = scanner_.next_token();
112 mon_st_.int_curr_symbol = convert_string (next.name);
113 mon_st_.wint_curr_symbol = convert_wstring (next);
114 break;
115
117 next = scanner_.next_token();
118 mon_st_.currency_symbol = convert_string (next.name);
119 mon_st_.wcurrency_symbol = convert_wstring (next);
120 break;
121
123 next = scanner_.next_token();
124 mon_st_.mon_decimal_point = convert_string (next.name);
125 mon_st_.wmon_decimal_point = convert_wstring (next);
126 break;
127
129 next = scanner_.next_token();
130 mon_st_.mon_thousands_sep = convert_string (next.name);
131 mon_st_.wmon_thousands_sep = convert_wstring (next);
132 break;
133
135 mon_st_.mon_grouping.clear();
136 while ((next = scanner_.next_token()).token != Scanner::tok_nl)
137 mon_st_.mon_grouping += std::strtol (next.name.c_str (), 0, 10);
138 break;
139
141 next = scanner_.next_token();
142 mon_st_.positive_sign = convert_string (next.name);
143 mon_st_.wpositive_sign = convert_wstring (next);
144 break;
145
147 next = scanner_.next_token();
148 mon_st_.negative_sign = convert_string (next.name);
149 mon_st_.wnegative_sign = convert_wstring (next);
150 break;
151
153 pcharint = &mon_out_.frac_digits [0];
154 break;
155
157 pcharint = &mon_out_.frac_digits [1 /* int'l */ ];
158 break;
159
161 maxval = 1;
162 pcharint = &mon_out_.p_cs_precedes [0];
163 break;
164
166 maxval = 2;
167 pcharint = &mon_out_.p_sep_by_space [0];
168 break;
169
171 maxval = 1;
172 pcharint = &mon_out_.n_cs_precedes [0];
173 break;
174
176 maxval = 2;
177 pcharint = &mon_out_.n_sep_by_space [0];
178 break;
179
181 maxval = 4;
182 pcharint = &mon_out_.p_sign_posn [0];
183 break;
184
186 maxval = 4;
187 pcharint = &mon_out_.n_sign_posn [0];
188 break;
189
191 maxval = 1;
192 pcharint = &mon_out_.p_cs_precedes [1 /* int'l */ ];
193 break;
194
196 maxval = 2;
197 pcharint = &mon_out_.p_sep_by_space [1 /* int'l */ ];
198 break;
199
201 maxval = 1;
202 pcharint = &mon_out_.n_cs_precedes [1 /* int'l */ ];
203 break;
204
206 maxval = 2;
207 pcharint = &mon_out_.n_sep_by_space [1 /* int'l */ ];
208 break;
209
211 maxval = 4;
212 pcharint = &mon_out_.p_sign_posn [1 /* int'l */ ];
213 break;
214
216 maxval = 4;
217 pcharint = &mon_out_.n_sign_posn [1 /* int'l */ ];
218 break;
219
220 default:
221 break;
222
223 }
224
225 if (pcharint) {
226 next = scanner_.next_token ();
227
228 char *end = 0;
229 const long val = std::strtol (next.name.c_str (), &end, 10);
230
231 if (next.name.empty () || *end || val < -1 || maxval < val) {
232 // report as errors values outside the permitted range
233 // (-1 indicates an unspecified value for a keyword)
234 issue_diag (E_INVAL, true, &next,
235 "expected integer in [0, %li], got: %s\n",
236 maxval, next.name.c_str ());
237 }
238 else
239 *pcharint = -1 == val ? CHAR_MAX : char (val);
240 }
241 }
242}
243
244
245void Def::create_format (char format [4],
246 char sign_posn,
247 char cs_precedes,
248 char sep_by_space,
249 bool is_positive)
250{
251 switch (sign_posn) {
252 // the international extension is not defined for this locale
253 case CHAR_MAX:
254 format [0] = CHAR_MAX;
255 format [1] = CHAR_MAX;
256 format [2] = CHAR_MAX;
257 format [3] = CHAR_MAX;
258 return;
259
260 case 0:
261 // if sign_posn is 0 then we change the sign to "()", if sign is
262 // not the empty string then issue a warning
263 if (is_positive) {
264 if (!mon_st_.positive_sign.empty())
266 issue_diag (W_INVAL, false, 0,
267 "invalid combination of positive_sign "
268 "and p_sign_posn. Ignoring positive_sign")
270 mon_st_.positive_sign = "()";
271 }
272 else {
273 if (!mon_st_.negative_sign.empty())
275 issue_diag (W_INVAL, false, 0,
276 "invalid combination of negative_sign "
277 "and n_sign_posn. Ignoring negative_sign")
279 mon_st_.negative_sign = "()";
280 }
281
282 // now construct the format
283 format[0] = std::money_base::sign;
284 if (cs_precedes == 0) {
285 format[1] = std::money_base::value;
286 format[2] = std::money_base::symbol;
287 }
288 else {
289 format[1] = std::money_base::symbol;
290 format[2] = std::money_base::value;
291 }
292
293 break;
294 case 1:
295 format[0] = std::money_base::sign;
296 if (cs_precedes == 0) {
297 format[1] = std::money_base::value;
298 format[2] = std::money_base::symbol;
299 }
300 else {
301 format[1] = std::money_base::symbol;
302 format[2] = std::money_base::value;
303 }
304 break;
305 case 2:
306 if (cs_precedes == 0) {
307 format[0] = std::money_base::value;
308 format[1] = std::money_base::symbol;
309 }
310 else {
311 format[0] = std::money_base::symbol;
312 format[1] = std::money_base::value;
313 }
314 format[2] = std::money_base::sign;
315 break;
316 case 3:
317 if (cs_precedes == 0) {
318 format[0] = std::money_base::value;
319 format[1] = std::money_base::sign;
320 format[2] = std::money_base::symbol;
321 }
322 else {
323 format[0] = std::money_base::sign;
324 format[1] = std::money_base::symbol;
325 format[2] = std::money_base::value;
326 }
327 break;
328 case 4:
329 if (cs_precedes == 0) {
330 format[0] = std::money_base::value;
331 format[1] = std::money_base::symbol;
332 format[2] = std::money_base::sign;
333 }
334 else {
335 format[0] = std::money_base::symbol;
336 format[1] = std::money_base::sign;
337 format[2] = std::money_base::value;
338 }
339 break;
340 default:
341 break;
342 }
343
344 // now put the space in the appropriate position
345 if (sep_by_space == 0)
346 format[3] = std::money_base::none;
347 else if (sep_by_space == 1) {
348 if (format[0] == std::money_base::value) {
349 format[3] = format[2];
350 format[2] = format[1];
351 format[1] = std::money_base::space;
352 }
353 else if (format[2] == std::money_base::value) {
354 format[3] = format[2];
355 format[2] = std::money_base::space;
356 }
357 else if (format[0] == std::money_base::symbol) {
358 format[3] = format[2];
359 format[2] = format[1];
360 format[1] = std::money_base::space;
361 }
362 else {
363 format[3] = format[2];
364 format[2] = std::money_base::space;
365 }
366 }
367 else {
368 if (format[0] == std::money_base::value) {
369 format[3] = format[2];
370 format[2] = std::money_base::space;
371 }
372 else if (format[2] == std::money_base::value) {
373 format[3] = format[2];
374 format[2] = format[1];
375 format[1] = std::money_base::space;
376 }
377 else if (format[0] == std::money_base::symbol) {
378 format[3] = format[2];
379 format[2] = std::money_base::space;
380 }
381 else {
382 format[3] = format[2];
383 format[2] = format[1];
384 format[1] = std::money_base::space;
385 }
386 }
387}
388
389
390void Def::write_monetary (std::string dir_name)
391{
392 assert (!dir_name.empty());
393
394 if (mon_written_)
395 return;
396
397 if (!mon_def_found_) {
398 issue_diag (I_SKIP, false, 0,
399 "%s section not found, skipping\n", lc_name);
400 return;
401 }
402
403 // write out all the information in the LC_MONETARY category
404 (dir_name += _RWSTD_PATH_SEP) += lc_name;
405
406 issue_diag (I_OPENWR, false, 0, "writing %s\n", dir_name.c_str ());
407
408 std::ofstream out (dir_name.c_str(), std::ios::binary);
409 out.exceptions (std::ios::failbit | std::ios::badbit);
410
411 _RW::__rw_punct_t punct;
412
413 // calculate the offsets for the mon_punct structure
414 punct.decimal_point_off [1] = 0;
415
416 punct.thousands_sep_off [1] =
417 unsigned (punct.decimal_point_off [1]
418 + (mon_st_.wmon_decimal_point.size () + 1) * sizeof (wchar_t));
419
420 punct.decimal_point_off [0] =
421 unsigned (punct.thousands_sep_off [1]
422 + (mon_st_.wmon_thousands_sep.size () + 1) * sizeof (wchar_t));
423
424 punct.thousands_sep_off [0] =
425 unsigned (punct.decimal_point_off [0]
426 + mon_st_.mon_decimal_point.size () + 1);
427
428 punct.grouping_off =
429 unsigned (punct.thousands_sep_off [0]
430 + mon_st_.mon_thousands_sep.size () + 1);
431
432 punct.punct_ext_off =
433 unsigned (punct.grouping_off
434 + mon_st_.mon_grouping.size () + 1);
435
436 // compute the alignment requirement of any offset member
437 const std::size_t align = sizeof punct.punct_ext_off;
438
439 // align the offset of the extension struct on the required boundary
440 const std::size_t misalign = punct.punct_ext_off % align;
441
442 // compute the amount of padding between the two structs
443 const std::size_t pad = misalign ? align - misalign : 0;
444
445 punct.punct_ext_off += unsigned (pad);
446
447 mon_out_.curr_symbol_off [1][1] = 0;
448
449 mon_out_.curr_symbol_off [0][1] =
450 unsigned (mon_out_.curr_symbol_off [1][1]
451 + (mon_st_.wint_curr_symbol.size () + 1) * sizeof (wchar_t));
452
453 mon_out_.positive_sign_off [1] =
454 unsigned (mon_out_.curr_symbol_off [0][1]
455 + (mon_st_.wcurrency_symbol.size () + 1) * sizeof (wchar_t));
456
457 mon_out_.negative_sign_off [1] =
458 unsigned (mon_out_.positive_sign_off [1]
459 + (mon_st_.wpositive_sign.size () + 1) * sizeof (wchar_t));
460
461
462 // calculate all the narrow character string offsets
463 mon_out_.curr_symbol_off [1][0] =
464 unsigned (mon_out_.negative_sign_off [1]
465 + (mon_st_.wnegative_sign.size () + 1) * sizeof (wchar_t));
466
467 mon_out_.curr_symbol_off [0][0] =
468 unsigned (mon_out_.curr_symbol_off [1][0]
469 + mon_st_.int_curr_symbol.size () + 1);
470
471 mon_out_.positive_sign_off [0] =
472 unsigned (mon_out_.curr_symbol_off [0][0]
473 + mon_st_.currency_symbol.size() + 1);
474
475 mon_out_.negative_sign_off [0] =
476 unsigned (mon_out_.positive_sign_off [0]
477 + mon_st_.positive_sign.size () + 1);
478
479 mon_out_.codeset_off = unsigned (mon_out_.negative_sign_off [0]
480 + mon_st_.negative_sign.size () + 1);
481
482 mon_out_.charmap_off = unsigned (mon_out_.codeset_off
483 + charmap_.get_code_set_name ().size () + 1);
484
485 issue_diag (I_WRITE, false, 0,
486 "%s layout:\n"
487 "__rw_punct_t {\n"
488 " decimal_point_off[] = { %u, %u }\n"
489 " thousand_sep_off[] = { %u, %u }\n"
490 " grouping_off = %u\n"
491 " ext_off = %u\n"
492 "}\n__rw_moneypunct_t {\n"
493 " curr_symbol_off[][] = { { %u, %u }, { %u, %u } }\n"
494 " positive_sign_off[] = { %u, %u }\n"
495 " negative_sign_off[] = { %u, %u }\n"
496 " codeset_off = %u\n"
497 " charmap_off = %u\n"
498 "}\n",
499 lc_name,
500 punct.decimal_point_off [0],
501 punct.decimal_point_off [1],
502 punct.thousands_sep_off [0],
503 punct.thousands_sep_off [1],
504 punct.grouping_off,
505 punct.punct_ext_off,
506 mon_out_.curr_symbol_off [0][0],
507 mon_out_.curr_symbol_off [0][1],
508 mon_out_.curr_symbol_off [1][0],
509 mon_out_.curr_symbol_off [1][1],
510 mon_out_.positive_sign_off [0],
511 mon_out_.negative_sign_off [1],
512 mon_out_.codeset_off,
513 mon_out_.charmap_off);
514
515 // construct the pos_format and neg_format
516 create_format (mon_out_.pos_format[0], mon_out_.p_sign_posn[0],
517 mon_out_.p_cs_precedes[0], mon_out_.p_sep_by_space[0],
518 true);
519
520 create_format (mon_out_.neg_format[0], mon_out_.n_sign_posn[0],
521 mon_out_.n_cs_precedes[0], mon_out_.n_sep_by_space[0],
522 false);
523
524 create_format (mon_out_.pos_format[1], mon_out_.p_sign_posn[1],
525 mon_out_.p_cs_precedes[1], mon_out_.p_sep_by_space[1],
526 true);
527
528 create_format (mon_out_.neg_format[1], mon_out_.n_sign_posn[1],
529 mon_out_.n_cs_precedes[1], mon_out_.n_sep_by_space[1],
530 false);
531
532 // write out the mon_punct structure
533 out.write ((char*)&punct, sizeof punct);
534
535 // write out the strings in the punct structure
536 out.write ((const char*)mon_st_.wmon_decimal_point.c_str(),
537 (mon_st_.wmon_decimal_point.size() + 1) * sizeof(wchar_t));
538 out.write ((const char*)mon_st_.wmon_thousands_sep.c_str(),
539 (mon_st_.wmon_thousands_sep.size() + 1) * sizeof(wchar_t));
540
541 out << mon_st_.mon_decimal_point << std::ends
542 << mon_st_.mon_thousands_sep << std::ends
543 << mon_st_.mon_grouping << std::ends;
544
545 // pad the structure up to the next alignment boundary
546 out.write ("\0\0\0\0\0\0\0\0", pad);
547
548 // now write out the monetary offset extension struct
549 out.write ((char*)&mon_out_, sizeof (mon_out_));
550
551 // write the wide character strings
552 out.write ((const char*)mon_st_.wint_curr_symbol.c_str(),
553 (mon_st_.wint_curr_symbol.size() + 1) * sizeof(wchar_t));
554 out.write ((const char*)mon_st_.wcurrency_symbol.c_str(),
555 (mon_st_.wcurrency_symbol.size() + 1) * sizeof(wchar_t));
556 out.write ((const char*)mon_st_.wpositive_sign.c_str(),
557 (mon_st_.wpositive_sign.size() + 1) * sizeof(wchar_t));
558 out.write ((const char*)mon_st_.wnegative_sign.c_str(),
559 (mon_st_.wnegative_sign.size() + 1) * sizeof(wchar_t));
560
561 // write the narrow character strings
562 out << mon_st_.int_curr_symbol << std::ends
563 << mon_st_.currency_symbol << std::ends
564 << mon_st_.positive_sign << std::ends
565 << mon_st_.negative_sign << std::ends
566 << charmap_.get_code_set_name() << std::ends
567 << charmap_.get_charmap_name() << std::ends;
568}
const char punct[]
#define val
Definition 17.names.cpp:570
const int end
const int out
#define assert(expr)
Definition _cassert.h:40
#define _RWSTD_PATH_SEP
Definition _config.h:297
const std::string & get_code_set_name() const
Definition charmap.h:112
std::string get_charmap_name() const
Definition charmap.cpp:475
void write_monetary(std::string dir_name)
Definition monetary.cpp:390
bool warnings_occurred_
Definition def.h:90
void open(std::string, char='#', char='\\')
Definition scanner.cpp:142
void close()
Definition scanner.cpp:169
token_t next_token()
Definition scanner.cpp:352
@ tok_mon_thousands_sep
Definition scanner.h:112
@ tok_int_n_sign_posn
Definition scanner.h:129
@ tok_int_frac_digits
Definition scanner.h:116
@ tok_end
Definition scanner.h:66
@ tok_int_p_sep_by_space
Definition scanner.h:126
@ tok_int_n_sep_by_space
Definition scanner.h:127
@ tok_n_sep_by_space
Definition scanner.h:121
@ tok_n_cs_precedes
Definition scanner.h:120
@ tok_p_sep_by_space
Definition scanner.h:119
@ tok_negative_sign
Definition scanner.h:115
@ tok_int_n_cs_precedes
Definition scanner.h:125
@ tok_string
Definition scanner.h:99
@ tok_frac_digits
Definition scanner.h:117
@ tok_p_sign_posn
Definition scanner.h:122
@ tok_positive_sign
Definition scanner.h:114
@ tok_mon_grouping
Definition scanner.h:113
@ tok_monetary
Definition scanner.h:55
@ tok_currency_symbol
Definition scanner.h:110
@ tok_copy
Definition scanner.h:166
@ tok_int_curr_symbol
Definition scanner.h:109
@ tok_nl
Definition scanner.h:168
@ tok_n_sign_posn
Definition scanner.h:123
@ tok_int_p_sign_posn
Definition scanner.h:128
@ tok_ident
Definition scanner.h:60
@ tok_mon_decimal_point
Definition scanner.h:111
@ tok_p_cs_precedes
Definition scanner.h:118
@ tok_int_p_cs_precedes
Definition scanner.h:124
std::string strip_quotes(const std::string &str)
Definition def.h:604
bool issue_diag(int type, bool, const Scanner::token_t *token, const char *fmt,...)
@ I_OPENWR
Definition diagnostic.h:83
@ I_WRITE
Definition diagnostic.h:85
@ W_INVAL
Definition diagnostic.h:74
@ E_INVAL
Definition diagnostic.h:52
@ I_SKIP
Definition diagnostic.h:86
@ I_STAGE
Definition diagnostic.h:81
@ E_SYNTAX
Definition diagnostic.h:49
#define CHAR_MAX
Definition limits.h:44
std::string get_pathname(const std::string &fname, const std::string &other)
Definition path.cpp:129
unsigned char UChar
Definition collate.cpp:122
std::string name
Definition scanner.h:178
token_id token
Definition scanner.h:179
const char * file
Definition scanner.h:186