Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
locale.cpp
Go to the documentation of this file.
1
29#include <rw/_defs.h>
30
31#if defined (__linux__) && !defined (_XOPEN_SOURCE)
32 // on Linux define _XOPEN_SOURCE to get CODESET defined in <langinfo.h>
33# define _XOPEN_SOURCE 500 /* Single UNIX conformance */
34#endif // __linux__
35
36#ifdef _RWSTD_EDG_ECCP
37 // disable error #450-D: the type "long long" is nonstandard
38 // issued for uses of the type in Linux system headers (e.g.,
39 // pthreadtypes.h)
40# pragma diag_suppress 450
41#endif // vanilla EDG eccp demo
42
43#include _RWSTD_SYS_TYPES_H
44
45#if _RWSTD_PATH_SEP == '/'
46# define SLASH "/"
47# define LS_1 "ls -1 "
48#else
49# define SLASH "\\"
50# define LS_1 "dir /B /A:D "
51#endif
52
53#ifndef _WIN32
54# include <sys/mman.h> // for mmap()
55# include <unistd.h> // for close ()
56# ifndef _RWSTD_NO_ICONV
57# include <iconv.h>
58# endif
59# ifndef _RWSTD_NO_NL_LANGINFO
60# include <langinfo.h>
61# endif
62#else
63# include <io.h> // for open()
64# include <windows.h>
65#endif // _WIN32
66
67#include <limits.h> // for INT_MAX, INT_MIN
68#include <sys/stat.h>
69#include <fcntl.h>
70
71#include <locale>
72#include <map> // for map
73#include <vector> // for vector
74#include <iostream> // for cerr, cout
75#include <iomanip>
76#include <fstream> // for fstream
77
78// #include <cerrno>
79#include <clocale>
80#include <cstdio>
81#include <cstdlib>
82#include <cstring>
83#include <cassert>
84
85#include <loc/_localedef.h>
86
87#include "aliases.h"
88#include "charmap.h"
89#include "loc_exception.h"
90#include "memchk.h"
91#include "diagnostic.h"
92
93
95#ifndef LC_MESSAGES
96# ifdef _RWSTD_LC_MESSAGES
97# define LC_MESSAGES _RWSTD_LC_MESSAGES
98# else
99# define LC_MESSAGES -1
100# endif // _RWSTD_LC_MESSAGES
101#endif // LC_MESSAGES
102
103
104// set to true in response to the "-c" command line option requesting
105// locale to print the name of each section before printing out its
106// contents
107static bool print_sect_names = false;
108
109// set to true in response to the "-k" command line option requesting
110// locale to print the name of each keyword before printing out its
111// value
112static bool print_keywords = false;
113
114// set to true in response to the "-h" command line option requesting
115// locale to try to use character names from the original charmap used
116// to create the locale (if possible)
117static bool decode = false;
118
119// set to false in response to the "-l" command line option requesting
120// locale to produce output suitable for processing by the localedef
121// utility
122static bool posix_output = true;
123
124// set to true in response to the "-p" command line option requesting
125// locale to produce output using the symbols from the POSIX Portable
126// Character Set
127static bool use_pcs = false;
128
129static bool is_utf8 = true;
130
131
132static const _RW::__rw_codecvt_t* codecvt_st = 0;
133static const _RW::__rw_collate_t* collate_st = 0;
134static const _RW::__rw_ctype_t* ctype_st = 0;
135static const _RW::__rw_time_t* time_st = 0;
136static const _RW::__rw_num_t* num_st = 0;
137static const _RW::__rw_mon_t* mon_st = 0;
138static const _RW::__rw_punct_t* num_punct_st = 0;
139static const _RW::__rw_punct_t* mon_punct_st = 0;
140static const _RW::__rw_messages_t* messages_st = 0;
141
142
143static const char sect_lc_all[] = "LC_ALL";
144static const char sect_lc_collate[] = "LC_COLLATE";
145static const char sect_lc_ctype[] = "LC_CTYPE";
146static const char sect_lc_messages[] = "LC_MESSAGES";
147static const char sect_lc_monetary[] = "LC_MONETARY";
148static const char sect_lc_numeric[] = "LC_NUMERIC";
149static const char sect_lc_time[] = "LC_TIME";
150
151// length of the largest string you want printed
152#define MAX_LINE_LEN 50
153
154// for convenience
155typedef unsigned char UChar;
156
157
159int validate (const void *addr, std::size_t nbytes)
160{
161 const std::size_t size = memchk (addr, nbytes);
162
163 if (nbytes != size) {
164 if (size)
165 issue_diag (E_INVAL, true, 0,
166 "invalid size at address %p: %u, expected %u\n",
167 addr, size, nbytes);
168 else
169 issue_diag (E_INVAL, true, 0,
170 "invalid address: %p (%u bytes)\n", addr, nbytes);
171
172 return -1;
173 }
174
175 return 0;
176}
177
178
179int validate (const char *str)
180{
181 if (std::size_t (-1) == strchk (str)) {
182
183 const std::size_t first_byte = memchk (str, 1);
184
185 if (1 == first_byte)
186 issue_diag (E_INVAL, true, 0,
187 "invalid string address: %p\n", str);
188 else
189 issue_diag (E_INVAL, true, 0,
190 "invalid string at %p: no terminating NUL\n", str);
191
192 return -1;
193 }
194
195 return 0;
196}
197
198
199// initialize the LC_CTYPE, LC_MONETARY, LC_COLLATE, LC_NUMERIC and LC_TIME
200// structures by finding the locale database and mmaping the file to the
201// structure.
202// Note: if the locale is not found no error msg is printed, instead we
203// silently use the hardcoded 'POSIX' locale
204
205const void*
206init_struct (const std::string &loc_path_root,
207 const char *cat_name, const char *codeset_name)
208{
209 // check to see if the LC_ALL or LC_LANG environment variable
210 // was set, if LC_LANG was not set it defaults to "C"
211 static const char* const all_val = std::getenv ("LC_ALL");
212 static const char* lang_val = std::getenv ("LANG");
213 if (0 == lang_val)
214 lang_val = "C";
215
216 // if LC_ALL is set, use that value for this locale
217 // otherwise, find out what the environment value is for this category
218 // is and if it is not set use the value in LC_LANG
219 const char* env_val = all_val;
220 if (!all_val || '\0' == *all_val) {
221 env_val = cat_name ? std::getenv (cat_name) : "";
222 if (!env_val)
223 env_val = lang_val;
224 }
225
226 // if env_val is POSIX or C then return NULL otherwise
227 // try to map the locale category database into memory
228 if (std::strcmp (env_val, "C") && std::strcmp (env_val, "POSIX")) {
229
230 // construct the path to the locale database file
231 std::string loc_path;
232
233 // if the LC_XXX environment variable contains a slash
234 // it is treated as a pathname (possibly relative to
235 // the current working directory, when the slash is not
236 // the first character), otherwise as a filename residing
237 // under `loc_path_root'
238 const char* const slash = std::strrchr (env_val, _RWSTD_PATH_SEP);
239 if (!slash)
240 loc_path = loc_path_root;
241
242 if (codeset_name) {
243 if (slash)
244 loc_path = std::string (env_val, slash - env_val);
245
246 (loc_path += _RWSTD_PATH_SEP) += codeset_name;
247 }
248 else
249 ((loc_path += env_val) += _RWSTD_PATH_SEP) += cat_name;
250
251 struct stat st;
252 const int fd = open (loc_path.c_str (), O_RDONLY);
253
254 // get the size of the file by using fstat
255 if (fd != -1 && 0 == fstat (fd, &st)) {
256 // map the file to a pointer and if it succeeds
257 // return the pointer, otherwise return 0
258
259#ifndef _WIN32
260 void* const ret = mmap (0, st.st_size, PROT_READ | PROT_WRITE,
261 MAP_PRIVATE, fd, 0);
262 if (MAP_FAILED == ret)
263 return 0;
264
265#else
266 HANDLE file = CreateFile (loc_path.c_str (), GENERIC_READ,
267 FILE_SHARE_READ, 0,
268 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
269 NULL);
270
271 HANDLE mapping = CreateFileMapping (file, 0, PAGE_READONLY,
272 0, 0, 0);
273
274 void* const ret = MapViewOfFile (mapping, FILE_MAP_READ, 0,
275 0, st.st_size);
276
277#endif // _WIN32
278
279 return ret;
280 }
281 }
282
283 return 0;
284}
285
286
287template <class FacetData>
288const FacetData*
289init_section (const std::string &loc_path_root,
290 const char *cat_name, const char *codeset_name,
291 FacetData*)
292{
293 const void* const ptr =
294 init_struct (loc_path_root, cat_name, codeset_name);
295
296 if (ptr && 0 == validate (ptr, sizeof (FacetData)))
297 return static_cast<const FacetData*>(ptr);
298
299 return 0;
300}
301
302
303static void
304init_sections ()
305{
306 std::string loc_path_root;
307
308 // if the locale root environment is not set
309 // use the current directory as the locale root
310 const char* const root = std::getenv ("RWSTD_LOCALE_ROOT");
311
312 loc_path_root = root ? root : ".";
313 loc_path_root += _RWSTD_PATH_SEP;
314
315 // points to the name of the codeset used by all non-empty
316 // locale categories, otherwise 0
317 const char *codeset = 0;
318
319 // points to the name of the LC_XXX environment variable that refers
320 // to the collate category whose codeset is described by codeset;
321 // the value of the variable is used to determine the location of
322 // the codeset conversion database file, e.g., when the environment
323 // variable RWSTD_LOCALE_ROOT is not defined and locale is invoked
324 // like so:
325 // LC_CTYPE=/foo/bar/somelocale locale --charmap
326 const char *section = 0;
327
328 // initialize collate_st
329 collate_st = init_section (loc_path_root, sect_lc_collate, 0,
330 (_RW::__rw_collate_t*)0);
331
332 if (collate_st) {
333 validate (collate_st->codeset_name ());
334
335 codeset = collate_st->codeset_name ();
336 section = sect_lc_collate;
337 }
338
339 // initialize ctype_st
340 ctype_st = init_section (loc_path_root, sect_lc_ctype, 0,
341 (_RW::__rw_ctype_t*)0);
342
343 if (ctype_st) {
344 validate (ctype_st->codeset_name ());
345
346 if (codeset) {
347 if (std::strcmp (codeset, ctype_st->codeset_name ()))
348 codeset = 0;
349 }
350 else {
351 codeset = ctype_st->codeset_name ();
352 section = sect_lc_ctype;
353 }
354 }
355
356 // initialize mon_st
357 mon_punct_st = init_section (loc_path_root, sect_lc_monetary, 0,
358 (_RW::__rw_punct_t*)0);
359
360 if (0 != mon_punct_st) {
361 mon_st = _RWSTD_STATIC_CAST (const _RW::__rw_mon_t*,
362 mon_punct_st->get_ext());
363 validate (mon_st, sizeof *mon_st);
364 }
365
366 if (mon_st) {
367 validate (mon_st->codeset_name ());
368
369 if (codeset) {
370 if (std::strcmp (codeset, mon_st->codeset_name ()))
371 codeset = 0;
372 }
373 else {
374 codeset = mon_st->codeset_name ();
375 section = sect_lc_monetary;
376 }
377 }
378
379 // initialize num_st
380 num_punct_st = init_section (loc_path_root, sect_lc_numeric, 0,
381 (_RW::__rw_punct_t*)0);
382 if (0 != num_punct_st) {
383 num_st = _RWSTD_STATIC_CAST (const _RW::__rw_num_t*,
384 num_punct_st->get_ext());
385 validate (num_st, sizeof *mon_st);
386 }
387
388 if (num_st) {
389 validate (num_st->codeset_name ());
390
391 if (codeset) {
392 if (std::strcmp (codeset, num_st->codeset_name ()))
393 codeset = 0;
394 }
395 else {
396 codeset = num_st->codeset_name ();
397 section = sect_lc_numeric;
398 }
399 }
400
401 // initialize time_st
402 time_st = init_section (loc_path_root, sect_lc_time, 0,
403 (_RW::__rw_time_t*)0);
404 if (time_st) {
405 validate (time_st->codeset_name ());
406
407 if (codeset) {
408 if (std::strcmp (codeset, time_st->codeset_name ()))
409 codeset = 0;
410 }
411 else {
412 codeset = time_st->codeset_name ();
413 section = sect_lc_time;
414 }
415 }
416
417 // initialize messages_st
418 messages_st = init_section (loc_path_root, sect_lc_messages, 0,
419 (_RW::__rw_messages_t*)0);
420
421 if (messages_st) {
422 validate (messages_st->codeset_name ());
423
424 if (codeset) {
425 if (std::strcmp (codeset, messages_st->codeset_name ()))
426 codeset = 0;
427 }
428 else {
429 codeset = messages_st->codeset_name ();
430 section = sect_lc_messages;
431 }
432 }
433
434 if (codeset) {
435 // initialize codecvt_st
436 codecvt_st = init_section (loc_path_root, section, codeset,
437 (_RW::__rw_codecvt_t*)0);
438 }
439}
440
441
442static const char*
443set_locale (int lc_cat, const char *locname, const std::string &charmap_name)
444{
445#ifndef _WIN32
446
447 assert (0 != locname);
448
449 locname = std::setlocale (lc_cat, locname);
450
451 if (locname)
452 return locname;
453
454 std::string encoding (charmap_name.substr (0, charmap_name.rfind ('.')));
455
456 std::vector<std::string> aliases;
457 get_cname_aliases (encoding, aliases);
458
459 std::vector<std::string>::iterator pos;
460
461 for (pos = aliases.begin(); !is_utf8 && pos != aliases.end(); pos++)
462 if (*pos == "utf8")
463 is_utf8 = true;
464
465 const char* names = get_installed_locales ();
466
467 for (; *names; names += std::strlen (names) + 1) {
468
469 if (0 != std::setlocale (LC_CTYPE, names)) {
470
471 const char* const codeset = nl_langinfo (CODESET);
472
473 for (pos = aliases.begin (); pos != aliases.end (); ++pos)
474 if (codeset == *pos)
475 return names;
476 }
477 }
478
479#endif // _WIN32
480
481 return 0;
482}
483
484
485
487static const Charmap*
488get_charmap (int lc_cat)
489{
490 if (!decode)
491 return 0;
492
493 static const char* const lang = std::getenv ("LANG");
494 static const char* const lc_all = std::getenv (sect_lc_all);
495 static const char* const lc_collate = std::getenv (sect_lc_collate);
496 static const char* const lc_ctype = std::getenv (sect_lc_ctype);
497 static const char* const lc_messages = std::getenv (sect_lc_messages);
498 static const char* const lc_monetary = std::getenv (sect_lc_monetary);
499 static const char* const lc_numeric = std::getenv (sect_lc_numeric);
500 static const char* const lc_time = std::getenv (sect_lc_time);
501
502 static const Charmap* cmaps [6];
503 static bool cmaps_tried [sizeof cmaps / sizeof *cmaps];
504
505 const char* charmap = 0;
506 const char* locale = 0;
507
508 const Charmap** cmap = 0;
509
510 switch (lc_cat) {
511
512 case LC_COLLATE:
513 charmap = collate_st ? collate_st->charmap_name () : "";
514 locale = lc_collate;
515 cmap = cmaps + 0;
516 break;
517
518 case LC_CTYPE:
519 charmap = ctype_st ? ctype_st->charmap_name () : "";
520 locale = lc_ctype;
521 cmap = cmaps + 1;
522 break;
523
524 case LC_MESSAGES:
525 charmap = messages_st ? messages_st->charmap_name () : "";
526 locale = lc_messages;
527 cmap = cmaps + 2;
528 break;
529
530 case LC_MONETARY:
531 charmap = mon_st ? mon_st->charmap_name () : "";
532 locale = lc_monetary;
533 cmap = cmaps + 3;
534 break;
535
536 case LC_NUMERIC:
537 charmap = num_st ? num_st->charmap_name () : "";
538 locale = lc_numeric;
539 cmap = cmaps + 4;
540 break;
541
542 case LC_TIME:
543 charmap = time_st ? time_st->charmap_name () : "";
544 locale = lc_time;
545 cmap = cmaps + 5;
546 break;
547
548 default: assert (!"bad LC_XXX constant");
549 }
550
551 assert (0 != cmap);
552 assert (0 != charmap);
553
554 if (*cmap && (*cmap)->get_charmap_name () == charmap)
555 return *cmap;
556
557 if (cmaps_tried [cmap - cmaps])
558 return *cmap;
559
560 cmaps_tried [cmap - cmaps] = true;
561
562 // LC_ALL overrides any other LC_XXX setting
563 if (lc_all && *lc_all)
564 locale = lc_all;
565
566 // when neither LC_ALL or LC_XX is specified fall back on LANG
567 if (0 == locale)
568 locale = lang ? lang : "POSIX";
569
570 set_locale (lc_cat, locale, charmap);
571
572 // look for the charmap directory
573 static const char* const src_root = std::getenv ("RWSTD_SRC_ROOT");
574
575 if (0 == src_root) {
576 static int warning_issued = 0;
577 if (0 == warning_issued++)
578 issue_diag (W_CHARMAP, false, 0, "RWSTD_SRC_ROOT not set\n");
579 }
580 else if ('\0' == *charmap) {
581 static int warning_issued = 0;
582 if (0 == warning_issued++)
583 issue_diag (W_CHARMAP, false, 0, "no charmap name\n");
584 }
585 else {
586 std::string charmap_path = src_root;
587
588 charmap_path += _RWSTD_PATH_SEP;
589 charmap_path += "charmaps";
590 charmap_path += _RWSTD_PATH_SEP;
591 charmap_path += charmap;
592
593 // search for a C library locale that uses the same encoding
594 std::string std_encoding (charmap);
595
596# if !defined (_WIN32)
597 std::string C_locale (get_C_encoding_locale (std_encoding));
598# else
599 std::string C_locale ("");
600# endif
601
602 *cmap = new Charmap (C_locale.c_str (), charmap_path.c_str(),
603 0 == std::strcmp ("utf8.cm", charmap),
604 false, true, false);
605 }
606
607 return cmap ? *cmap : 0;
608}
609
610
611static std::string
612escape_value (unsigned val, bool always = false)
613{
614 // set of printable ASCII characters
615 static const char printable [] = {
616 // ................
617 // 0123456789abcdef
618 /* 0. */ " "
619 /* 1. */ " "
620 /* 2. */ " ! #$%''()*+,-./"
621 /* 3. */ "0123456789: <=>?"
622 /* 4. */ "@ABCDEFGHIJKLMNO"
623 /* 5. */ "PQRSTUVWXYZ[ ]^_"
624 /* 6. */ "`abcdefghijklmno"
625 /* 7. */ "pqrstuvwxyz{|}~ "
626 };
627
628 static const char hexdigit[] = "0123456789abcdef";
629
630 std::string ret;
631
632 if ( (UChar (';') == val || UChar ('"') == val || UChar ('\\') == val)
633 && !always) {
634 ret += '\\';
635 ret += char (val);
636 }
637 else if ( use_pcs && val <= UChar ('~')
639 // use symbols from the Portable Character Set
641 }
642 else if (val < sizeof printable - 1 && ' ' != printable [val] && !always) {
643 // represent non-space printable characters as themselves
644 ret += printable [val];
645 }
646 else if (UChar (' ') == val && !always) {
647 // represent space as itself unless always escaping
648 ret += ' ';
649 }
650 else {
651 // non-printable character or escaping requested
652
653 char buf [40];
654 char *pbuf = buf;
655
656 if (0xffU < val)
657 *pbuf++ = '"';
658
659 const unsigned mask = 0xffU << (sizeof mask - 1) * 8;
660
661 while (val && 0 == (val & mask))
662 val <<= 8;
663
664 do {
665 *pbuf++ = '\\';
666 *pbuf++ = 'x';
667 *pbuf++ = hexdigit [val >> (sizeof val * 8 - 4)];
668 val <<= 4;
669 *pbuf++ = hexdigit [val >> (sizeof val * 8 - 4)];
670 } while (val <<= 4);
671
672 if ('"' == *buf)
673 *pbuf++ = '"';
674
675 *pbuf = '\0';
676
677 ret = buf;
678 }
679
680 return ret;
681}
682
683
684static std::string
685create_str (const char* str, const wchar_t* wstr, const Charmap *charmap)
686{
687 if (0 == str)
688 str = "";
689
690 std::string ret;
691
692 if (0 == charmap) {
693
694 // when no character map is provided format non-printable
695 // characters using escape sequences
696 for (; *str; ++str)
697 ret += escape_value (UChar (*str));
698
699 return ret;
700 }
701
702 typedef std::map <UChar, std::string>::const_iterator rn_cmap_iter;
703 typedef std::map <wchar_t, std::string>::const_iterator rw_cmap_iter;
704
705 if (0 == ctype_st || 1 == ctype_st->mb_cur_max) {
706 // look up each character in the character map and (try
707 // to) get the symbolic name associated with each, falling
708 // back on ordinary formatting using escape sequences when
709 // the character is not found in the map
710
711 const rn_cmap_iter end = charmap->get_rn_cmap ().end ();
712
713 for (; *str != '\0'; ++str) {
714 const UChar uc = UChar (*str);
715 const rn_cmap_iter it = charmap->get_rn_cmap ().find (uc);
716
717 ret += (it == end) ? escape_value (uc) : it->second;
718 }
719 }
720 else {
721 const rw_cmap_iter end = charmap->get_rw_cmap ().end ();
722
723 if (0 == wstr)
724 wstr = L"";
725
726 for ( ; *wstr != '\0'; ++wstr) {
727
728 const unsigned uc = unsigned (*wstr);
729
730 const rw_cmap_iter it = charmap->get_rw_cmap ().find (uc);
731
732 ret += (it == end) ? escape_value (uc) : it->second;
733 }
734 }
735
736 return ret;
737}
738
739
740// formats a character in human readable form
741static std::string
742create_str (unsigned ch, const Charmap *charmap)
743{
744 typedef std::map <wchar_t, std::string>::const_iterator rw_cmap_iter;
745
746 std::string ret;
747
748 if (charmap) {
749 // look up character in the reverse wide character map
750 const rw_cmap_iter ch_pos = charmap->get_rw_cmap ().find (ch);
751
752 if (ch_pos == charmap->get_rw_cmap ().end ()) {
753 // issue a warning when not found and format it below
754 issue_diag (W_CHAR, true, 0, "wide character L'\\%x' "
755 "not found in character map\n", ch);
756 }
757 else
758 return ch_pos->second;
759 }
760
761 return escape_value (ch);
762}
763
764
765static void
766print_section (const char* name, bool end = false)
767{
768 assert (0 != name);
769
770 if (print_sect_names)
771 std::cout << (end ? "END " : "") << name << '\n';
772}
773
774
775static void
776print_keyword (const char* str)
777{
778 assert (0 != str);
779
780 if (print_keywords)
781 std::cout << str << (posix_output ? '=' : ' ');
782}
783
784
786// place holder for function that prints the "C" locale LC_COLLATE category
787static void
788print_c_lc_collate ()
789{
790 assert (0);
791}
792
793
795static wchar_t
796get_wchar_from_offset(unsigned int offset,
797 const unsigned int* wchar_map,
798 unsigned int num_wchars) {
799 unsigned int beg = 0;
800 unsigned int end = num_wchars;
801 while (beg <= end) {
802 unsigned int cur = (beg + end) / 2;
803 if (*(wchar_map + cur * 2 + 1) == offset) {
804 return *(const wchar_t*)(wchar_map + cur * 2);
805 }
806 else if (*(wchar_map + cur *2) > offset)
807 end = cur - 1;
808 else
809 beg = cur + 1;
810 }
811 return 0;
812}
813
814
815static void
816print_weight (const unsigned int* weightp,
817 unsigned int num_weights,
818 unsigned int longest_weight)
819{
820 // FIXME: ignore the order of the element
821 ++weightp;
822
823 for (unsigned k = 0; k != num_weights; ++k) {
824
825 for (unsigned x = 0; x != longest_weight; ++x, ++weightp) {
826
827 if (*weightp != UINT_MAX) {
828 if (0 == *weightp)
829 std::cout << "IGNORE;";
830 else
831 std::cout << escape_value (*weightp, true) << ';';
832 }
833 }
834 }
835
836 std::cout << '\n';
837}
838
839
840static void
841write_coll_info (const std::string &ch, unsigned int idx,
842 unsigned int tab_num)
843{
844 if (collate_st->num_elms > 1) {
845 const Charmap* const cmap = get_charmap (LC_COLLATE);
846
847 typedef std::map <std::string, wchar_t>::const_iterator n_cmap2_iter;
848 const unsigned int* tab = collate_st->get_n_tab (tab_num);
849 unsigned int first = collate_st->get_first_char_in_n_tab(tab_num);
850 for (unsigned int i = first; i <= UCHAR_MAX; i++) {
851 std::string new_ch = ch;
852 new_ch += UChar (i);
853 if (tab[i - first] != UINT_MAX) {
854 if (tab[i - first] & 0x80000000) {
855 // it's an offset to another table
856 write_coll_info (new_ch, idx + 1,
857 tab[i - first] &~ 0x80000000);
858 }
859 else {
860 // we found the offset to the weight
861 if (cmap) {
862 // first we need to print the symbolic name
863 n_cmap2_iter n_cmap2_it =
864 cmap->get_mb_cmap().find(new_ch);
865 if (n_cmap2_it != cmap->get_mb_cmap().end())
866 std::cout << cmap->get_rw_cmap().find(
867 n_cmap2_it->second)->second;
868 }
869 else {
870 for (unsigned int j = 0; j < idx; j++) {
871 const UChar uc = UChar (new_ch [j]);
872
873 std::cout << "\\d" << int (uc);
874
875 if (j != idx - 1)
876 std::cout << ';';
877 }
878 }
879 std::cout << " ";
880 print_weight (collate_st->get_weight (tab[i - first]),
881 collate_st->num_weights,
882 collate_st->longest_weight);
883
884 }
885 }
886 }
887 }
888}
889
890
891static void
892print_ce_info (unsigned tab_num,
893 const std::string &mb_str,
894 std::map<std::string, unsigned int> &ce_map)
895{
896 static unsigned ce_num = 0;
897
898 const unsigned* const tab = collate_st->get_n_ce_tab (tab_num);
899
900 const unsigned first = collate_st->get_first_char_in_n_ce_tab (tab_num);
901 const unsigned last = collate_st->get_last_char_in_n_ce_tab (tab_num);
902
903 std::string mbchar;
904
905 const Charmap* const cmap = get_charmap (LC_COLLATE);
906
907 for (unsigned i = first; i <= last; ++i) {
908
909 mbchar = mb_str;
910 mbchar += UChar (i);
911
912 const unsigned elem = tab [i - first];
913
914 if (elem != UINT_MAX) {
915
916 if (elem & 0x80000000) {
917 // it's an offset to another table. recursively call
918 // print_ce_info with the new table number.
919
920 print_ce_info (elem &~ 0x80000000, mbchar, ce_map);
921 }
922 else {
923 // we found the end of the collating element
924 // now we need to do a lookup in the narrow character maps
925 // and find the symbolic names for the characters that make
926 // up this collating element
927
928 // sym is sized at 13 because there will never be more then
929 // 99,999 collating elements
930 char sym [13];
931 std::sprintf (sym, "<RW_CE_%u>", ce_num++);
932
933 ce_map.insert (std::make_pair (sym, elem));
934 std::cout << "collating-element " << sym << " from \"";
935
936 if (0 == cmap)
937 std::cout << mbchar << "\"\n";
938 else {
939 const std::map<std::string, wchar_t> &cm =
940 cmap->get_mb_cmap ();
941
942 unsigned ch = 0;
943
944 for (unsigned j = 1; j <= mbchar.size (); ++j) {
945 const std::map<std::string, wchar_t>::const_iterator
946 it = cm.find (mbchar.substr (ch, j));
947
948 if (it != cm.end ()) {
949 std::cout << (cmap->get_rw_cmap ().find
950 (it->second))->second;
951 ch = j;
952 }
953 }
954
955 std::cout << "\"\n";
956 }
957 }
958 }
959 }
960}
961
962
963static int
964print_lc_collate (const char *section, int)
965{
966 print_section (section);
967
968 if (collate_st) {
969
970 if (decode) {
971
972 // print out internal collate_st data
973 std::cout << "# collate data:"
974 << "\n# codeset: \""
975 << collate_st->codeset_name ()
976 << "\"\n# charmap: \""
977 << collate_st->charmap_name ()
978 << "\"\n# codeset_off: "
979 << collate_st->codeset_off
980 << "\n# charmap_off: "
981 << collate_st->charmap_off
982 << "\n# elm_size: "
983 << collate_st->elm_size
984 << "\n# num_elms: "
985 << collate_st->num_elms
986 << "\n# num_wchars: "
987 << collate_st->num_wchars
988 << "\n# longest_weight: "
989 << int (collate_st->longest_weight)
990 << "\n# num_weights: "
991 << int (collate_st->num_weights)
992 << "\n# largest_ce: "
993 << int (collate_st->largest_ce)
994 << '\n';
995 }
996
997 std::map<std::string, unsigned int> ce_map;
998 typedef std::map<std::string, unsigned int>::iterator ce_map_iter;
999
1000 if (collate_st->largest_ce > 1) {
1001 print_ce_info (0, "", ce_map);
1002 }
1003
1004 std::cout << "\norder_start ";
1005 // if there are more then one weight then each should be seperated
1006 // by a semicolon. Print out all the weights names in this format
1007 // except for the last one.
1008 for (int i = 0; i < collate_st->num_weights; i++) {
1009 switch (collate_st->weight_type[i]) {
1010 case 0:
1011 std::cout << "forward";
1012 break;
1013 case 1:
1014 std::cout << "backward";
1015 break;
1016 case 2:
1017 std::cout << "forward,position";
1018 break;
1019 case 3:
1020 std::cout << "backward,position";
1021 break;
1022 default:
1023 issue_diag (502, true, 0, "invalid order type found "
1024 "in collate definition\n");
1025 }
1026 if (i == collate_st->num_weights - 1)
1027 std::cout << '\n';
1028 else
1029 std::cout << ';';
1030 }
1031
1032 // Print out the characters and their weights in
1033 // decimal format
1034
1035
1036 // first print out the collating elements
1037 for (ce_map_iter it = ce_map.begin (); it != ce_map.end (); ++it) {
1038 std::cout << it->first << " ";
1039
1040 print_weight (collate_st->get_weight (it->second),
1041 collate_st->num_weights,
1042 collate_st->longest_weight);
1043 }
1044
1045 write_coll_info ("", 0, 0);
1046
1047 if (collate_st->undefined_optimization) {
1048 std::cout << "UNDEFINED ";
1049
1050 const unsigned idx = collate_st->undefined_weight_idx;
1051
1052 print_weight (collate_st->get_weight (idx),
1053 collate_st->num_weights,
1054 collate_st->longest_weight);
1055 }
1056
1057 std::cout << "\norder_end\n";
1058 }
1059
1060 print_section (section, true);
1061
1062 return 0;
1063}
1064
1065
1067// print_mask takes in a ctype_base::mask value and prints all the
1068// characters in that mask category. If a charmap was given on the
1069// command line then it will look up the symbolic name and print that instead
1070static int
1071print_mask (const char *section, int mask)
1072{
1073 std::string out;
1074
1075 if (section)
1076 print_section (section);
1077
1078 const char *keyword = 0;
1079
1080 switch (mask) {
1081 case std::ctype_base::upper: keyword = "upper"; break;
1082 case std::ctype_base::lower: keyword = "lower"; break;
1083 case std::ctype_base::space: keyword = "space"; break;
1084 case std::ctype_base::print: keyword = "print"; break;
1085 case std::ctype_base::alpha: keyword = "alpha"; break;
1086 case std::ctype_base::cntrl: keyword = "cntrl"; break;
1087 case std::ctype_base::punct: keyword = "punct"; break;
1088 case std::ctype_base::graph: keyword = "graph"; break;
1089 case std::ctype_base::digit: keyword = "digit"; break;
1090 case std::ctype_base::xdigit: keyword = "xdigit"; break;
1091 default: break;
1092 }
1093
1094 if (keyword)
1095 print_keyword (keyword);
1096
1097 int nchars = 0;
1098
1099 if (0 != ctype_st) {
1100 const Charmap* const cmap = get_charmap (LC_CTYPE);
1101
1102 // go through the entire mask_table and print out each
1103 // character that has the specified mask, counting the
1104 // matching characters in the process
1105 // avoid printing masks without a keyword while still
1106 // counting such characters
1107#if 1
1108 for (std::size_t i = 0; i != ctype_st->wmask_s; ++i) {
1109
1110 if (ctype_st->wmask_tab (i).mask & mask) {
1111
1112 ++nchars;
1113
1114 if (keyword) {
1115 std::cout << create_str (ctype_st->wmask_tab (i).ch, cmap);
1116
1117 if (i + 1 < ctype_st->wmask_s)
1118 std::cout << ';';
1119 }
1120 }
1121 }
1122#else
1123 for (std::size_t k = 0; k < ctype_st->wmask_s; ++k) {
1124
1125 if (ctype_st->wmask_tab (k).mask & mask) {
1126
1127 if (keyword)
1128 out += create_str (ctype_st->wmask_tab (k).ch, cmap);
1129
1130 ++nchars;
1131
1132 for (std::size_t j = k + 1; j < ctype_st->wmask_s; ++j) {
1133
1134 if (ctype_st->wmask_tab (j).mask & mask) {
1135
1136 if (keyword) {
1137 out += ';';
1138
1139 if (out.size () >= MAX_LINE_LEN && !posix_output)
1140 out += '\\';
1141 }
1142
1143 break;
1144 }
1145 }
1146 }
1147
1148 if (keyword && MAX_LINE_LEN < out.size () && !posix_output) {
1149 std::cout << out << '\n';
1150 out.clear ();
1151 }
1152 }
1153
1154 std::cout << out;
1155#endif
1156
1157 }
1158
1159 if (keyword)
1160 std::cout << '\n';
1161
1162 return nchars;
1163}
1164
1165
1166static int
1167print_toupper (const char *keyword, int print_cat)
1168{
1169 if (print_cat)
1170 print_section (sect_lc_ctype);
1171
1172 print_keyword (keyword);
1173
1174 std::string out;
1175
1176 // number of characters in the maps
1177 int nchars = 0;
1178
1179 if (0 != ctype_st) {
1180
1181 const Charmap* const cmap = get_charmap (LC_CTYPE);
1182
1183 const std::size_t count = ctype_st->wtoupper_s ();
1184
1185 nchars += int (count);
1186
1187 // print out each pair in the toupper table.
1188 // the wide char table is used because it contains all characters
1189 for (std::size_t j = 0; j < count; ++j) {
1190 out += '(';
1191 out += create_str (ctype_st->wtoupper_tab (j).lower, cmap);
1192 out += ',';
1193 out += create_str (ctype_st->wtoupper_tab (j).upper, cmap);
1194 out += ')';
1195
1196 if (j != count - 1) {
1197 if (out.size () >= MAX_LINE_LEN && !posix_output)
1198 out += ";\\";
1199 else
1200 out += ';';
1201 }
1202
1203 if (out.size () > MAX_LINE_LEN && !posix_output) {
1204 std::cout << out << '\n';
1205 out.clear ();
1206 }
1207 }
1208
1209 std::cout << out;
1210 }
1211
1212 std::cout << '\n';
1213
1214 return nchars;
1215}
1216
1217
1218static int
1219print_tolower (const char *keyword, int print_cat)
1220{
1221 if (print_cat)
1222 print_section (sect_lc_ctype);
1223
1224 print_keyword (keyword);
1225
1226 std::string out;
1227
1228 // number of characters in the maps
1229 int nchars = 0;
1230
1231 if (0 != ctype_st) {
1232
1233 const Charmap* const cmap = get_charmap (LC_CTYPE);
1234
1235 const std::size_t count = ctype_st->wtolower_s ();
1236
1237 nchars += int (count);
1238
1239 for (std::size_t j = 0; j < count; ++j) {
1240 out += '(';
1241 out += create_str (ctype_st->wtolower_tab (j).upper, cmap);
1242 out += ',';
1243 out += create_str (ctype_st->wtolower_tab (j).lower, cmap);
1244 out += ')';
1245
1246 if (j != count - 1) {
1247 if (out.size () >= MAX_LINE_LEN && !posix_output)
1248 out += ";\\";
1249 else
1250 out += ';';
1251 }
1252 if (out.size () > MAX_LINE_LEN && !posix_output) {
1253 std::cout << out << '\n';
1254 out.clear ();
1255 }
1256 }
1257 std::cout << out;
1258 }
1259
1260 std::cout << '\n';
1261
1262 return nchars;
1263}
1264
1265
1266static int
1267print_lc_ctype (const char *section, int)
1268{
1269 print_section (section);
1270
1271 if (0 != ctype_st && decode) {
1272
1273 // print out internal ctype_st data
1274 std::cout << "# ctype data:"
1275 << "\n# codeset: \""
1276 << ctype_st->codeset_name ()
1277 << "\"\n# charmap: \""
1278 << ctype_st->charmap_name ()
1279 << "\"\n# codeset_off: "
1280 << ctype_st->codeset_off
1281 << "\n# charmap_off: "
1282 << ctype_st->charmap_off
1283 << "\n# wmask_s: "
1284 << ctype_st->wmask_s
1285 << "\n# wtoupper_off: "
1286 << ctype_st->wtoupper_off
1287 << "\n# wtolower_off: "
1288 << ctype_st->wtolower_off
1289 << "\n# wmask_off: "
1290 << ctype_st->wmask_off
1291 << "\n# ctype_ext_off: "
1292 << ctype_st->ctype_ext_off
1293 << "\n# mb_cur_max: "
1294 << unsigned (ctype_st->mb_cur_max)
1295 << '\n';
1296 }
1297
1298 const std::size_t nupper = print_mask (0, std::ctype_base::upper);
1299 const std::size_t nlower = print_mask (0, std::ctype_base::lower);
1300 const std::size_t nspace = print_mask (0, std::ctype_base::space);
1301 const std::size_t nprint = print_mask (0, std::ctype_base::print);
1302 const std::size_t ncntrl = print_mask (0, std::ctype_base::cntrl);
1303 const std::size_t nalpha = print_mask (0, std::ctype_base::alpha);
1304 const std::size_t ndigit = print_mask (0, std::ctype_base::digit);
1305 const std::size_t npunct = print_mask (0, std::ctype_base::punct);
1306 const std::size_t ngraph = print_mask (0, std::ctype_base::graph);
1307 const std::size_t nxdigit = print_mask (0, std::ctype_base::xdigit);
1308
1309 const int all_masks =
1310 std::ctype_base::upper | std::ctype_base::lower
1311 | std::ctype_base::space | std::ctype_base::print
1312 | std::ctype_base::cntrl | std::ctype_base::alpha
1313 | std::ctype_base::digit | std::ctype_base::punct
1314 | std::ctype_base::graph | std::ctype_base::xdigit;
1315
1316 // count the number of all characters in all tables
1317 const std::size_t nall = print_mask (0, -1);
1318
1319 // count the number of characters whose mask is other than
1320 // any of those specified (probably mistakes)
1321 const std::size_t nother = print_mask (0, ~all_masks);
1322
1323 const std::size_t ntoupper = print_toupper ("toupper", 0);
1324 const std::size_t ntolower = print_tolower ("tolower", 0);
1325
1326 if (0 != ctype_st && decode) {
1327 std::cout << "\n# ctype stats:"
1328 << "\n# total characters: " << nall
1329 << "\n# upper characters: " << nupper
1330 << "\n# lower characters: " << nlower
1331 << "\n# space characters: " << nspace
1332 << "\n# print characters: " << nprint
1333 << "\n# cntrl characters: " << ncntrl
1334 << "\n# alpha characters: " << nalpha
1335 << "\n# digit characters: " << ndigit
1336 << "\n# punct characters: " << npunct
1337 << "\n# graph characters: " << ngraph
1338 << "\n# xdigit characters: " << nxdigit
1339 << "\n# unclassified: " << nother
1340 << "\n# tolower pairs: " << ntolower
1341 << "\n# toupper pairs: " << ntoupper
1342 << "\n";
1343 }
1344
1345 print_section (section, true);
1346
1347 return 0;
1348}
1349
1350
1352static int
1353print_decimal_point (const char *keyword, int print_cat)
1354{
1355 if (print_cat)
1356 print_section (sect_lc_numeric);
1357
1358 print_keyword (keyword);
1359
1360 if (0 == num_st)
1361 std::cout << '"' << create_str (".", 0, 0) << "\"\n";
1362 else {
1363 const char* const dp =
1364 _RWSTD_STATIC_CAST (const char*, num_punct_st->decimal_point (0));
1365
1366 const wchar_t* const wdp =
1367 _RWSTD_STATIC_CAST(const wchar_t*, num_punct_st->decimal_point (1));
1368
1369 const Charmap* const cmap = get_charmap (LC_NUMERIC);
1370
1371 std::cout << '"' << create_str (dp, wdp, cmap) << "\"\n";
1372 }
1373
1374 return 0;
1375}
1376
1377
1378static int
1379print_thousands_sep (const char *keyword, int print_cat)
1380{
1381 if (print_cat)
1382 print_section (sect_lc_numeric);
1383
1384 print_keyword (keyword);
1385
1386 if (0 == num_st)
1387 std::cout << "\"\"\n";
1388 else {
1389 const char* const ts =
1390 _RWSTD_STATIC_CAST (const char*, num_punct_st->thousands_sep (0));
1391
1392 const wchar_t* const wts =
1393 _RWSTD_STATIC_CAST(const wchar_t*, num_punct_st->thousands_sep (1));
1394
1395 const Charmap* const cmap = get_charmap (LC_NUMERIC);
1396
1397 std::cout << '"' << create_str (ts, wts, cmap) << "\"\n";
1398 }
1399
1400 return 0;
1401}
1402
1403
1404static int
1405print_grouping (const char *keyword, int print_cat)
1406{
1407 if (print_cat)
1408 print_section (sect_lc_numeric);
1409
1410 print_keyword (keyword);
1411
1412 if (0 == num_st)
1413 std::cout << "-1\n";
1414 else {
1415 size_t i;
1416 for (i = 0;
1417 i < num_punct_st->punct_ext_off - num_punct_st->grouping_off - 2;
1418 i++)
1419 std::cout << (int)((const char*)num_punct_st->grouping())[i]
1420 << ";";
1421 std::cout << (int)((const char*)num_punct_st->grouping())[i]
1422 << '\n';
1423 }
1424
1425 return 0;
1426}
1427
1428
1429static int
1430print_lc_numeric (const char *section, int)
1431{
1432 print_section (section);
1433
1434 if (0 != num_st && decode) {
1435
1436 // print out internal numeric_st data
1437 std::cout << "# numeric data:"
1438 << "\n# codeset: \""
1439 << num_st->codeset_name ()
1440 << "\"\n# charmap: \""
1441 << num_st->charmap_name ()
1442 << "\"\n# codeset_off: "
1443 << num_st->codeset_off
1444 << "\n# charmap_off: "
1445 << num_st->charmap_off
1446 << '\n';
1447 }
1448
1449 // keywords follow the established order on popular platforms
1450 print_decimal_point ("decimal_point", 0);
1451 print_thousands_sep ("thousands_sep", 0);
1452 print_grouping ("grouping", 0);
1453
1454 print_section (section, true);
1455
1456 return 0;
1457}
1458
1459
1461static int
1462print_int_curr_symbol (const char *keyword, int print_cat)
1463{
1464 if (print_cat)
1465 print_section (sect_lc_monetary);
1466
1467 print_keyword (keyword);
1468
1469 if (0 == mon_st)
1470 std::cout << "\"\"\n";
1471 else {
1472 const char* const cs =
1473 _RWSTD_STATIC_CAST (const char*, mon_st->curr_symbol (1, 0));
1474
1475 const wchar_t* const wcs =
1476 _RWSTD_STATIC_CAST (const wchar_t*, mon_st->curr_symbol (1, 1));
1477
1478 const Charmap* const cmap = get_charmap (LC_MONETARY);
1479
1480 std::cout << '"' << create_str (cs, wcs, cmap) << "\"\n";
1481 }
1482
1483 return 0;
1484}
1485
1486
1487static int
1488print_currency_symbol (const char *keyword, int print_cat)
1489{
1490 if (print_cat)
1491 print_section (sect_lc_monetary);
1492
1493 print_keyword (keyword);
1494
1495 if (0 == mon_st)
1496 std::cout << "\"\"\n";
1497 else {
1498 const char* const cs =
1499 _RWSTD_STATIC_CAST (const char*, mon_st->curr_symbol (0, 0));
1500
1501 const wchar_t* const wcs =
1502 _RWSTD_STATIC_CAST (const wchar_t*, mon_st->curr_symbol (0, 1));
1503
1504 const Charmap* const cmap = get_charmap (LC_MONETARY);
1505
1506 std::cout << '"' << create_str (cs, wcs, cmap) << "\"\n";
1507 }
1508
1509 return 0;
1510}
1511
1512
1513static int
1514print_mon_decimal_point (const char *keyword, int print_cat)
1515{
1516 if (print_cat)
1517 print_section (sect_lc_monetary);
1518
1519 print_keyword (keyword);
1520
1521 if (0 == mon_st)
1522 std::cout << "\"\"\n";
1523 else {
1524 const char* const dp =
1525 _RWSTD_STATIC_CAST (const char*, mon_punct_st->decimal_point (0));
1526
1527 const wchar_t* const wdp =
1528 _RWSTD_STATIC_CAST(const wchar_t*, mon_punct_st->decimal_point (1));
1529
1530 const Charmap* const cmap = get_charmap (LC_MONETARY);
1531
1532 std::cout << '"' << create_str (dp, wdp, cmap) << "\"\n";
1533 }
1534
1535 return 0;
1536}
1537
1538
1539static int
1540print_mon_thousands_sep (const char *keyword, int print_cat)
1541{
1542 if (print_cat)
1543 print_section (sect_lc_monetary);
1544
1545 print_keyword (keyword);
1546
1547 if (0 == mon_st)
1548 std::cout << "\"\"\n";
1549 else {
1550 const char* const ts =
1551 _RWSTD_STATIC_CAST (const char*, mon_punct_st->thousands_sep (0));
1552
1553 const wchar_t* const wts =
1554 _RWSTD_STATIC_CAST(const wchar_t*, mon_punct_st->thousands_sep (1));
1555
1556 const Charmap* const cmap = get_charmap (LC_MONETARY);
1557
1558 std::cout << '"' << create_str (ts, wts, cmap) << "\"\n";
1559 }
1560
1561 return 0;
1562}
1563
1564
1565static int
1566print_mon_grouping (const char *keyword, int print_cat)
1567{
1568 if (print_cat)
1569 print_section (sect_lc_monetary);
1570
1571 print_keyword (keyword);
1572
1573 if (0 == mon_st)
1574 std::cout << "-1\n";
1575 else {
1576 size_t i;
1577 for (i = 0;
1578 i < mon_punct_st->punct_ext_off - mon_punct_st->grouping_off - 2;
1579 i++)
1580 std::cout << (int)((const char*)mon_punct_st->grouping())[i] << ";";
1581 std::cout << (int)((const char*)mon_punct_st->grouping())[i]
1582 << '\n';
1583 }
1584
1585 return 0;
1586}
1587
1588
1589static int
1590print_positive_sign (const char *keyword, int print_cat)
1591{
1592 if (print_cat)
1593 print_section (sect_lc_monetary);
1594
1595 print_keyword (keyword);
1596
1597 if (0 == mon_st)
1598 std::cout << "\"\"\n";
1599 else {
1600 const char* const ps =
1601 _RWSTD_STATIC_CAST (const char*, mon_st->positive_sign (0));
1602
1603 const wchar_t* const wps =
1604 _RWSTD_STATIC_CAST (const wchar_t*, mon_st->positive_sign (1));
1605
1606 const Charmap* const cmap = get_charmap (LC_MONETARY);
1607
1608 std::cout << '"' << create_str (ps, wps, cmap) << "\"\n";
1609 }
1610
1611 return 0;
1612}
1613
1614
1615static int
1616print_negative_sign (const char *keyword, int print_cat)
1617{
1618 if (print_cat)
1619 print_section (sect_lc_monetary);
1620
1621 print_keyword (keyword);
1622
1623 if (0 == mon_st)
1624 std::cout << "\"\"\n";
1625 else {
1626 const char* const ns =
1627 _RWSTD_STATIC_CAST (const char*, mon_st->negative_sign (0));
1628
1629 const wchar_t* const wns =
1630 _RWSTD_STATIC_CAST (const wchar_t*, mon_st->negative_sign (1));
1631
1632 const Charmap* const cmap = get_charmap (LC_MONETARY);
1633
1634 std::cout << '"' << create_str (ns, wns, cmap) << "\"\n";
1635 }
1636
1637 return 0;
1638}
1639
1640
1641static void
1642print_int (const char *keyword, int val, int print_cat)
1643{
1644 if (print_cat)
1645 print_section (sect_lc_monetary);
1646
1647 print_keyword (keyword);
1648
1649 std::cout << val << '\n';
1650}
1651
1652
1653#define MON_INT(member) \
1654 (mon_st && CHAR_MAX != (mon_st->member) ? int (UChar (mon_st->member)) : -1)
1655
1656static int
1657print_int_frac_digits (const char *keyword, int print_cat)
1658{
1659 print_int (keyword, MON_INT (frac_digits [1]), print_cat);
1660
1661 return 0;
1662
1663}
1664
1665
1666static int
1667print_frac_digits (const char *keyword, int print_cat)
1668{
1669 print_int (keyword, MON_INT (frac_digits [0]), print_cat);
1670
1671 return 0;
1672}
1673
1674
1675static int
1676print_p_cs_precedes (const char *keyword, int print_cat)
1677{
1678 print_int (keyword, MON_INT (p_cs_precedes [0]), print_cat);
1679
1680 return 0;
1681}
1682
1683
1684static int
1685print_n_sep_by_space (const char *keyword, int print_cat)
1686{
1687 print_int (keyword, MON_INT (n_sep_by_space [0]), print_cat);
1688
1689 return 0;
1690}
1691
1692
1693static int
1694print_p_sep_by_space (const char *keyword, int print_cat)
1695{
1696 print_int (keyword, MON_INT (p_sep_by_space [0]), print_cat);
1697
1698 return 0;
1699}
1700
1701
1702static int
1703print_n_cs_precedes (const char *keyword, int print_cat)
1704{
1705 print_int (keyword, MON_INT (n_cs_precedes [0]), print_cat);
1706
1707 return 0;
1708}
1709
1710
1711static int
1712print_p_sign_posn (const char *keyword, int print_cat)
1713{
1714 print_int (keyword, MON_INT (p_sign_posn [0]), print_cat);
1715
1716 return 0;
1717}
1718
1719
1720static int
1721print_n_sign_posn (const char *keyword, int print_cat)
1722{
1723 print_int (keyword, MON_INT (n_sign_posn [0]), print_cat);
1724
1725 return 0;
1726}
1727
1728
1729static int
1730print_int_p_cs_precedes (const char *keyword, int print_cat)
1731{
1732 print_int (keyword, MON_INT (p_cs_precedes [1]), print_cat);
1733
1734 return 0;
1735}
1736
1737
1738static int
1739print_int_n_sep_by_space (const char *keyword, int print_cat)
1740{
1741 print_int (keyword, MON_INT (n_sep_by_space [1]), print_cat);
1742
1743 return 0;
1744}
1745
1746
1747static int
1748print_int_p_sep_by_space (const char *keyword, int print_cat)
1749{
1750 print_int (keyword, MON_INT (p_sep_by_space [1]), print_cat);
1751
1752 return 0;
1753}
1754
1755
1756static int
1757print_int_n_cs_precedes (const char *keyword, int print_cat)
1758{
1759 print_int (keyword, MON_INT (n_cs_precedes [1]), print_cat);
1760
1761 return 0;
1762}
1763
1764
1765static int
1766print_int_p_sign_posn (const char *keyword, int print_cat)
1767{
1768 print_int (keyword, MON_INT (p_sign_posn [1]), print_cat);
1769
1770 return 0;
1771}
1772
1773
1774static int
1775print_int_n_sign_posn (const char *keyword, int print_cat)
1776{
1777 print_int (keyword, MON_INT (n_sign_posn [1]), print_cat);
1778
1779 return 0;
1780}
1781
1782
1783static int
1784print_lc_monetary (const char *section, int)
1785{
1786 print_section (section);
1787
1788 if (mon_st && decode) {
1789
1790 // print out internal monetary_st data
1791 std::cout << "# monetary data:"
1792 << "\n# codeset: \""
1793 << mon_st->codeset_name ()
1794 << "\"\n# charmap: \""
1795 << mon_st->charmap_name ()
1796 << "\"\n# codeset_off: "
1797 << mon_st->codeset_off
1798 << "\n# charmap_off: "
1799 << mon_st->charmap_off
1800 << '\n';
1801 }
1802
1803 // keywords follow the established order on popular platforms
1804 print_int_curr_symbol ("int_curr_symbol", 0);
1805 print_currency_symbol ("currency_symbol", 0);
1806 print_mon_decimal_point ("mon_decimal_point", 0);
1807 print_mon_thousands_sep ("mon_thousands_sep", 0);
1808 print_mon_grouping ("mon_grouping", 0);
1809 print_positive_sign ("positive_sign", 0);
1810 print_negative_sign ("negative_sign", 0);
1811
1812 print_int_frac_digits ("int_frac_digits", 0);
1813 print_frac_digits ("frac_digits", 0);
1814
1815 print_p_cs_precedes ("p_cs_precedes", 0);
1816 print_p_sep_by_space ("p_sep_by_space", 0);
1817 print_n_cs_precedes ("n_cs_precedes", 0);
1818 print_n_sep_by_space ("n_sep_by_space", 0);
1819 print_p_sign_posn ("p_sign_posn", 0);
1820 print_n_sign_posn ("n_sign_posn", 0);
1821
1822 print_int_p_cs_precedes ("int_p_cs_precedes", 0);
1823 print_int_p_sep_by_space ("int_p_sep_by_space", 0);
1824 print_int_n_cs_precedes ("int_n_cs_precedes", 0);
1825 print_int_n_sep_by_space ("int_n_sep_by_space", 0);
1826 print_int_p_sign_posn ("int_p_sign_posn", 0);
1827 print_int_n_sign_posn ("int_n_sign_posn", 0);
1828
1829 print_section (section, true);
1830
1831 return 0;
1832}
1833
1834
1836static void
1837print_time_keyword (const char *keyword, int print_cat,
1838 const void *vstr, const void *vwstr)
1839{
1840 if (print_cat)
1841 print_section (sect_lc_monetary);
1842
1843 if (keyword)
1844 print_keyword (keyword);
1845
1846 const Charmap* const cmap = get_charmap (LC_TIME);
1847
1848 const char* const str = _RWSTD_STATIC_CAST (const char*, vstr);
1849 const wchar_t* const wstr = _RWSTD_STATIC_CAST (const wchar_t*, vwstr);
1850
1851 std::cout << '"' << create_str (str, wstr, cmap) << "\"";
1852}
1853
1854
1855static int
1856print_abday (const char *keyword, int print_cat)
1857{
1858 static const char str[][4] = {
1859 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
1860 };
1861
1862 for (std::size_t i = 0; ; ) {
1863
1864 print_time_keyword (keyword, print_cat,
1865 time_st ? time_st->abday (i, 0) : str [i],
1866 time_st ? time_st->abday (i, 1) : 0);
1867
1868 keyword = 0;
1869 print_cat = 0;
1870
1871 if (sizeof str / sizeof *str == ++i)
1872 break;
1873
1874 std::cout << ';';
1875 }
1876
1877 std::cout << '\n';
1878
1879 return 0;
1880}
1881
1882
1883static int
1884print_day (const char *keyword, int print_cat)
1885{
1886 static const char str[][10] = {
1887 "Sunday", "Monday", "Tuesday", "Wednesday",
1888 "Thursday", "Friday", "Saturday"
1889 };
1890
1891 for (std::size_t i = 0; ; ) {
1892
1893 print_time_keyword (keyword, print_cat,
1894 time_st ? time_st->day (i, 0) : str [i],
1895 time_st ? time_st->day (i, 1) : 0);
1896
1897 keyword = 0;
1898 print_cat = 0;
1899
1900 if (sizeof str / sizeof *str == ++i)
1901 break;
1902
1903 std::cout << ';';
1904 }
1905
1906 std::cout << '\n';
1907
1908 return 0;
1909}
1910
1911
1912static int
1913print_abmon (const char *keyword, int print_cat)
1914{
1915 static const char str[][4] = {
1916 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1917 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1918 };
1919
1920 for (std::size_t i = 0; ; ) {
1921
1922 print_time_keyword (keyword, print_cat,
1923 time_st ? time_st->abmon (i, 0) : str [i],
1924 time_st ? time_st->abmon (i, 1) : 0);
1925
1926 keyword = 0;
1927 print_cat = 0;
1928
1929 if (sizeof str / sizeof *str == ++i)
1930 break;
1931
1932 std::cout << ';';
1933 }
1934
1935 std::cout << '\n';
1936
1937 return 0;
1938}
1939
1940
1941static int
1942print_mon (const char *keyword, int print_cat)
1943{
1944 static const char str[][10] = {
1945 "January", "February", "March", "April", "May", "June",
1946 "July", "August", "September", "October", "November", "December"
1947 };
1948
1949 for (std::size_t i = 0; ; ) {
1950
1951 print_time_keyword (keyword, print_cat,
1952 time_st ? time_st->mon (i, 0) : str [i],
1953 time_st ? time_st->mon (i, 1) : 0);
1954
1955 keyword = 0;
1956 print_cat = 0;
1957
1958 if (sizeof str / sizeof *str == ++i)
1959 break;
1960
1961 std::cout << ';';
1962 }
1963
1964 std::cout << '\n';
1965
1966 return 0;
1967}
1968
1969
1970static int
1971print_am_pm (const char *keyword, int print_cat)
1972{
1973 static const char str[][3] = { "AM", "PM" };
1974
1975 print_time_keyword (keyword, print_cat,
1976 time_st ? time_st->am_pm (0, 0) : str [0],
1977 time_st ? time_st->am_pm (0, 1) : str [1]);
1978
1979 std::cout << ';';
1980
1981 print_time_keyword (0, 0,
1982 time_st ? time_st->am_pm (1, 0) : str [0],
1983 time_st ? time_st->am_pm (1, 1) : str [1]);
1984
1985 std::cout << '\n';
1986
1987 return 0;
1988}
1989
1990
1991static int
1992print_era (const char *keyword, int print_cat)
1993{
1994 if (print_cat)
1995 print_section (sect_lc_monetary);
1996
1997 print_keyword (keyword);
1998
1999 if (0 == time_st)
2000 std::cout << '"' << create_str ("", 0, 0)
2001 << "\"\n";
2002 else if (0 == time_st->era_count ()) {
2003 // if there are no eras, print out the empty string
2004 std::cout << "\"\"\n";
2005 }
2006 else {
2007 const Charmap* const cmap = get_charmap (LC_TIME);
2008
2009 // print each era in the database according to the format
2010 // specified by POSIX
2011 for (unsigned int i = 0; i < time_st->era_count(); i++) {
2012 const _RW::__rw_time_t::era_t *era_p = time_st->era (i);
2013 // first print the direction and the offset
2014 if (era_p->offset >= 0)
2015 std::cout << "\"+:" << era_p->offset << ":";
2016 else {
2017 std::cout << "\"-:" << era_p->offset * -1 << ":";
2018 }
2019 // now print the start year, if it's negative, make sure the
2020 // negative sign gets in front
2021 if (era_p->year[0] < 0)
2022 std::cout << '-' << std::setw(4) << std::setfill ('0')
2023 << era_p->year[0] * -1;
2024 else
2025 std::cout << std::setw(4) << std::setfill ('0')
2026 << era_p->year[0];
2027
2028 // now print the rest of the start date
2029 std::cout << _RWSTD_PATH_SEP << std::setw(2)
2030 << int(era_p->month[0]) + 1 << _RWSTD_PATH_SEP
2031 << std::setw(2) << int(era_p->day[0]) << ":";
2032
2033 // now print the end year, INT_MIN is the beginning of time
2034 // and INT_MAX is the end of time
2035 if (era_p->year[1] == INT_MIN)
2036 std::cout << "-*:";
2037 else if (era_p->year[1] == INT_MAX)
2038 std::cout << "+*:";
2039 else {
2040 if (era_p->year[1] < 0)
2041 std::cout << '-' << std::setw(4) << era_p->year[1] * -1;
2042 else
2043 std::cout << std::setw(4) << era_p->year[1];
2044
2045 // now print out the rest of the end date
2046 std::cout << _RWSTD_PATH_SEP << std::setw(2)
2047 << int(era_p->month[1]) + 1 << _RWSTD_PATH_SEP
2048 << std::setw(2) << int(era_p->day[1]) << ":";
2049 }
2050
2051 const char* const era =
2052 _RWSTD_STATIC_CAST (const char*, time_st->era_name (i, 0));
2053
2054 const wchar_t* const wera =
2055 _RWSTD_STATIC_CAST (const wchar_t*, time_st->era_name (i, 1));
2056
2057 const char* const fmt =
2058 _RWSTD_STATIC_CAST (const char*, time_st->era_fmt (i, 0));
2059
2060 const wchar_t* const wfmt =
2061 _RWSTD_STATIC_CAST (const wchar_t*, time_st->era_fmt (i, 1));
2062
2063 std::cout << create_str (era, wera, cmap) << ":"
2064 << create_str (fmt, wfmt, cmap);
2065
2066 if (i != time_st->era_count () - 1)
2067 std::cout << "\";";
2068 else
2069 std::cout << "\"\n";
2070 }
2071 }
2072
2073 return 0;
2074}
2075
2076
2077static int
2078print_d_t_fmt (const char *keyword, int print_cat)
2079{
2080 static const char str[] = "%a %b %e %H:%M:%S %Y";
2081
2082 print_time_keyword (keyword, print_cat,
2083 time_st ? time_st->d_t_fmt (0) : str,
2084 time_st ? time_st->d_t_fmt (1) : 0);
2085
2086 std::cout << '\n';
2087
2088 return 0;
2089}
2090
2091
2092static int
2093print_era_d_t_fmt (const char *keyword, int print_cat)
2094{
2095 print_time_keyword (keyword, print_cat,
2096 time_st ? time_st->era_d_t_fmt (0) : 0,
2097 time_st ? time_st->era_d_t_fmt (1) : 0);
2098
2099 std::cout << '\n';
2100
2101 return 0;
2102}
2103
2104
2105static int
2106print_d_fmt (const char *keyword, int print_cat)
2107{
2108 static const char str[] = "%m/%d/%y";
2109
2110 print_time_keyword (keyword, print_cat,
2111 time_st ? time_st->d_fmt (0) : str,
2112 time_st ? time_st->d_fmt (1) : 0);
2113
2114 std::cout << '\n';
2115
2116 return 0;
2117}
2118
2119
2120static int
2121print_era_d_fmt (const char *keyword, int print_cat)
2122{
2123 print_time_keyword (keyword, print_cat,
2124 time_st ? time_st->era_d_fmt (0) : 0,
2125 time_st ? time_st->era_d_fmt (1) : 0);
2126
2127 std::cout << '\n';
2128
2129 return 0;
2130}
2131
2132
2133static int
2134print_t_fmt (const char *keyword, int print_cat)
2135{
2136 static const char str[] = "%H:%M:%S";
2137
2138 print_time_keyword (keyword, print_cat,
2139 time_st ? time_st->t_fmt (0) : str,
2140 time_st ? time_st->t_fmt (1) : 0);
2141
2142 std::cout << '\n';
2143
2144 return 0;
2145}
2146
2147
2148static int
2149print_era_t_fmt (const char *keyword, int print_cat)
2150{
2151 print_time_keyword (keyword, print_cat,
2152 time_st ? time_st->era_t_fmt (0) : 0,
2153 time_st ? time_st->era_t_fmt (1) : 0);
2154
2155 std::cout << '\n';
2156
2157 return 0;
2158}
2159
2160
2161static int
2162print_t_fmt_ampm (const char *keyword, int print_cat)
2163{
2164 static const char str[] = "%I:%M:%S %p";
2165
2166 print_time_keyword (keyword, print_cat,
2167 time_st ? time_st->t_fmt_ampm (0) : str,
2168 time_st ? time_st->t_fmt_ampm (1) : 0);
2169
2170 std::cout << '\n';
2171
2172 return 0;
2173}
2174
2175
2176static int
2177print_alt_digits (const char *keyword, int print_cat)
2178{
2179 if (time_st) {
2180 const unsigned ndigits = time_st->alt_digits_count ();
2181
2182 for (unsigned i = 0; ; ) {
2183
2184 print_time_keyword (keyword, print_cat,
2185 i < ndigits ? time_st->alt_digits (i, 0) : 0,
2186 i < ndigits ? time_st->alt_digits (i, 1) : 0);
2187
2188 keyword = 0;
2189 print_cat = 0;
2190
2191 if (ndigits <= ++i)
2192 break;
2193
2194 std::cout << ';';
2195 }
2196
2197 std::cout << '\n';
2198 }
2199 else {
2200 print_time_keyword (keyword, print_cat, 0, 0);
2201 }
2202
2203 return 0;
2204}
2205
2206
2207static int
2208print_lc_time (const char *section, int)
2209{
2210 print_section (section);
2211
2212 if (time_st && decode) {
2213
2214 // print out internal time_st data
2215 std::cout << "# time data:"
2216 << "\n# codeset: \""
2217 << time_st->codeset_name ()
2218 << "\"\n# charmap: \""
2219 << time_st->charmap_name ()
2220 << "\"\n# codeset_off: "
2221 << time_st->codeset_off
2222 << "\n# charmap_off: "
2223 << time_st->charmap_off
2224 << '\n';
2225 }
2226
2227 print_abday ("abday", 0);
2228 print_day ("day", 0);
2229 print_abmon ("abmon", 0);
2230 print_mon ("mon", 0);
2231 print_am_pm ("am_pm", 0);
2232 print_d_t_fmt ("d_t_fmt", 0);
2233 print_d_fmt ("d_fmt", 0);
2234 print_t_fmt ("t_fmt", 0);
2235 print_t_fmt_ampm ("t_fmt_ampm", 0);
2236 print_era ("era", 0);
2237 print_era_d_t_fmt ("era_d_t_fmt", 0);
2238 print_era_d_fmt ("era_d_fmt", 0);
2239 print_era_t_fmt ("era_t_fmt", 0);
2240 print_alt_digits ("alt_digits", 0);
2241
2242 print_section (section, true);
2243
2244 return 0;
2245}
2246
2247
2249static int
2250print_noexpr (const char *keyword, int print_cat)
2251{
2252 if (print_cat)
2253 print_section (sect_lc_messages);
2254
2255 print_keyword (keyword);
2256
2257 if (0 == messages_st)
2258 std::cout << '"' << create_str ("^[nN]", 0, 0) << "\"\n";
2259 else {
2260 const char* const no
2261 = _RWSTD_STATIC_CAST (const char*, messages_st->noexpr (0));
2262
2263 const wchar_t* const wno
2264 = _RWSTD_STATIC_CAST (const wchar_t*, messages_st->noexpr (1));
2265
2266 const Charmap* const cmap = get_charmap (LC_MESSAGES);
2267
2268 std::cout << '"' << create_str (no, wno, cmap) << "\"\n";
2269 }
2270
2271 return 0;
2272}
2273
2274
2275static int
2276print_yesexpr (const char *keyword, int print_cat)
2277{
2278 if (print_cat)
2279 print_section (sect_lc_messages);
2280
2281 print_keyword (keyword);
2282
2283 if (0 == messages_st)
2284 std::cout << '"' << create_str ("^[yY]", 0, 0) << "\"\n";
2285 else {
2286 const char* const yes
2287 = _RWSTD_STATIC_CAST (const char*, messages_st->yesexpr (0));
2288
2289 const wchar_t* const wyes
2290 = _RWSTD_STATIC_CAST (const wchar_t*, messages_st->yesexpr (1));
2291
2292 const Charmap* const cmap = get_charmap (LC_MESSAGES);
2293
2294 std::cout << '"' << create_str (yes, wyes, cmap) << "\"\n";
2295 }
2296
2297 return 0;
2298}
2299
2300
2301static int
2302print_lc_messages (const char *section, int)
2303{
2304 print_section (section);
2305
2306 if (messages_st && decode) {
2307
2308 // print out internal time_st data
2309 std::cout << "# messages data:"
2310 << "\n# codeset: \""
2311 << messages_st->codeset_name ()
2312 << "\"\n# charmap: \""
2313 << messages_st->charmap_name ()
2314 << "\"\n# codeset_off: "
2315 << messages_st->codeset_off
2316 << "\n# charmap_off: "
2317 << messages_st->charmap_off
2318 << '\n';
2319 }
2320
2321 print_yesexpr ("yesexpr", 0);
2322 print_noexpr ("noexpr", 0);
2323
2324 print_section (section, true);
2325
2326 return 0;
2327}
2328
2329
2331static int
2332print_lc_all (const char*, int)
2333{
2334 print_lc_collate (sect_lc_collate, 0);
2335 std::cout << '\n';
2336
2337 print_lc_ctype (sect_lc_ctype, 0);
2338 std::cout << '\n';
2339
2340 print_lc_monetary (sect_lc_monetary, 0);
2341 std::cout << '\n';
2342
2343 print_lc_numeric (sect_lc_numeric, 0);
2344 std::cout << '\n';
2345
2346 print_lc_time (sect_lc_time, 0);
2347 std::cout << '\n';
2348
2349 print_lc_messages (sect_lc_messages, 0);
2350
2351 return 0;
2352}
2353
2354
2356static int
2357print_charmap_name (const char *section, int)
2358{
2359 if (0 != ctype_st) {
2360 print_section (section);
2361
2362 print_keyword ("charmap");
2363 std::cout << '"'<< ctype_st->charmap_name () << "\"\n";
2364 }
2365
2366 return 0;
2367}
2368
2369
2370#ifdef _WIN32
2371static BOOL CALLBACK
2372EnumLocales (char* locale_id)
2373{
2374 const LCID lcid = std::strtoul (locale_id, 0, 16);
2375
2376 char buf [80];
2377 const int bufsize = sizeof (buf) / sizeof (*buf);
2378
2379 std::string name;
2380
2381 if (GetLocaleInfo (lcid, LOCALE_SENGLANGUAGE, buf, bufsize))
2382 name = buf;
2383
2384 if (GetLocaleInfo (lcid, LOCALE_SENGCOUNTRY, buf, bufsize)) {
2385 name += '_';
2386 name += buf;
2387 }
2388
2389 if ( GetLocaleInfo (lcid, LOCALE_IDEFAULTANSICODEPAGE , buf, bufsize)
2390 && std::strtoul (buf, 0, 10)) {
2391 name += '.';
2392 name += buf;
2393 }
2394
2395 if (const char* locname = std::setlocale (LC_ALL, name.c_str ()))
2396 std::cout << locname << '\n';
2397
2398 return TRUE;
2399}
2400#endif
2401
2402// print the available locales
2403static void
2404print_locale_names ()
2405{
2406 std::cout << "C\n";
2407
2408 const char* const locale_root = std::getenv ("RWSTD_LOCALE_ROOT");
2409
2410 if (0 != locale_root) {
2411 const std::string cmd = std::string (LS_1) + locale_root;
2412
2413 std::system (cmd.c_str ());
2414 }
2415 else {
2416#ifndef _WIN32
2417 std::system ("/usr/bin/locale -a");
2418#else
2419 EnumSystemLocales (EnumLocales, LCID_INSTALLED);
2420#endif
2421 }
2422}
2423
2424
2425// print the available charmaps
2426static void
2427print_charmap_names ()
2428{
2429 const char* const locale_root = std::getenv ("RWSTD_SRC_ROOT");
2430
2431 if (0 != locale_root) {
2432 const std::string cmd =
2433 std::string (LS_1) + locale_root + SLASH "charmaps";
2434
2435 std::system (cmd.c_str());
2436 }
2437}
2438
2439
2441static void
2442print_help ()
2443{
2444 static const char* msg =
2445 "NAME\n\tlocale - get locale-specific information\n\n"
2446 "SYNOPSIS\n"
2447 "\tlocale [-a | -m | -? | --help | --charmap]\n\n"
2448 "\tlocale [-ckhlw] name ...\n\n"
2449 "DESCRIPTION\n"
2450 "\tThe locale utility writes information about the current\n"
2451 "\tlocale environment, or all public locales, to the standard\n"
2452 "\toutput. For the purposes of this section, a public locale is\n"
2453 "\tone provided by the implementation that is accessible to the\n"
2454 "\tapplication.\n\n"
2455 "\tWhen locale is invoked without any arguments, it summarizes\n"
2456 "\tthe current locale environment for each locale category as\n"
2457 "\tdetermined by the settings of the environment variables.\n\n"
2458 "\tWhen invoked with operands, it writes values that have been\n"
2459 "\tassigned to the keywords in the locale categories.\n\n"
2460 "OPTIONS\n"
2461 "\tThe following options are supported:\n\n"
2462 "\t-a\tWrite information about all available public locales.\n"
2463 "\t\tThe available locales include C, representing the\n"
2464 "\t\tPOSIX locale.\n\n"
2465 "\t-c\tWrite the names of selected locale categories.\n\n"
2466 "\t-k\tWrite the names and values of selected keywords.\n\n"
2467 "\t-m\tWrite names of available charmaps.\n\n"
2468 "\t-h\tIf available, use the original character map and \n"
2469 "\t\twrite the symbolic names instead of the character values\n\n"
2470 "\t-l\tWrite the locale information in a format readable by\n"
2471 "\t\tthe localedef utility\n\n"
2472 "\t-w\tTurn off all warning messages\n\n"
2473 "\t-w###\tTurn off a specific warning message\n\n"
2474 "\t-?\tWrite this message\n\n"
2475 "\t--help\tWrite this message\n\n"
2476 "\t--charmap\tWrite the character map.\n\n"
2477 "OPERANDS\n"
2478 "\tThe following operand is supported:\n\n"
2479 "\tname\tThe name of a locale category, the name of a keyword\n"
2480 "\t\tin a locale category, or the reserved name charmap.\n"
2481 "\t\tWhen charmap is specified, the utility writes the name\n"
2482 "\t\tof the character set description file or files used\n"
2483 "\t\tto create the current locale environment.\n\n";
2484
2485 std::cout << msg;
2486}
2487
2488
2490static void
2491print_ellipsis (const char *mbchar,
2492 unsigned last_byte [2],
2493 unsigned last_ucs4 [2],
2494 unsigned last_wchar [2])
2495{
2496 // close the ellipsis
2497 const int open_width = last_ucs4 [0] < 0x10000 ? 4 : 8;
2498 const int close_width = last_ucs4 [1] < 0x10000 ? 4 : 8;
2499
2500 // the number of spaces between the symbolic character name
2501 // and its multibyte character representation
2502 int pad = 28 - open_width;
2503
2504 const unsigned nchars = last_byte [1] - last_byte [0] + 1;
2505
2506 if (1 < nchars) {
2507
2508 pad -= close_width + 8;
2509
2510 // print the UCS code, followed by the MB character,
2511 // followed by the libc wchar_t value of the character
2512 std::printf ("<U%0*X>..<U%0*X>%*s%s\\x%02x "
2513 "# L'\\x%02x' (%u characters)\n",
2514 open_width, last_ucs4 [0],
2515 close_width, last_ucs4 [1], pad, " ",
2516 mbchar, last_byte [0], last_wchar [0],
2517 nchars);
2518 }
2519 else {
2520 pad -= 3;
2521
2522 std::printf ("<U%0*X>%*s%s\\x%02x "
2523 "# L'\\x%02x'\n",
2524 open_width, last_ucs4 [0], pad, " ",
2525 mbchar, last_byte [0], last_wchar [0]);
2526 }
2527
2528 last_byte [0] = last_byte [1] = UINT_MAX;
2529 last_ucs4 [0] = last_ucs4 [1] = 0;
2530 last_wchar [0] = last_wchar [1] = 0;
2531}
2532
2533// traverses codeset conversion tables and prints out the character
2534// map in POSIX format with the internal wchar_t encoding in comments
2535// collects space utilization statistics
2536static void
2537print_charmap (const __rw::__rw_codecvt_t *cvt,
2538 char *mbchar,
2539 const unsigned *tab,
2540 unsigned *ntables,
2541 unsigned *nchars,
2542 unsigned *nunused)
2543{
2544 const unsigned* const table = cvt->n_to_w_tab ();
2545
2546 if (!tab)
2547 tab = table;
2548
2549 // the length of the multibyte character (prefix) formatted
2550 // in a human-readable form (e.g., "\x80\xff" or similar)
2551 const std::size_t mbchar_len = std::strlen (mbchar);
2552
2553 // index into the array of counters corresponding to the
2554 // table being processed at this level of recursion
2555 const std::size_t count_inx = mbchar_len / 4 + 1;
2556
2557 if (ntables) {
2558 // increment the grand total of all tables
2559 ++ntables [0];
2560 // increment the number of tables for characters
2561 // of this length
2562 ++ntables [count_inx];
2563 }
2564
2565 unsigned last_byte [2] = { UINT_MAX, 0 };
2566 unsigned last_ucs4 [2] = { 0, 0 };
2567 unsigned last_wchar [2] = { 0, 0 };
2568
2569 // print out all multibyte characters in this map
2570 for (unsigned i = 0; i != UCHAR_MAX + 1U; ++i) {
2571
2572 if (tab [i] & 0x80000000) {
2573
2574 if (last_byte [0] <= UCHAR_MAX) {
2575 // print the last character or ellipsis
2576 print_ellipsis (mbchar, last_byte, last_ucs4, last_wchar);
2577 }
2578
2579 // skip invalid character or next table
2580 continue;
2581 }
2582
2583 // look up the UCS-4 and the wchar_t value of the MB character
2584 const unsigned ucs4 = cvt->get_ucs4_at_offset (tab [i]);
2585 const unsigned wchar = cvt->get_internal_at_offset (tab [i]);
2586
2587 if (UCHAR_MAX < last_byte [0]) {
2588 last_byte [0] = i;
2589 last_ucs4 [0] = ucs4;
2590 last_wchar [0] = wchar;
2591 }
2592 else if (1 < ucs4 - last_ucs4 [1] || 1 < wchar - last_wchar [1]) {
2593 // print the last character or ellipsis
2594 print_ellipsis (mbchar, last_byte, last_ucs4, last_wchar);
2595
2596 last_byte [0] = i;
2597 last_ucs4 [0] = ucs4;
2598 last_wchar [0] = wchar;
2599 }
2600
2601 last_byte [1] = i;
2602 last_ucs4 [1] = ucs4;
2603 last_wchar [1] = wchar;
2604
2605 if (nchars) {
2606 // increment the grand total of all characters
2607 ++nchars [0];
2608
2609 // increment the number of multibyte characters
2610 // of this length
2611 ++nchars [count_inx];
2612 }
2613 }
2614
2615 if (last_byte [0] <= UCHAR_MAX)
2616 print_ellipsis (mbchar, last_byte, last_ucs4, last_wchar);
2617
2618 // process subsequent maps
2619 for (unsigned i = 0; i != UCHAR_MAX + 1U; ++i) {
2620
2621 if (UINT_MAX == tab [i]) {
2622 // invalid multibyte sequence (i.e., unused slot)
2623
2624 if (nunused) {
2625 // increment counters
2626 ++nunused [0];
2627 ++nunused [count_inx];
2628 }
2629
2630 continue;
2631 }
2632
2633 if (!(tab [i] & 0x80000000)) {
2634 // valid multibyte characater already printed out above
2635 continue;
2636 }
2637
2638 // invoke self recursively to print out the contents
2639 // of the next map
2640 std::sprintf (mbchar + mbchar_len, "\\x%02x", i);
2641
2642 print_charmap (cvt, mbchar, table + 256 * (tab [i] & 0x7fffffff),
2643 ntables, nchars, nunused);
2644
2645 mbchar [mbchar_len] = '\0';
2646 }
2647}
2648
2649
2650// print out the contents of the __rw_codecvt_t structure
2651static void
2652print_charmap (const __rw::__rw_codecvt_t *cvt = 0)
2653{
2654 if (0 == cvt) {
2655 // use the codecvt map when none is specified
2656 cvt = codecvt_st;
2657 }
2658
2659 if (0 == cvt)
2660 return;
2661
2662 std::cout << "<escape_char> \\"
2663 << "\n<comment_char> #"
2664 << "\n<code_set_name> " << cvt->codeset_name ()
2665 << "\n<mb_cur_max> " << int (cvt->mb_cur_max)
2666 << "\nCHARMAP\n";
2667
2668 if (decode) {
2669 std::cout << "# charmap data:"
2670 << "\n# charmap name: "
2671 << cvt->charmap_name ()
2672 << "\n# n_to_w_tab_off: "
2673 << cvt->n_to_w_tab_off
2674 << "\n# w_to_n_tab_off: "
2675 << cvt->w_to_n_tab_off
2676 << "\n# utf8_to_ext_tab_off: "
2677 << cvt->utf8_to_ext_tab_off
2678 << "\n# xliteration_off: "
2679 << cvt->xliteration_off
2680 << "\n# wchar_off: "
2681 << cvt->wchar_off
2682 << "\n# codeset_off: "
2683 << cvt->codeset_off
2684 << "\n# charmap_off: "
2685 << cvt->charmap_off
2686 << "\n# codecvt_ext_off: "
2687 << cvt->codecvt_ext_off
2688 << '\n';
2689 }
2690
2691 char buf [1024];
2692 *buf = '\0';
2693
2694 // total number of conversion tables for characters
2695 // of each length up to MB_CUR_MAX with ntables being
2696 // the sum of all of them
2697 unsigned ntables [64] = { 0 };
2698
2699 // total number of unused slots in tables at each level
2700 // (i.e., slots not used either to encode character or
2701 // to store an offset to the next table)
2702 unsigned nunused [64] = { 0 };
2703
2704 // total numbers of multibyte characters of each lenght
2705 // up to MB_CUR_MAX with nchars [0] being the sum of all
2706 // of them
2707 unsigned nchars [64] = { 0 };
2708
2709 print_charmap (cvt, buf, 0, ntables, nchars, nunused);
2710
2711 std::cout << "END CHARMAP\n"
2712 << "\n# charmap stats:";
2713
2714 for (std::size_t i = 1; i != sizeof nchars / sizeof *nchars; ++i) {
2715 if (0 != nchars [i] || 0 != ntables [i]) {
2716
2717 const double waste =
2718 (100.0 * nunused [i]) / (ntables [i] * UCHAR_MAX);
2719
2720 std::cout << "\n# ";
2721 std::cout << i << " byte characters: " << nchars [i]
2722 << " (" << ntables [i] << " tables, "
2723 << unsigned (waste) << "% waste)";
2724 }
2725 }
2726
2727 const double waste = (100.0 * nunused [0]) / (ntables [0] * UCHAR_MAX);
2728
2729 std::cout << "\n# total characters: " << nchars [0]
2730 << " (" << ntables [0] << " tables, "
2731 << unsigned (waste) << "% waste)\n";
2732}
2733
2734
2736// print the value of a single localization environment variable
2737// according to POSIX rules
2738static void
2739print_lc_var (const char* cat_name, const char* val,
2740 const char *lc_all, const char *lang)
2741{
2742 std::cout << cat_name << '=';
2743
2744 if (0 == val)
2745 std::cout << '"';
2746
2747 const char* const strval =
2748 (lc_all ? lc_all : val ? val : lang ? lang : "");
2749
2750 // POSIX requires that environment variable "values be properly
2751 // quoted for possible later reentry to the shell"
2752 for (const char* s = strval; *s; ++s) {
2753 switch (*s) {
2754 case '$': case '"':
2755 // escape unconditionally
2756 std::cout << '\\' << *s; break;
2757
2758 case '|': case '&': case '\\': case '<': case '>':
2759 case '`': case ' ':
2760 // escape only when not quoted
2761 if (val) std::cout << '\\' << *s;
2762
2763 default:
2764 // do not escape
2765 std::cout << *s;
2766 }
2767 }
2768
2769 if (0 == val)
2770 std::cout << '"';
2771
2772 std::cout << '\n';
2773}
2774
2775
2777// print the values of the LANG and LC_XXX environment variables
2778// according to POSIX rules
2779static void
2780print_lc_vars ()
2781{
2782 const char* const lang = std::getenv ("LANG");
2783 const char* const lc_all = std::getenv (sect_lc_all);
2784 const char* const lc_collate = std::getenv (sect_lc_collate);
2785 const char* const lc_ctype = std::getenv (sect_lc_ctype);
2786 const char* const lc_messages = std::getenv (sect_lc_messages);
2787 const char* const lc_monetary = std::getenv (sect_lc_monetary);
2788 const char* const lc_numeric = std::getenv (sect_lc_numeric);
2789 const char* const lc_time = std::getenv (sect_lc_time);
2790
2791 print_lc_var ("LANG", lang ? lang : "", 0, 0);
2792 print_lc_var (sect_lc_ctype, lc_ctype, lc_all, lang);
2793 print_lc_var (sect_lc_collate, lc_collate, lc_all, lang);
2794 print_lc_var (sect_lc_time, lc_time, lc_all, lang);
2795 print_lc_var (sect_lc_monetary, lc_monetary, lc_all, lang);
2796 print_lc_var (sect_lc_numeric, lc_numeric, lc_all, lang);
2797 print_lc_var (sect_lc_messages, lc_messages, lc_all, lang);
2798 print_lc_var (sect_lc_all, lc_all ? lc_all : "", 0, 0);
2799}
2800
2801
2803static const struct {
2804 const char *name;
2805 int (*print)(const char*, int);
2806 int arg;
2807} handlers[] = {
2808
2809 { sect_lc_time, print_lc_time, 0 },
2810 { sect_lc_monetary, print_lc_monetary, 0 },
2811 { sect_lc_numeric, print_lc_numeric, 0 },
2812 { sect_lc_ctype, print_lc_ctype, 0 },
2813 { sect_lc_collate, print_lc_collate, 0 },
2814 { sect_lc_messages, print_lc_messages, 0 },
2815 { sect_lc_all, print_lc_all, 0 },
2816
2817 { "abday", print_abday, -1 },
2818 { "day", print_day, -1 },
2819 { "abmon", print_abmon, -1 },
2820 { "mon", print_mon, -1 },
2821 { "am_pm", print_am_pm, -1 },
2822 { "d_t_fmt", print_d_t_fmt, -1 },
2823 { "t_fmt", print_t_fmt, -1 },
2824 { "d_fmt", print_d_fmt, -1 },
2825 { "t_fmt_ampm", print_t_fmt_ampm, -1 },
2826 { "era_d_t_fmt", print_era_d_t_fmt, -1 },
2827 { "era_t_fmt", print_era_t_fmt, -1 },
2828 { "era_d_fmt", print_era_d_fmt, -1 },
2829 { "era", print_era, -1 },
2830 { "alt_digits", print_alt_digits, -1 },
2831 { "yesexpr", print_yesexpr, -1 },
2832 { "noexpr", print_noexpr, -1 },
2833 { "int_curr_symbol", print_int_curr_symbol, -1 },
2834 { "currency_symbol", print_currency_symbol, -1 },
2835 { "mon_decimal_point", print_mon_decimal_point, -1 },
2836 { "mon_thousands_sep", print_mon_thousands_sep, -1 },
2837 { "mon_grouping", print_mon_grouping, -1 },
2838 { "positive_sign", print_positive_sign, -1 },
2839 { "negative_sign", print_negative_sign, -1 },
2840 { "int_frac_digits", print_int_frac_digits, -1 },
2841 { "frac_digits", print_frac_digits, -1 },
2842 { "p_cs_precedes", print_p_cs_precedes, -1 },
2843 { "p_sep_by_space", print_p_sep_by_space, -1 },
2844 { "n_cs_precedes", print_n_cs_precedes, -1 },
2845 { "n_sep_by_space", print_n_sep_by_space, -1 },
2846 { "p_sign_posn", print_p_sign_posn, -1 },
2847 { "n_sign_posn", print_n_sign_posn, -1 },
2848 { "int_p_cs_precedes", print_int_p_cs_precedes, -1 },
2849 { "int_p_sep_by_space", print_int_p_sep_by_space, -1 },
2850 { "int_n_cs_precedes", print_int_n_cs_precedes, -1 },
2851 { "int_n_sep_by_space", print_int_n_sep_by_space, -1 },
2852 { "int_p_sign_posn", print_int_p_sign_posn, -1 },
2853 { "int_n_sign_posn", print_int_n_sign_posn, -1 },
2854 { "decimal_point", print_decimal_point, -1 },
2855 { "thousands_sep", print_thousands_sep, -1 },
2856 { "grouping", print_grouping, -1 },
2857 { "upper", print_mask, std::ctype_base::upper },
2858 { "lower", print_mask, std::ctype_base::lower },
2859 { "space", print_mask, std::ctype_base::space },
2860 { "print", print_mask, std::ctype_base::print },
2861 { "cntrl", print_mask, std::ctype_base::cntrl },
2862 { "alpha", print_mask, std::ctype_base::alpha },
2863 { "digit", print_mask, std::ctype_base::digit },
2864 { "punct", print_mask, std::ctype_base::punct },
2865 { "graph", print_mask, std::ctype_base::graph },
2866 { "xdigit", print_mask, std::ctype_base::xdigit },
2867 { "tolower", print_tolower, -1 },
2868 { "toupper", print_toupper, -1 },
2869 { "charmap", print_charmap_name, 0 },
2870
2871 // sentinel
2872 { 0, 0, 0 }
2873};
2874
2875
2876int locale_main (int argc, char *argv[])
2877{
2878 const char* const program_name = argv [0];
2879
2880 if (1 == argc) {
2881 // print all localization environment variables
2882 print_lc_vars ();
2883 }
2884 else {
2885 init_sections ();
2886
2887 --argc;
2888
2889 while (0 != *++argv && 0 < argc-- && '-' == **argv) {
2890
2891 switch (*++*argv) {
2892
2893 case 'a':
2894 // -a: print the names of all installed locales
2895 print_locale_names ();
2896 return EXIT_SUCCESS;
2897
2898 case 'k':
2899 // -k: print the names of keywords when printing
2900 // their values
2901 print_keywords = true;
2902 break;
2903
2904 case 'c':
2905 // -c[k]: print the name of each section
2906 print_sect_names = true;
2907 if (*(*argv + 1) == 'k')
2908 print_keywords = true;
2909 break;
2910
2911 case 'm':
2912 print_charmap_names ();
2913 return EXIT_SUCCESS;
2914
2915 case 'h':
2916 // -h: use character names from the original charmap
2917 // used by localedef to build the locale (if possible)
2918 decode = true;
2919 break;
2920
2921 case 'l':
2922 // -l: produce output suitable as input for processing
2923 // by the localedef utility
2924 posix_output = false;
2925 break;
2926
2927 case 'p':
2928 // -p: produce output using symbols from the Portable
2929 // Character Set whenever possible
2930 use_pcs = true;
2931 posix_output = false;
2932 break;
2933
2934 case 'w':
2935 if (std::strlen (*argv) == 1)
2936 issue_diag (W_DISABLE, 0, 0, 0);
2937 else
2938 issue_diag (std::atoi (++*argv), 0, 0, 0);
2939 break;
2940
2941 case '?':
2942 print_help ();
2943 return EXIT_SUCCESS;
2944
2945 case '-':
2946 if (0 == std::strcmp (*argv, "-help")) {
2947 print_help ();
2948 return EXIT_SUCCESS;
2949 }
2950
2951 if (0 == std::strcmp (*argv, "-charmap")) {
2952 print_charmap ();
2953 return EXIT_SUCCESS;
2954 }
2955
2956 // fall through...
2957
2958 default:
2959 issue_diag (504, true, 0, "%s: invalid option "
2960 "-%s\n", program_name, *argv);
2961 }
2962 }
2963
2964 if (0 == *argv) {
2965 issue_diag (505, true, 0, "%s: missing argument\n Try '"
2966 "%s --help'\n", program_name, program_name);
2967 }
2968
2969 for (; 0 != *argv; ++argv) {
2970
2971 for (std::size_t i = 0; handlers [i].name; ++i) {
2972 if (0 == std::strcmp (*argv, handlers [i].name)) {
2973
2974 const int arg =
2975 -1 == handlers [i].arg ? print_sect_names
2976 : handlers [i].arg;
2977
2978 handlers [i].print (handlers [i].name, arg);
2979 }
2980 }
2981 }
2982 }
2983
2984 return EXIT_SUCCESS;
2985}
const char print[]
void count(T, T, const U &,...)
#define i
Definition 17.names.cpp:126
#define k
Definition 17.names.cpp:128
#define nchars
Definition 17.names.cpp:502
#define msg
Definition 17.names.cpp:498
#define ptr
Definition 17.names.cpp:525
#define last
Definition 17.names.cpp:487
#define x
Definition 17.names.cpp:140
#define buf
Definition 17.names.cpp:452
#define j
Definition 17.names.cpp:127
#define offset
Definition 17.names.cpp:508
#define addr
Definition 17.names.cpp:446
#define s
#define val
Definition 17.names.cpp:570
#define pos
Definition 17.names.cpp:518
const char * locale_root
#define open(f, m)
const int end
const int out
const int cur
#define assert(expr)
Definition _cassert.h:40
#define NULL
#define LC_CTYPE
#define LC_NUMERIC
#define LC_MONETARY
#define LC_ALL
#define LC_TIME
#define LC_COLLATE
#define _RWSTD_PATH_SEP
Definition _config.h:297
#define EXIT_SUCCESS
#define _RWSTD_STATIC_CAST(T, x)
Definition _defs.h:534
char * get_installed_locales(int loc_cat)
Definition aliases.cpp:542
void get_cname_aliases(const std::string &name, StringVector &aliases)
Definition aliases.cpp:392
std::string get_C_encoding_locale(const std::string &codeset)
Definition aliases.cpp:498
#define MAP_PRIVATE
Definition alloc.cpp:166
const std::map< unsigned char, std::string > & get_rn_cmap() const
Definition charmap.h:65
static const char *const portable_charset[]
Definition charmap.h:261
const std::map< wchar_t, std::string > & get_rw_cmap() const
Definition charmap.h:77
const std::map< std::string, wchar_t > & get_mb_cmap() const
Definition charmap.h:83
A TOML table.
Definition table.hpp:190
const char * name
Definition codecvt1.cpp:72
bool issue_diag(int type, bool, const Scanner::token_t *token, const char *fmt,...)
@ W_CHARMAP
Definition diagnostic.h:71
@ W_DISABLE
Definition diagnostic.h:62
@ E_INVAL
Definition diagnostic.h:52
@ W_CHAR
Definition diagnostic.h:70
const char * str
Definition exec.cpp:170
#define INT_MIN
Definition limits.h:80
#define UCHAR_MAX
Definition limits.h:60
#define INT_MAX
Definition limits.h:76
#define UINT_MAX
Definition limits.h:84
size_t strchk(const char *str)
Definition memchk.cpp:232
size_t memchk(const void *addr, size_t nbytes)
Definition memchk.cpp:108
#define MAP_FAILED
unsigned char UChar
Definition collate.cpp:122
#define MAX_LINE_LEN
Definition locale.cpp:152
const FacetData * init_section(const std::string &loc_path_root, const char *cat_name, const char *codeset_name, FacetData *)
Definition locale.cpp:289
unsigned char UChar
Definition locale.cpp:155
#define SLASH
Definition locale.cpp:49
#define LC_MESSAGES
Definition locale.cpp:99
int locale_main(int argc, char *argv[])
Definition locale.cpp:2876
#define LS_1
Definition locale.cpp:50
const char * name
Definition locale.cpp:2804
const void * init_struct(const std::string &loc_path_root, const char *cat_name, const char *codeset_name)
Definition locale.cpp:206
int validate(const void *addr, std::size_t nbytes)
Definition locale.cpp:159
#define MON_INT(member)
Definition locale.cpp:1653
int arg
Definition locale.cpp:2806