Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
localedef.cpp
Go to the documentation of this file.
1
29#include "aliases.h"
30#include "def.h" // for Def
31#include "diagnostic.h" // for issue_diag()
32#include "loc_exception.h" // for loc_exception
33#include "path.h"
34
35#include <fstream> // for ifstream
36#include <iostream> // for cerr
37#include <string> // for string
38#include <vector> // for vector
39
40#include <clocale> // for setlocale(), LC_XXX
41#include <cstdlib> // for atoi()
42#include <cstring> // for strcmp()
43
44
45// exit status
46#define EXIT_OK 0
47#define EXIT_ERRORS 4
48
49
50// charmaps holds pointers to the character maps being used to generate
51// the locales.
52static std::vector<Charmap*> charmaps;
53
54
55static void
56print_help_msg ()
57{
58 static const char msg[] =
59 "NAME\n"
60 "\tlocaledef - generate a locale environment\n"
61 "\n"
62 "SYNOPSIS\n"
63 "\tlocaledef [-c][-w[###]][-f charmap_file][-i locale_defintion]\n"
64 "\t\tlocale_name\n"
65 "\n"
66 "\tlocaledef -g [-m creation_list]\n"
67 "\t\t[-d output_dir][-r charmap_dir][-s src_dir][--ucs]\n"
68 "\n"
69 "DESCRIPTION\n"
70 "\tThe localedef utility sets up the language environment for the\n"
71 "\tnamed locale. localedef reads a locale definition file from\n"
72 "\tstandard input or from locale_definition file and creates a\n"
73 "\tlocale database with the name specified on the command line.\n"
74 "\n"
75 "OPTIONS\n"
76 "\tThe localedef utility recognizes the following options:\n"
77 "\n"
78 "\t-c\tCreate output irrespective of warnings.\n"
79 "\n"
80 "\t-f charmap_file\n"
81 "\t\tIf the locale definition uses symbolic names use charmap_file.\n"
82 "\n"
83 "\t-i locale_definition\n"
84 "\t\tUse locale_definition as input, instead of standard input\n"
85 "\t\t(default).\n"
86 "\n"
87 "\t-g\tGenerate all the locales listed in the creation list.\n"
88 "\n"
89 "\t--ucs\tUse UCS for the internal (wchar_t) encoding."
90 "\n"
91 "\n\t-m creation_list\n"
92 "\t\tSpecify a file that lists what combinations of charmaps and\n"
93 "\t\tsource files should be used to create a locale.\n"
94 "\n"
95 "\t-r charmap_dir\n"
96 "\t\tSpecify the directory where the character maps are located.\n"
97 "\n"
98 "\t-s src_dir\n"
99 "\t\tSpecify the directory where the source files are located.\n"
100 "\n"
101 "\t-d output_dir\n"
102 "\t\tSpecify the directory where the generated locale database\n"
103 "\t\tfiles should be placed.\n"
104 "\n"
105 "\t-w\tDisable all warning messages.\n"
106 "\n"
107 "\t-w###\n"
108 "\t\tDisable warning number ###.\n"
109 "\n"
110 "\t--notes\tEnable notes (informational messages).\n"
111 "\t-?\n"
112 "\t--help\tPrint out this message.\n";
113
114 std::cout << msg;
115}
116
117
118static void
119create_locale (std::string std_src,
120 std::string std_cmap,
121 std::string outdir,
122 std::string std_locale,
123 bool force_output, bool use_ucs,
124 bool no_position, bool link_aliases)
125{
126 // extract the names of the locale and of the codeset
127 std::string lname (std_src);
128 std::string cname (std_cmap);
129
130 if (lname.rfind(_RWSTD_PATH_SEP) != std::string::npos)
131 lname = lname.substr(lname.rfind(_RWSTD_PATH_SEP) + 1, lname.size());
132
133 if (cname.rfind(_RWSTD_PATH_SEP) != std::string::npos)
134 cname = cname.substr(cname.rfind(_RWSTD_PATH_SEP) + 1, cname.size());
135
136 if (lname.find('.') != std::string::npos)
137 lname = lname.substr(0, lname.find('.'));
138 if (cname.find('.') != std::string::npos)
139 cname = cname.substr(0, cname.find('.'));
140
141 // the vector of corresponding C locales
142 StringVector C_locales;
143#ifndef _WIN32
144 get_same_encoding_C_locale (lname, cname, C_locales);
145#endif // _WIN32
146
147 // C library locale using same encoding
148 std::string enc_C_locale;
149
150#ifdef _RWSTD_NO_ISO_10646_WCHAR_T
151 // the encoding C locale
152 enc_C_locale = get_C_encoding_locale (cname);
153
154 // platforms with locale dependant wchar_t encodings need the current
155 // C locale to be set. If there is no C locale with the same name
156 // or that uses the same encoding as the locale we are creating
157 // issue warning
158 if (enc_C_locale.empty ()) {
159 issue_diag (W_COMPAT, false, 0, "no compatible locale found\n");
160 } else
161 std::setlocale (LC_ALL, enc_C_locale.c_str ());
162
163#endif // _RWSTD_NO_ISO_10646_WCHAR_T
164
165 // if no charmap is present assume ISO-8859-1
166 if (std_cmap.empty ())
167 std_cmap = "ISO-8859-1";
168
169 // retrieve UTF-8 encoding aliases
170 std::string utf8_cname("UTF-8");
171 StringVector utf8_aliases;
172 get_cname_aliases (utf8_cname, utf8_aliases);
173
174 // is it a UTF-8 encoded locale?
175 bool is_utf8 = false;
176 StringVector::iterator pos = utf8_aliases.begin();
177 for (; pos != utf8_aliases.end (); pos++)
178 if (ci_compare (cname, *pos) == 0) {
179 is_utf8 = true;
180 break;
181 }
182
183 // retrieve the charmap/codeset object
184 Charmap* charmap_p = 0;
185 std::vector <Charmap*>::iterator charmaps_it = charmaps.begin();
186 for (; charmaps_it != charmaps.end(); charmaps_it++){
187 if ((*charmaps_it)->get_full_charmap_name() == std_cmap) {
188 charmap_p = *charmaps_it;
189 break;
190 }
191 }
192
193 // if none found, create one and parse the corresponding file
194 if (0 == charmap_p) {
195
196 issue_diag (I_STAGE, false, 0,
197 "processing character set description file %s\n",
198 std_cmap.c_str ());
199
200 charmap_p = new Charmap (enc_C_locale.c_str (),
201 std_cmap.c_str (),
202 is_utf8, true, true, use_ucs);
203 charmaps.push_back (charmap_p);
204 }
205
206 // parse the source definition files
207 bool def_error = false;
208
209 issue_diag (I_STAGE, false, 0,
210 "processing locale definition file %s\n", std_src.c_str ());
211
212 Def def (std_src.c_str (), (outdir + std_locale).c_str (),
213 *charmap_p, no_position);
214
215 try {
216 // try to parse the input files
217 def.process_input ();
218 }
219 catch (...) {
220 def_error = true;
221 }
222
223 // create the locale directory
224 std::string locale_dir (outdir + std_locale);
225
226 makedir (locale_dir.c_str ());
227
228 if (def_error) {
229 // write out the codecvt database and exit if parsing failed
230 def.write_codecvt (locale_dir);
231 throw loc_exception ("abort.");
232 }
233
234 // no output when it hasn't been forced and warnings were present
235 if (!force_output && def.warnings_occurred_) {
236 std::cerr << "Warnings occurred - No output produced\n";
237 return;
238 }
239
240 // and write out the locale categories data
241 issue_diag (I_STAGE, false, 0, "generating LC_CTYPE database\n");
242 def.write_ctype (locale_dir);
243
244 issue_diag (I_STAGE, false, 0, "generating codeset database\n");
245 def.write_codecvt (locale_dir);
246
247 issue_diag (I_STAGE, false, 0, "generating LC_MONETARY database\n");
248 def.write_monetary (locale_dir);
249
250 issue_diag (I_STAGE, false, 0, "generating LC_NUMERIC database\n");
251 def.write_numeric (locale_dir);
252
253 issue_diag (I_STAGE, false, 0, "generating LC_TIME database\n");
254 def.write_time (locale_dir);
255
256 issue_diag (I_STAGE, false, 0, "generating LC_COLLATE database\n");
257 def.write_collate (locale_dir);
258
259#ifndef _WIN32
260
261 issue_diag (I_STAGE, false, 0, "generating LC_MESSAGES database\n");
262 def.write_messages (locale_dir);
263
264#endif // _WIN32
265
266 // no C library locales equivalents
267 if (C_locales.empty ())
268 return;
269
270#if !defined (_WIN32) && !defined (__CYGWIN__)
271
272 if (link_aliases == false)
273 return;
274
275 // some corresponding C lib locale names where found for this name
276 StringVector::iterator it = C_locales.begin ();
277 for (; it != C_locales.end (); it++) {
278 // check if the name actually exists
279 if (*it == std_locale)
280 continue;
281
282 // set a symlink with the name of the C lib locale
283 // pointing to our locale database
284 create_symlink (outdir, std_locale, *it);
285 }
286#endif // !_WIN32 && !__CYGWIN__
287}
288
289
290static void
291generate_locales (const char* map_name, const char* /*alias_name*/,
292 const char* charmap_dir, const char* src_dir,
293 const char* output_dir, bool use_ucs,
294 bool no_position, bool link_aliases)
295{
296 std::ifstream f (map_name);
297
298 if (!f) {
299 issue_diag (E_OPENRD, true, 0,
300 "the generation list '%s' "
301 "could not be opened\n", map_name);
302 return;
303 }
304
305 while (f) {
306 std::string s1;
307 std::string s2;
308
309 f >> s1 >> s2;
310 if (f) {
311 std::string lname = s1.substr (0, s1.find('.'));
312 std::string cname = s2.substr (0, s2.find('.'));
313
314 // our name for a locale database is <locale>.<codeset>
315 std::string std_locale(lname + "." + cname);
316
317 // create the locale database
318 std::cout << "creating locale " << std_locale << '\n';
319 try {
320 create_locale ((std::string(src_dir) + s1),
321 (std::string(charmap_dir) + s2),
322 std::string (output_dir), std_locale,
323 true, use_ucs, no_position, link_aliases);
324
325 }
326 catch (const std::ios::failure& error) {
327 std::cerr << "I/O exception " << error.what() << '\n';
328 }
329 catch (loc_exception& e) {
330 std::cerr << "Unable to create locale " << std_locale
331 << " : " << e.what () << '\n';
332 }
333 catch (const std::exception& error) {
334 std::cerr <<"ERROR: " << error.what() << '\n';
335 }
336 catch (...) {
337 std::cerr << "Unable to create locale " << std_locale
338 << '\n';
339 }
340 }
341 }
342}
343
344
346{
347 const char* program_name;
348 const char* charmap_name;
349 const char* source_name;
350 const char* map_file;
351 const char* alias_file;
352 const char* locale_name;
353
354 std::string charmap_dir;
355 std::string src_dir;
356 std::string output_dir;
357
358 bool gen;
363};
364
365
366static bool
367process_command_line (ProgramOptions *opts, int argc, char* argv[])
368{
369 opts->program_name = argv [0];
370 opts->charmap_name = "";
371 opts->source_name = "";
372 opts->map_file = 0;
373 opts->alias_file = 0;
374 opts->locale_name = 0;
375
376 opts->gen = false;
377 opts->force_output = false;
378 opts->use_ucs = false;
379 opts->no_position = false;
380 opts->link_aliases = false;
381
382 int i; // index of command line argument being processed
383
384 for (i = 1; i < argc && '-' == argv [i][0]; ++i) {
385
386 switch (argv [i][1]) {
387
388 case 'f': // set character set description file name
389 if (argv [i + 1])
390 opts->charmap_name = argv [++i];
391 break;
392
393 case 'i': // set locale definition file name
394 if (argv [i + 1])
395 opts->source_name = argv [++i];
396 break;
397
398 case 'c': // create output even if warnings are issued
399 opts->force_output = true;
400 break;
401
402 case 'g': // generate more than one locale database
403 opts->gen = true;
404 break;
405
406 case 'm':
407 if (argv [i + 1])
408 opts->map_file = argv [++i];
409 break;
410
411 case 'a':
412 if (argv [i + 1])
413 opts->alias_file = argv [++i];
414 break;
415
416 case 'r':
417 if (argv [i + 1])
418 opts->charmap_dir = argv [++i];
419 break;
420
421 case 's':
422 if (argv [i + 1])
423 opts->src_dir = argv [++i];
424 break;
425
426 case 'd':
427 if (argv [i + 1])
428 opts->output_dir = argv [++i];
429 break;
430
431 case 'w': // disable one or all warnings
432 if (argv [i][2])
433 issue_diag (std::atoi (argv [i] + 2), false, 0, 0);
434 else
435 issue_diag (W_DISABLE, false, 0, 0);
436 break;
437
438 case '?':
439 print_help_msg ();
440 return false;
441
442 case '-':
443 if (0 == std::strcmp (argv [i] + 2, "help")) {
444 print_help_msg ();
445 return false;
446 }
447
448 if (0 == std::strcmp (argv [i] + 2, "ucs")) {
449 // --ucs: use UCS as the internal wchar_t encoding
450 opts->use_ucs = true;
451 break;
452 }
453 else if (0 == std::strcmp (argv [i] + 2, "no_position")) {
454 opts->no_position = true;
455 break;
456 }
457 else if (0 == std::strcmp (argv [i] + 2, "aliases")) {
458 opts->link_aliases = true;
459 break;
460 }
461 else if (0 == std::strcmp (argv [i] + 2, "notes")) {
462 // --notes: enable informational messages (notes)
463 issue_diag (I_ENABLE, false, 0, 0);
464 break;
465 }
466 // fall through
467
468 default:
469 issue_diag (E_CMDARG, true, 0, "invalid option %s\n", argv [i]);
470 }
471 }
472
473 if (opts->gen) {
474
475 bool errors = false;
476
477 // make sure that all the required options are specified
478 if (0 == opts->map_file) {
479 issue_diag (E_NOARG, true, 0,
480 "option %s requires a string argument\n", "-m");
481 }
482
483 if (opts->charmap_dir.empty ()) {
484 issue_diag (E_NOARG, true, 0,
485 "option %s requires a string argument\n", "-r");
486 }
487
488 if (opts->src_dir.empty ()) {
489 issue_diag (E_NOARG, true, 0,
490 "option %s requires a string argument\n", "-s");
491 }
492
493 if (opts->output_dir.empty ()) {
494 issue_diag (E_NOARG, true, 0,
495 "option %s requires a string argument\n", "-d");
496 }
497
498 // append a slash to the directories if the user didn't
499 if (opts->output_dir [opts->output_dir.size () - 1] != _RWSTD_PATH_SEP)
501
502 if (opts->src_dir [opts->src_dir.size () - 1] != _RWSTD_PATH_SEP)
503 opts->src_dir += _RWSTD_PATH_SEP;
504
505 if (opts->charmap_dir [opts->charmap_dir.size () - 1] != _RWSTD_PATH_SEP)
507 }
508
509 if (0 == argv [i] && !opts->gen) {
510 issue_diag (E_NOARG, true, 0, "missing command line argument\n");
511 }
512
513 opts->locale_name = argv [i];
514
515 if (argv [i + 1]) {
516 issue_diag (E_XARG, true, 0,
517 "extra command line arguments after %s\n", argv [i]);
518 }
519
520 return true;
521}
522
523
524int localedef_main (int argc, char *argv[])
525{
526 ProgramOptions opts;
527
528 if (!process_command_line (&opts, argc, argv))
529 return EXIT_OK;
530
531 if (opts.gen) {
532 // create the locale databases as specified in generation list
533 generate_locales (opts.map_file, opts.alias_file,
534 opts.charmap_dir.c_str (),
535 opts.src_dir.c_str (),
536 opts.output_dir.c_str (),
537 opts.use_ucs,
538 opts.no_position,
539 opts.link_aliases);
540 }
541 else {
542 assert (0 != opts.locale_name);
543
544 // C++ locale name requested
545 std::string std_locale (opts.locale_name);
546
547 // retrieve the output directory if any
548 std::string std_outdir ("");
549
550 if (std_locale.rfind (_RWSTD_PATH_SEP) != std::string::npos) {
551 std_outdir =
552 std_locale.substr (
553 0, std_locale.rfind (_RWSTD_PATH_SEP) + 1);
554
555 std_locale =
556 std_locale.substr (std_locale.rfind (_RWSTD_PATH_SEP) + 1,
557 std_locale.size ());
558 }
559
560 // create the locale database
562 std_outdir, std_locale,
563 opts.force_output, opts.use_ucs,
564 opts.no_position, opts.link_aliases);
565 }
566
567 return EXIT_OK;
568}
569
570
571// defined in locale.cpp
572int locale_main (int, char*[]);
573
574
575int main (int argc, char *argv[])
576{
577 int exit_status = EXIT_OK;
578
579 try {
580
581 if (1 < argc && 0 == std::strcmp (argv [1], "--locale-mode")) {
582
583 // invoked with the special option ""--locale-mode"
584 // to act like the locale utility
585
586 // remove argv [1] from command line
587 for (int i = 2; argv [i]; ++i)
588 argv [i - 1] = argv [i];
589
590 // NULL-terminate argv
591 argv [argc - 1] = 0;
592
593 exit_status = locale_main (argc - 1, argv);
594 }
595 else {
596 exit_status = localedef_main (argc, argv);
597 }
598 }
599 catch (const std::ios::failure& error) {
600 std::cerr << "Error: I/O exception: " << error.what () << '\n';
602 }
603 catch (loc_exception&) {
605 }
606 catch (const std::exception& error) {
607 std::cerr <<"Error: " << error.what () << '\n';
609 }
610 catch (...) {
611 std::cerr << "Error: unknown exception\n";
613 }
614
615 return exit_status;
616}
int exit_status
#define i
Definition 17.names.cpp:126
#define s1
Definition 17.names.cpp:242
#define e
Definition 17.names.cpp:118
#define msg
Definition 17.names.cpp:498
#define s2
Definition 17.names.cpp:268
#define f
Definition 17.names.cpp:119
#define pos
Definition 17.names.cpp:518
const char *const errors[]
Definition 19.cerrno.cpp:34
const char * create_locale()
#define main
#define assert(expr)
Definition _cassert.h:40
#define LC_ALL
#define _RWSTD_PATH_SEP
Definition _config.h:297
void get_same_encoding_C_locale(const std::string &lname, const std::string &cname, StringVector &libc_locales)
Definition aliases.cpp:445
void get_cname_aliases(const std::string &name, StringVector &aliases)
Definition aliases.cpp:392
int ci_compare(const char *s1, const char *s2)
Definition aliases.cpp:367
std::string get_C_encoding_locale(const std::string &codeset)
Definition aliases.cpp:498
std::vector< std::string > StringVector
Definition aliases.h:43
Definition def.h:49
bool issue_diag(int type, bool, const Scanner::token_t *token, const char *fmt,...)
@ I_ENABLE
Definition diagnostic.h:80
@ E_OPENRD
Definition diagnostic.h:37
@ E_XARG
Definition diagnostic.h:54
@ E_CMDARG
Definition diagnostic.h:53
@ W_COMPAT
Definition diagnostic.h:63
@ W_DISABLE
Definition diagnostic.h:62
@ E_NOARG
Definition diagnostic.h:55
@ I_STAGE
Definition diagnostic.h:81
int localedef_main(int argc, char *argv[])
#define EXIT_ERRORS
Definition localedef.cpp:47
int locale_main(int, char *[])
Definition locale.cpp:2876
#define EXIT_OK
Definition localedef.cpp:46
@ error
throw a parse_error exception in case of a tag
void create_symlink(const std::string &dir, const std::string &xname, const std::string &sname)
Definition path.cpp:75
int makedir(const char *name)
Definition path.cpp:236
const char * locale_name
std::string charmap_dir
std::string output_dir
const char * alias_file
const char * program_name
const char * source_name
const char * map_file
const char * charmap_name
std::string src_dir