Imported Upstream version 0.18.1.1
[platform/upstream/gettext.git] / gettext-tools / src / msgunfmt.c
1 /* msgunfmt - converts binary .mo files to Uniforum style .po files
2    Copyright (C) 1995-1998, 2000-2007, 2009-2010 Free Software Foundation, Inc.
3    Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, April 1995.
4
5    This program is free software: you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 3 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21
22 #include <getopt.h>
23 #include <limits.h>
24 #include <stdbool.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <locale.h>
28
29 #include "closeout.h"
30 #include "error.h"
31 #include "error-progname.h"
32 #include "progname.h"
33 #include "relocatable.h"
34 #include "basename.h"
35 #include "message.h"
36 #include "msgunfmt.h"
37 #include "read-mo.h"
38 #include "read-java.h"
39 #include "read-csharp.h"
40 #include "read-resources.h"
41 #include "read-tcl.h"
42 #include "write-catalog.h"
43 #include "write-po.h"
44 #include "write-properties.h"
45 #include "write-stringtable.h"
46 #include "color.h"
47 #include "propername.h"
48 #include "gettext.h"
49
50 #define _(str) gettext (str)
51
52
53 /* Be more verbose.  */
54 bool verbose;
55
56 /* Java mode input file specification.  */
57 static bool java_mode;
58 static const char *java_resource_name;
59 static const char *java_locale_name;
60
61 /* C# mode input file specification.  */
62 static bool csharp_mode;
63 static const char *csharp_resource_name;
64 static const char *csharp_locale_name;
65 static const char *csharp_base_directory;
66
67 /* C# resources mode input file specification.  */
68 static bool csharp_resources_mode;
69
70 /* Tcl mode input file specification.  */
71 static bool tcl_mode;
72 static const char *tcl_locale_name;
73 static const char *tcl_base_directory;
74
75 /* Force output of PO file even if empty.  */
76 static int force_po;
77
78 /* Long options.  */
79 static const struct option long_options[] =
80 {
81   { "color", optional_argument, NULL, CHAR_MAX + 6 },
82   { "csharp", no_argument, NULL, CHAR_MAX + 4 },
83   { "csharp-resources", no_argument, NULL, CHAR_MAX + 5 },
84   { "escape", no_argument, NULL, 'E' },
85   { "force-po", no_argument, &force_po, 1 },
86   { "help", no_argument, NULL, 'h' },
87   { "indent", no_argument, NULL, 'i' },
88   { "java", no_argument, NULL, 'j' },
89   { "locale", required_argument, NULL, 'l' },
90   { "no-escape", no_argument, NULL, 'e' },
91   { "no-wrap", no_argument, NULL, CHAR_MAX + 2 },
92   { "output-file", required_argument, NULL, 'o' },
93   { "properties-output", no_argument, NULL, 'p' },
94   { "resource", required_argument, NULL, 'r' },
95   { "sort-output", no_argument, NULL, 's' },
96   { "strict", no_argument, NULL, 'S' },
97   { "stringtable-output", no_argument, NULL, CHAR_MAX + 3 },
98   { "style", required_argument, NULL, CHAR_MAX + 7 },
99   { "tcl", no_argument, NULL, CHAR_MAX + 1 },
100   { "verbose", no_argument, NULL, 'v' },
101   { "version", no_argument, NULL, 'V' },
102   { "width", required_argument, NULL, 'w', },
103   { NULL, 0, NULL, 0 }
104 };
105
106
107 /* Forward declaration of local functions.  */
108 static void usage (int status)
109 #if defined __GNUC__ && ((__GNUC__ == 2 && __GNUC_MINOR__ >= 5) || __GNUC__ > 2)
110         __attribute__ ((noreturn))
111 #endif
112 ;
113 static void read_one_file (message_list_ty *mlp, const char *filename);
114
115
116 int
117 main (int argc, char **argv)
118 {
119   int optchar;
120   bool do_help = false;
121   bool do_version = false;
122   const char *output_file = "-";
123   msgdomain_list_ty *result;
124   catalog_output_format_ty output_syntax = &output_format_po;
125   bool sort_by_msgid = false;
126
127   /* Set program name for messages.  */
128   set_program_name (argv[0]);
129   error_print_progname = maybe_print_progname;
130
131 #ifdef HAVE_SETLOCALE
132   /* Set locale via LC_ALL.  */
133   setlocale (LC_ALL, "");
134 #endif
135
136   /* Set the text message domain.  */
137   bindtextdomain (PACKAGE, relocate (LOCALEDIR));
138   bindtextdomain ("bison-runtime", relocate (BISON_LOCALEDIR));
139   textdomain (PACKAGE);
140
141   /* Ensure that write errors on stdout are detected.  */
142   atexit (close_stdout);
143
144   while ((optchar = getopt_long (argc, argv, "d:eEhijl:o:pr:svVw:",
145                                  long_options, NULL))
146          != EOF)
147     switch (optchar)
148       {
149       case '\0':
150         /* long option */
151         break;
152
153       case 'd':
154         csharp_base_directory = optarg;
155         tcl_base_directory = optarg;
156         break;
157
158       case 'e':
159         message_print_style_escape (false);
160         break;
161
162       case 'E':
163         message_print_style_escape (true);
164         break;
165
166       case 'h':
167         do_help = true;
168         break;
169
170       case 'i':
171         message_print_style_indent ();
172         break;
173
174       case 'j':
175         java_mode = true;
176         break;
177
178       case 'l':
179         java_locale_name = optarg;
180         csharp_locale_name = optarg;
181         tcl_locale_name = optarg;
182         break;
183
184       case 'o':
185         output_file = optarg;
186         break;
187
188       case 'p':
189         output_syntax = &output_format_properties;
190         break;
191
192       case 'r':
193         java_resource_name = optarg;
194         csharp_resource_name = optarg;
195         break;
196
197       case 's':
198         sort_by_msgid = true;
199         break;
200
201       case 'S':
202         message_print_style_uniforum ();
203         break;
204
205       case 'v':
206         verbose = true;
207         break;
208
209       case 'V':
210         do_version = true;
211         break;
212
213       case 'w':
214         {
215           int value;
216           char *endp;
217           value = strtol (optarg, &endp, 10);
218           if (endp != optarg)
219             message_page_width_set (value);
220         }
221         break;
222
223       case CHAR_MAX + 1: /* --tcl */
224         tcl_mode = true;
225         break;
226
227       case CHAR_MAX + 2: /* --no-wrap */
228         message_page_width_ignore ();
229         break;
230
231       case CHAR_MAX + 3: /* --stringtable-output */
232         output_syntax = &output_format_stringtable;
233         break;
234
235       case CHAR_MAX + 4: /* --csharp */
236         csharp_mode = true;
237         break;
238
239       case CHAR_MAX + 5: /* --csharp-resources */
240         csharp_resources_mode = true;
241         break;
242
243       case CHAR_MAX + 6: /* --color */
244         if (handle_color_option (optarg) || color_test_mode)
245           usage (EXIT_FAILURE);
246         break;
247
248       case CHAR_MAX + 7: /* --style */
249         handle_style_option (optarg);
250         break;
251
252       default:
253         usage (EXIT_FAILURE);
254         break;
255       }
256
257   /* Version information is requested.  */
258   if (do_version)
259     {
260       printf ("%s (GNU %s) %s\n", basename (program_name), PACKAGE, VERSION);
261       /* xgettext: no-wrap */
262       printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
263 License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n\
264 This is free software: you are free to change and redistribute it.\n\
265 There is NO WARRANTY, to the extent permitted by law.\n\
266 "),
267               "1995-1998, 2000-2010");
268       printf (_("Written by %s.\n"), proper_name ("Ulrich Drepper"));
269       exit (EXIT_SUCCESS);
270     }
271
272   /* Help is requested.  */
273   if (do_help)
274     usage (EXIT_SUCCESS);
275
276   /* Check for contradicting options.  */
277   {
278     unsigned int modes =
279       (java_mode ? 1 : 0)
280       | (csharp_mode ? 2 : 0)
281       | (csharp_resources_mode ? 4 : 0)
282       | (tcl_mode ? 8 : 0);
283     static const char *mode_options[] =
284       { "--java", "--csharp", "--csharp-resources", "--tcl" };
285     /* More than one bit set?  */
286     if (modes & (modes - 1))
287       {
288         const char *first_option;
289         const char *second_option;
290         unsigned int i;
291         for (i = 0; ; i++)
292           if (modes & (1 << i))
293             break;
294         first_option = mode_options[i];
295         for (i = i + 1; ; i++)
296           if (modes & (1 << i))
297             break;
298         second_option = mode_options[i];
299         error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"),
300                first_option, second_option);
301       }
302   }
303   if (java_mode)
304     {
305       if (optind < argc)
306         {
307           error (EXIT_FAILURE, 0,
308                  _("%s and explicit file names are mutually exclusive"),
309                  "--java");
310         }
311     }
312   else if (csharp_mode)
313     {
314       if (optind < argc)
315         {
316           error (EXIT_FAILURE, 0,
317                  _("%s and explicit file names are mutually exclusive"),
318                  "--csharp");
319         }
320       if (csharp_locale_name == NULL)
321         {
322           error (EXIT_SUCCESS, 0,
323                  _("%s requires a \"-l locale\" specification"),
324                  "--csharp");
325           usage (EXIT_FAILURE);
326         }
327       if (csharp_base_directory == NULL)
328         {
329           error (EXIT_SUCCESS, 0,
330                  _("%s requires a \"-d directory\" specification"),
331                  "--csharp");
332           usage (EXIT_FAILURE);
333         }
334     }
335   else if (tcl_mode)
336     {
337       if (optind < argc)
338         {
339           error (EXIT_FAILURE, 0,
340                  _("%s and explicit file names are mutually exclusive"),
341                  "--tcl");
342         }
343       if (tcl_locale_name == NULL)
344         {
345           error (EXIT_SUCCESS, 0,
346                  _("%s requires a \"-l locale\" specification"),
347                  "--tcl");
348           usage (EXIT_FAILURE);
349         }
350       if (tcl_base_directory == NULL)
351         {
352           error (EXIT_SUCCESS, 0,
353                  _("%s requires a \"-d directory\" specification"),
354                  "--tcl");
355           usage (EXIT_FAILURE);
356         }
357     }
358   else
359     {
360       if (java_resource_name != NULL)
361         {
362           error (EXIT_SUCCESS, 0, _("%s is only valid with %s or %s"),
363                  "--resource", "--java", "--csharp");
364           usage (EXIT_FAILURE);
365         }
366       if (java_locale_name != NULL)
367         {
368           error (EXIT_SUCCESS, 0, _("%s is only valid with %s or %s"),
369                  "--locale", "--java", "--csharp");
370           usage (EXIT_FAILURE);
371         }
372     }
373
374   /* Read the given .mo file. */
375   if (java_mode)
376     {
377       result = msgdomain_read_java (java_resource_name, java_locale_name);
378     }
379   else if (csharp_mode)
380     {
381       result = msgdomain_read_csharp (csharp_resource_name, csharp_locale_name,
382                                       csharp_base_directory);
383     }
384   else if (tcl_mode)
385     {
386       result = msgdomain_read_tcl (tcl_locale_name, tcl_base_directory);
387     }
388   else
389     {
390       message_list_ty *mlp;
391
392       mlp = message_list_alloc (false);
393       if (optind < argc)
394         {
395           do
396             read_one_file (mlp, argv[optind]);
397           while (++optind < argc);
398         }
399       else
400         read_one_file (mlp, "-");
401
402       result = msgdomain_list_alloc (false);
403       result->item[0]->messages = mlp;
404     }
405
406   /* Sorting the list of messages.  */
407   if (sort_by_msgid)
408     msgdomain_list_sort_by_msgid (result);
409
410   /* Write the resulting message list to the given .po file.  */
411   msgdomain_list_print (result, output_file, output_syntax, force_po, false);
412
413   /* No problems.  */
414   exit (EXIT_SUCCESS);
415 }
416
417
418 /* Display usage information and exit.  */
419 static void
420 usage (int status)
421 {
422   if (status != EXIT_SUCCESS)
423     fprintf (stderr, _("Try `%s --help' for more information.\n"),
424              program_name);
425   else
426     {
427       printf (_("\
428 Usage: %s [OPTION] [FILE]...\n\
429 "), program_name);
430       printf ("\n");
431       printf (_("\
432 Convert binary message catalog to Uniforum style .po file.\n\
433 "));
434       printf ("\n");
435       printf (_("\
436 Mandatory arguments to long options are mandatory for short options too.\n"));
437       printf ("\n");
438       printf (_("\
439 Operation mode:\n"));
440       printf (_("\
441   -j, --java                  Java mode: input is a Java ResourceBundle class\n"));
442       printf (_("\
443       --csharp                C# mode: input is a .NET .dll file\n"));
444       printf (_("\
445       --csharp-resources      C# resources mode: input is a .NET .resources file\n"));
446       printf (_("\
447       --tcl                   Tcl mode: input is a tcl/msgcat .msg file\n"));
448       printf ("\n");
449       printf (_("\
450 Input file location:\n"));
451       printf (_("\
452   FILE ...                    input .mo files\n"));
453       printf (_("\
454 If no input file is given or if it is -, standard input is read.\n"));
455       printf ("\n");
456       printf (_("\
457 Input file location in Java mode:\n"));
458       printf (_("\
459   -r, --resource=RESOURCE     resource name\n"));
460       printf (_("\
461   -l, --locale=LOCALE         locale name, either language or language_COUNTRY\n"));
462       printf (_("\
463 The class name is determined by appending the locale name to the resource name,\n\
464 separated with an underscore.  The class is located using the CLASSPATH.\n\
465 "));
466       printf ("\n");
467       printf (_("\
468 Input file location in C# mode:\n"));
469       printf (_("\
470   -r, --resource=RESOURCE     resource name\n"));
471       printf (_("\
472   -l, --locale=LOCALE         locale name, either language or language_COUNTRY\n"));
473       printf (_("\
474   -d DIRECTORY                base directory for locale dependent .dll files\n"));
475       printf (_("\
476 The -l and -d options are mandatory.  The .dll file is located in a\n\
477 subdirectory of the specified directory whose name depends on the locale.\n"));
478       printf ("\n");
479       printf (_("\
480 Input file location in Tcl mode:\n"));
481       printf (_("\
482   -l, --locale=LOCALE         locale name, either language or language_COUNTRY\n"));
483       printf (_("\
484   -d DIRECTORY                base directory of .msg message catalogs\n"));
485       printf (_("\
486 The -l and -d options are mandatory.  The .msg file is located in the\n\
487 specified directory.\n"));
488       printf ("\n");
489       printf (_("\
490 Output file location:\n"));
491       printf (_("\
492   -o, --output-file=FILE      write output to specified file\n"));
493       printf (_("\
494 The results are written to standard output if no output file is specified\n\
495 or if it is -.\n"));
496       printf ("\n");
497       printf (_("\
498 Output details:\n"));
499       printf (_("\
500       --color                 use colors and other text attributes always\n\
501       --color=WHEN            use colors and other text attributes if WHEN.\n\
502                               WHEN may be 'always', 'never', 'auto', or 'html'.\n"));
503       printf (_("\
504       --style=STYLEFILE       specify CSS style rule file for --color\n"));
505       printf (_("\
506   -e, --no-escape             do not use C escapes in output (default)\n"));
507       printf (_("\
508   -E, --escape                use C escapes in output, no extended chars\n"));
509       printf (_("\
510       --force-po              write PO file even if empty\n"));
511       printf (_("\
512   -i, --indent                write indented output style\n"));
513       printf (_("\
514       --strict                write strict uniforum style\n"));
515       printf (_("\
516   -p, --properties-output     write out a Java .properties file\n"));
517       printf (_("\
518       --stringtable-output    write out a NeXTstep/GNUstep .strings file\n"));
519       printf (_("\
520   -w, --width=NUMBER          set output page width\n"));
521       printf (_("\
522       --no-wrap               do not break long message lines, longer than\n\
523                               the output page width, into several lines\n"));
524       printf (_("\
525   -s, --sort-output           generate sorted output\n"));
526       printf ("\n");
527       printf (_("\
528 Informative output:\n"));
529       printf (_("\
530   -h, --help                  display this help and exit\n"));
531       printf (_("\
532   -V, --version               output version information and exit\n"));
533       printf (_("\
534   -v, --verbose               increase verbosity level\n"));
535       printf ("\n");
536       /* TRANSLATORS: The placeholder indicates the bug-reporting address
537          for this package.  Please add _another line_ saying
538          "Report translation bugs to <...>\n" with the address for translation
539          bugs (typically your translation team's web or email address).  */
540       fputs (_("Report bugs to <bug-gnu-gettext@gnu.org>.\n"),
541              stdout);
542     }
543
544   exit (status);
545 }
546
547
548 static void
549 read_one_file (message_list_ty *mlp, const char *filename)
550 {
551   if (csharp_resources_mode)
552     read_resources_file (mlp, filename);
553   else
554     read_mo_file (mlp, filename);
555 }