Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
def.cpp
Go to the documentation of this file.
1
29// #ifndef _RWSTD_NO_PURE_C_HEADERS
30// # define _RWSTD_NO_PURE_C_HEADERS
31// #endif // _RWSTD_NO_PURE_C_HEADERS
32
33// #ifndef _RWSTD_NO_DEPRECATED_C_HEADERS
34// # define _RWSTD_NO_DEPRECATED_C_HEADERS
35// #endif // _RWSTD_NO_DEPRECATED_C_HEADERS
36
37#ifdef __DECCXX
38# undef __PURE_CNAME
39#endif // __DECCXX
40
41#include <algorithm>
42#include <fstream>
43#include <iostream>
44#include <locale>
45#include <map>
46#include <string>
47#include <vector>
48
49#include <cassert>
50#include <cctype>
51#include <cerrno>
52#include <climits>
53#include <clocale>
54#include <cstdio>
55#include <cstdlib>
56#include <cstring> // for memset()
57
58#include "aliases.h"
59#include "def.h"
60#include "diagnostic.h"
61#include "loc_exception.h"
62#include "path.h"
63
64
65#define UTF8_MAX_SIZE 6
66
67
68// convert_to_ext converts a wchar_t value with some encoding into
69// a narrow character string in the current locale's encoding
70std::string Def::convert_to_ext (wchar_t val)
71{
72 rmb_cmap_iter it;
73 if ((it = charmap_.get_rmb_cmap().find(val))
74 != charmap_.get_rmb_cmap().end()){
75 return it->second;
76
77 }
78
79 issue_diag (E_CVT2EXT, true, 0,
80 "unable to convert character %d to external "
81 "representation\n", val);
82
83 return std::string("");
84}
85
86
87// convert the wchar_t value into a utf8 string
88std::string Def::utf8_encode (wchar_t wc)
89{
90 unsigned int wc_int = _RWSTD_STATIC_CAST (unsigned int, wc);
91
92 std::string ret;
93 std::size_t size = 0;
94 char buf[UTF8_MAX_SIZE + 1];
95 char* bufp = buf;
96
97 if (wc_int < 0x80)
98 {
99 size = 1;
100 *bufp++ = wc_int;
101 }
102 else
103 {
104 int b;
105
106 for (b = 2; b < UTF8_MAX_SIZE; b++)
107 if ((wc_int & (~(wchar_t)0 << (5 * b + 1))) == 0)
108 break;
109 size = b;
110
111 *bufp = (unsigned char) (~0xff >> b);
112 --b;
113 do
114 {
115 bufp[b] = 0x80 | (wc_int & 0x3f);
116 wc_int >>= 6;
117 }
118 while (--b > 0);
119 *bufp |= wc_int;
120 }
121 buf[size] = (char)0;
122 for (unsigned int i = 0; i < size; i++)
123 ret += buf[i];
124 return ret;
125
126}
127
128void Def::copy_file (const std::string& name, const std::string& outname)
129{
130 assert (name.size() > 0);
131 assert (outname.size() > 0);
132
133 std::ifstream from (name.c_str(), std::ios::binary);
134 if (!from) {
135 issue_diag (E_OPENRD, true,
136 &next, "unable to open locale database %s\n",
137 name.c_str());
138 }
139 from.exceptions (std::ios::badbit);
140
141 std::ofstream to (outname.c_str(), std::ios::binary);
142 if (!to) {
143 issue_diag (E_OPENWR, true,
144 &next, "unable to create locale database %s\n",
145 outname.c_str());
146 }
147 to.exceptions (std::ios::failbit | std::ios::badbit);
148
149 // copy the file
150 to << from.rdbuf ();
151}
152
153
154void Def::copy_category(int category, std::string name)
155{
156 assert (name.size() > 0);
157
158 // create the name of the file to copy to and call copy_file
159 std::string outname (output_name_);
160
161 makedir (outname.c_str ());
162
163 switch (category) {
164 // append the category name to both 'name' and 'outname'
165 // and call the copy_file routine
166 // the xxx_written variable is set to true so that write_xxx
167 // does not overwrite the file that is written here
168 case LC_CTYPE:
169 (name += _RWSTD_PATH_SEP) += "LC_CTYPE";
170 (outname += _RWSTD_PATH_SEP) += "LC_CTYPE";
171 copy_file (name, outname);
172 ctype_written_ = true;
173
174 break;
175 case LC_COLLATE:
176 (name += _RWSTD_PATH_SEP) += "LC_COLLATE";
177 (outname += _RWSTD_PATH_SEP) += "LC_COLLATE";
178 copy_file(name, outname);
179 collate_written_ = true;
180
181 break;
182 case LC_MONETARY:
183 (name += _RWSTD_PATH_SEP) += "LC_MONETARY";
184 (outname += _RWSTD_PATH_SEP) += "LC_MONETARY";
185 copy_file(name, outname);
186 mon_written_ = true;
187
188 break;
189
190 case LC_NUMERIC:
191 (name += _RWSTD_PATH_SEP) += "LC_NUMERIC";
192 (outname += _RWSTD_PATH_SEP) += "LC_NUMERIC";
193 copy_file(name, outname);
194 num_written_ = true;
195
196 break;
197 case LC_TIME:
198 (name += _RWSTD_PATH_SEP) += "LC_TIME";
199 (outname += _RWSTD_PATH_SEP) += "LC_TIME";
200 copy_file(name, outname);
201 time_written_ = true;
202
203 break;
204
205#ifdef LC_MESSAGES
206 case LC_MESSAGES:
207 (name += _RWSTD_PATH_SEP) += "LC_MESSAGES";
208 (outname += _RWSTD_PATH_SEP) += "LC_MESSAGES";
209 copy_file(name, outname);
210 messages_written_ = true;
211 break;
212#endif // LC_MESSAGES
213
214 default:
215 break;
216 }
217}
218
219
220// strip a pair, which should be in the form '(<sym>,<sym2>)'
221void Def::strip_pair (const std::string &tok, std::string &sym,
222 std::string &sym2)
223{
224 std::size_t i = 0;
225
226 if(tok[i] == '(') {
227 if(tok[++i] == '<')
228 while (tok[i] != '>'){
229 if (tok[i] == scanner_.escape_char ())
230 i++;
231 sym.push_back(tok[i++]);
232 }
233 // this push_back is safe because the while loop above ends when
234 // tok[i] == '>'
235 sym.push_back(tok[i++]);
236 if (tok[i++] != ',')
237 issue_diag (E_PAIR, true, &next,
238 "invalid pair %s\n", tok.c_str());
239 if (tok[i] == '<')
240 while (tok[i] != '>'){
241 if (tok[i] == scanner_.escape_char ())
242 sym2.push_back(tok[i++]);
243 if ('\0' != tok[i])
244 sym2.push_back(tok[i++]);
245 else
246 issue_diag (E_PAIR, true, &next,
247 "invalid pair %s\n", tok.c_str());
248 }
249
250 // this push_back is safe because the while loop above ends when
251 // tok[i] == '>'
252 sym2.push_back(tok[i++]);
253
254 }
255}
256
257// converts str, which is a string in the following format
258// "[<sym_name>][char]" including the quotes to a string of characters
259// str is not a const reference because if the string spans multiple lines
260// str is modified
261std::string Def::convert_string (const std::string &str1)
262{
263 assert (str1[0] == '\"');
264
265 std::string ret;
266
267 std::string sym;
268 // the index starts at 1 so that we ignore the initial '"'
269 int idx = 1;
270
271 const char* str = str1.c_str();
272 while (str[idx] != '\"') {
273 sym.clear();
274 // if we reach the null-terminator before we see an end-quote
275 // then we must have a multi-line string, so get the next token
276 if (str[idx] == '\0') {
277 if((next = scanner_.next_token()).token == Scanner::tok_string)
278 break;
279 str = next.name.c_str();
280 idx = 0;
281 }
282
283 // '<' marks the beginning of a symbolic name
284 // construct the name and look up its value in the cmap
285 if (str[idx] == '<') {
286 while (str [idx] && str [idx] != '>') {
287 if (str[idx] == scanner_.escape_char ())
288 idx++;
289 sym += str[idx++];
290 }
291
292 // this is safe because the while loop ended with *str == '>'
293 if (str [idx])
294 sym += str [idx++];
295
296 w_cmap_iter w_pos = charmap_.get_w_cmap().find (sym);
297 if (w_pos != charmap_.get_w_cmap().end()) {
298 ret += convert_to_ext(w_pos->second);
299 }
300 else {
301 return std::string();
302 }
303 }
304
305 // the definition file contains a sting with non-symbol names.
306 // process each character as it's actual character value.
307 // Locale definitions that use this may not be portable.
308 else {
309 ret += (char)str[idx++];
310
311 }
312 }
313
314 return ret;
315
316
317}
318
319#ifndef _RWSTD_NO_WCHAR_T
320// converts a collating element definition to an array of wide characters
321// (the wide characters the collating element is composed of).
322
323// this overload deals with collating elements defined through
324// a sequence of symbolic names, NOT enclosed within quotes.
325std::wstring
326Def::convert_wstring (const StringVector& sym_array)
327{
328 std::wstring ret;
329 StringVector::const_iterator it = sym_array.begin ();
330 while (it != sym_array.end ()) {
331 // lookup the symbol we just constructed
332 w_cmap_iter w_pos = charmap_.get_w_cmap().find (*it);
333 if (w_pos != charmap_.get_w_cmap().end()) {
334 ret += w_pos->second;
335 it++;
336 }
337 else {
338 // we return an empty string if we couldn't find any character
339 // in the character map
340 ret.clear();
341 return ret;
342 }
343 }
344
345 return ret;
346}
347
348// this overload deals with collating elements defined through
349// a sequence of characters or symbolic names, enclosed within quotes.
350std::wstring
351Def::convert_wstring (const token_t& t)
352{
353 std::wstring ret;
354 std::string sym;
355
356 std::string str1 (t.name);
357
358 int idx = 0;
359 char term = 0;
360 const char* str = str1.c_str();
361
362 // skip first character if quote
363 if (str[idx] == '\"') {
364 term = '\"', idx++;
365 }
366
367 while (str[idx] != term) {
368 sym.clear();
369
370 // '<' marks the beginning of a symbolic name
371 // construct the name and look up its value in the cmap
372 if (str[idx] == '<') {
373 while (str[idx] != '>') {
374 if (str[idx] == scanner_.escape_char ()) {
375 // sym += str[idx++];
376 idx++;
377 }
378
379 if ('\0' != str[idx])
380 sym += str[idx++];
381 else
382 issue_diag (E_SYMEND, true, &t,
383 "end of symbolic name not found\n");
384 }
385
386 // this is safe because the while loop ended with *str == '>'
387 sym += str[idx++];
388
389 // lookup the symbol we just constructed
390 w_cmap_iter w_pos = charmap_.get_w_cmap().find (sym);
391 if (w_pos != charmap_.get_w_cmap().end()) {
392 ret += w_pos->second;
393 }
394 else {
395 // if we can't find a symbol then return an empty string,
396 // most likely this will happen if inside a collating-element
397 // the user uses a character that is not in the current
398 // codeset, in this case the collating element will be ignored
399 ret.clear();
400 return ret;
401 }
402 }
403 // the definition file contains a string with non-symbol names.
404 // process each character as it's actual character value.
405 // Locale definitions that use this may not be portable.
406 else
407 ret += (wchar_t)str[idx++];
408 }
409
410 return ret;
411
412}
413
414#endif // _RWSTD_NO_WCHAR_T
415
416
417// automatically fill any categories that depend on other categories
418void Def::auto_fill ()
419{
420
421 mask_iter mask_pos;
422
423 for (std::size_t i = 0; i <= UCHAR_MAX; i++) {
424 if ( ctype_out_.mask_tab[i] & std::ctype_base::upper
425 || ctype_out_.mask_tab[i] & std::ctype_base::lower
426 || ctype_out_.mask_tab[i] & std::ctype_base::alpha
427 || ctype_out_.mask_tab[i] & std::ctype_base::digit
428 || ctype_out_.mask_tab[i] & std::ctype_base::xdigit
429 || ctype_out_.mask_tab[i] & std::ctype_base::punct)
430
431 ctype_out_.mask_tab[i] |= std::ctype_base::print;
432
433 if ( ctype_out_.mask_tab[i] & std::ctype_base::upper
434 || ctype_out_.mask_tab[i] & std::ctype_base::lower)
435
436 ctype_out_.mask_tab[i] |= std::ctype_base::alpha;
437
438 if ( ctype_out_.mask_tab[i] & std::ctype_base::upper
439 || ctype_out_.mask_tab[i] & std::ctype_base::lower
440 || ctype_out_.mask_tab[i] & std::ctype_base::alpha
441 || ctype_out_.mask_tab[i] & std::ctype_base::digit
442 || ctype_out_.mask_tab[i] & std::ctype_base::xdigit
443 || ctype_out_.mask_tab[i] & std::ctype_base::punct)
444
445 ctype_out_.mask_tab[i] |= std::ctype_base::graph;
446 }
447
448 for (mask_pos = mask_.begin(); mask_pos != mask_.end(); mask_pos++) {
449 // all lower, alpha, digit, xdigit, and punct, and space
450 // characters are automatically print
451
452 if ( mask_pos->second & std::ctype_base::upper
453 || mask_pos->second & std::ctype_base::lower
454 || mask_pos->second & std::ctype_base::alpha
455 || mask_pos->second & std::ctype_base::digit
456 || mask_pos->second & std::ctype_base::xdigit
457 || mask_pos->second & std::ctype_base::punct)
458 // || mask_pos->second & std::ctype_base::space)
459
460 mask_pos->second |= std::ctype_base::print;
461
462 // all upper and lower characters are alpha
463 if ( mask_pos->second & std::ctype_base::upper
464 || mask_pos->second & std::ctype_base::lower)
465
466 mask_pos->second |= std::ctype_base::alpha;
467
468 // all upper, lower, alpha, digit, xdigit, and punct characters
469 // are graph characters
470 if ( mask_pos->second & std::ctype_base::upper
471 || mask_pos->second & std::ctype_base::lower
472 || mask_pos->second & std::ctype_base::alpha
473 || mask_pos->second & std::ctype_base::digit
474 || mask_pos->second & std::ctype_base::xdigit
475 || mask_pos->second & std::ctype_base::punct)
476
477 mask_pos->second |= std::ctype_base::graph;
478
479
480 }
481}
482
483
485{
486 while ((next = scanner_.next_token ()).token != Scanner::tok_end_tokens) {
487
488 switch (next.token) {
489
491 scanner_.ignore_line ();
492 break;
493
495 process_ctype ();
496 break;
497
499 process_collate ();
500 break;
501
503 process_monetary ();
504 break;
505
507 process_numeric ();
508 break;
509
511 process_time ();
512 break;
513
515 process_messages ();
516 break;
517
518 case Scanner::tok_nl:
519 break;
520
521 default:
522 scanner_.ignore_line ();
523 break;
524 }
525 }
526
527 auto_fill ();
528}
529
530
531Def::Def (const char* filename, const char* out_name, Charmap& char_map,
532 bool no_position)
533 : warnings_occurred_ (false),
534 scan_ahead_ (false),
535 next_offset_ (0),
536 output_name_ (out_name),
537 charmap_ (char_map),
538 ctype_written_ (false),
539 codecvt_written_ (false),
540 collate_written_ (false),
541 time_written_ (false),
542 num_written_ (false),
543 mon_written_ (false),
544 messages_written_ (false),
545 ctype_def_found_ (false),
546 collate_def_found_ (false),
547 time_def_found_ (false),
548 num_def_found_ (false),
549 mon_def_found_ (false),
550 messages_def_found_ (false),
551 undefined_keyword_found_ (false),
552 no_position_ (no_position)
553
554{
555 // make sure ctype_out object is cleared
556 std::memset (&ctype_out_, 0, sizeof (ctype_out_));
557 std::memset (&time_out_, 0, sizeof (time_out_));
558
559 // invalidate format characters by setting each to CHAR_MAX
560 // as specified by the C function localeconv()
561 mon_out_.frac_digits [0] = CHAR_MAX;
562 mon_out_.frac_digits [1] = CHAR_MAX;
563 mon_out_.p_cs_precedes [0] = CHAR_MAX;
564 mon_out_.p_sep_by_space [0] = CHAR_MAX;
565 mon_out_.n_cs_precedes [0] = CHAR_MAX;
566 mon_out_.n_sep_by_space [0] = CHAR_MAX;
567 mon_out_.p_sign_posn [0] = CHAR_MAX;
568 mon_out_.n_sign_posn [0] = CHAR_MAX;
569
570 mon_st_.mon_grouping += CHAR_MAX;
571
572 // invalidate int'l formats
573 mon_out_.p_cs_precedes [1] = CHAR_MAX;
574 mon_out_.p_sep_by_space [1] = CHAR_MAX;
575 mon_out_.n_cs_precedes [1] = CHAR_MAX;
576 mon_out_.n_sep_by_space [1] = CHAR_MAX;
577 mon_out_.p_sign_posn [1] = CHAR_MAX;
578 mon_out_.n_sign_posn [1] = CHAR_MAX;
579
580 num_st_.grouping += CHAR_MAX;
581
582 collate_out_.largest_ce = 1;
583 collate_out_.longest_weight = 1;
584 collate_out_.num_wchars = 0;
585 std::memset (collate_out_.weight_type, 0,
586 sizeof (collate_out_.weight_type));
587
588 // initialize all extensions to 0
589 ctype_out_.ctype_ext_off = 0;
590 num_out_.numeric_ext_off = 0;
591 collate_out_.collate_ext_off = 0;
592 mon_out_.monetary_ext_off = 0;
593 time_out_.time_ext_off = 0;
594
595 // actual processing
596 scanner_.open (filename);
597}
598
599
601{
602 // free up the memory that was allocated
603
604 coll_map_iter coll_map_pos;
605 for (coll_map_pos = coll_map_.begin();
606 coll_map_pos != coll_map_.end(); coll_map_pos ++) {
607 delete[] (coll_map_pos->second.weights);
608 }
609
610}
#define i
Definition 17.names.cpp:126
#define t
Definition 17.names.cpp:136
#define buf
Definition 17.names.cpp:452
#define b
Definition 17.names.cpp:110
#define val
Definition 17.names.cpp:570
#define assert(expr)
Definition _cassert.h:40
#define LC_CTYPE
#define LC_NUMERIC
#define LC_MONETARY
#define LC_TIME
#define LC_COLLATE
unsigned short wchar_t
#define _RWSTD_PATH_SEP
Definition _config.h:297
#define _RWSTD_STATIC_CAST(T, x)
Definition _defs.h:534
std::vector< std::string > StringVector
Definition aliases.h:43
const std::map< wchar_t, std::string > & get_rmb_cmap() const
Definition charmap.h:89
const std::map< std::string, wchar_t > & get_w_cmap() const
Definition charmap.h:71
~Def()
Definition def.cpp:600
Def(const char *filename, const char *out_name, Charmap &charmap, bool no_position)
Definition def.cpp:531
void process_input()
Definition def.cpp:484
void open(std::string, char='#', char='\\')
Definition scanner.cpp:142
char escape_char() const
Definition scanner.cpp:129
void ignore_line()
Definition scanner.cpp:135
token_t next_token()
Definition scanner.cpp:352
@ tok_numeric
Definition scanner.h:56
@ tok_comment
Definition scanner.h:163
@ tok_string
Definition scanner.h:99
@ tok_messages
Definition scanner.h:54
@ tok_collate
Definition scanner.h:52
@ tok_monetary
Definition scanner.h:55
@ tok_ctype
Definition scanner.h:53
@ tok_time
Definition scanner.h:57
@ tok_nl
Definition scanner.h:168
@ tok_end_tokens
Definition scanner.h:170
const char * name
Definition codecvt1.cpp:72
#define UTF8_MAX_SIZE
Definition def.cpp:65
bool issue_diag(int type, bool, const Scanner::token_t *token, const char *fmt,...)
@ E_OPENRD
Definition diagnostic.h:37
@ E_PAIR
Definition diagnostic.h:39
@ E_OPENWR
Definition diagnostic.h:38
@ E_CVT2EXT
Definition diagnostic.h:41
@ E_SYMEND
Definition diagnostic.h:42
const char * str
Definition exec.cpp:170
#define UCHAR_MAX
Definition limits.h:60
#define CHAR_MAX
Definition limits.h:44
int makedir(const char *name)
Definition path.cpp:236
#define LC_MESSAGES
Definition time_put.cpp:60
#define false
Definition stdbool.h:26
std::string name
Definition scanner.h:178
token_id token
Definition scanner.h:179