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