xref: /netbsd-src/external/gpl2/gettext/dist/gettext-tools/src/msgconv.c (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
1 /* Converts a translation catalog to a different character encoding.
2    Copyright (C) 2001-2006 Free Software Foundation, Inc.
3    Written by Bruno Haible <haible@clisp.cons.org>, 2001.
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 
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
23 
24 #include <getopt.h>
25 #include <limits.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <locale.h>
29 
30 #include "closeout.h"
31 #include "dir-list.h"
32 #include "error.h"
33 #include "error-progname.h"
34 #include "progname.h"
35 #include "relocatable.h"
36 #include "basename.h"
37 #include "message.h"
38 #include "read-catalog.h"
39 #include "read-po.h"
40 #include "read-properties.h"
41 #include "read-stringtable.h"
42 #include "write-catalog.h"
43 #include "write-po.h"
44 #include "write-properties.h"
45 #include "write-stringtable.h"
46 #include "msgl-iconv.h"
47 #include "localcharset.h"
48 #include "exit.h"
49 #include "propername.h"
50 #include "gettext.h"
51 
52 #define _(str) gettext (str)
53 
54 
55 /* Force output of PO file even if empty.  */
56 static int force_po;
57 
58 /* Target encoding.  */
59 static const char *to_code;
60 
61 /* Long options.  */
62 static const struct option long_options[] =
63 {
64   { "add-location", no_argument, &line_comment, 1 },
65   { "directory", required_argument, NULL, 'D' },
66   { "escape", no_argument, NULL, 'E' },
67   { "force-po", no_argument, &force_po, 1 },
68   { "help", no_argument, NULL, 'h' },
69   { "indent", no_argument, NULL, 'i' },
70   { "no-escape", no_argument, NULL, 'e' },
71   { "no-location", no_argument, &line_comment, 0 },
72   { "no-wrap", no_argument, NULL, CHAR_MAX + 1 },
73   { "output-file", required_argument, NULL, 'o' },
74   { "properties-input", no_argument, NULL, 'P' },
75   { "properties-output", no_argument, NULL, 'p' },
76   { "sort-by-file", no_argument, NULL, 'F' },
77   { "sort-output", no_argument, NULL, 's' },
78   { "strict", no_argument, NULL, 'S' },
79   { "stringtable-input", no_argument, NULL, CHAR_MAX + 2 },
80   { "stringtable-output", no_argument, NULL, CHAR_MAX + 3 },
81   { "to-code", required_argument, NULL, 't' },
82   { "version", no_argument, NULL, 'V' },
83   { "width", required_argument, NULL, 'w', },
84   { NULL, 0, NULL, 0 }
85 };
86 
87 
88 /* Forward declaration of local functions.  */
89 static void usage (int status)
90 #if defined __GNUC__ && ((__GNUC__ == 2 && __GNUC_MINOR__ >= 5) || __GNUC__ > 2)
91 	__attribute__ ((noreturn))
92 #endif
93 ;
94 
95 
96 int
main(int argc,char ** argv)97 main (int argc, char **argv)
98 {
99   int opt;
100   bool do_help;
101   bool do_version;
102   char *output_file;
103   const char *input_file;
104   msgdomain_list_ty *result;
105   catalog_input_format_ty input_syntax = &input_format_po;
106   catalog_output_format_ty output_syntax = &output_format_po;
107   bool sort_by_filepos = false;
108   bool sort_by_msgid = false;
109 
110   /* Set program name for messages.  */
111   set_program_name (argv[0]);
112   error_print_progname = maybe_print_progname;
113 
114 #ifdef HAVE_SETLOCALE
115   /* Set locale via LC_ALL.  */
116   setlocale (LC_ALL, "");
117 #endif
118 
119   /* Set the text message domain.  */
120   bindtextdomain (PACKAGE, relocate (LOCALEDIR));
121   bindtextdomain ("bison-runtime", relocate (BISON_LOCALEDIR));
122   textdomain (PACKAGE);
123 
124   /* Ensure that write errors on stdout are detected.  */
125   atexit (close_stdout);
126 
127   /* Set default values for variables.  */
128   do_help = false;
129   do_version = false;
130   output_file = NULL;
131   input_file = NULL;
132 
133   while ((opt = getopt_long (argc, argv, "D:eEFhio:pPst:Vw:", long_options,
134 			     NULL))
135 	 != EOF)
136     switch (opt)
137       {
138       case '\0':		/* Long option.  */
139 	break;
140 
141       case 'D':
142 	dir_list_append (optarg);
143 	break;
144 
145       case 'e':
146 	message_print_style_escape (false);
147 	break;
148 
149       case 'E':
150 	message_print_style_escape (true);
151 	break;
152 
153       case 'F':
154 	sort_by_filepos = true;
155 	break;
156 
157       case 'h':
158 	do_help = true;
159 	break;
160 
161       case 'i':
162 	message_print_style_indent ();
163 	break;
164 
165       case 'o':
166 	output_file = optarg;
167 	break;
168 
169       case 'p':
170 	output_syntax = &output_format_properties;
171 	break;
172 
173       case 'P':
174 	input_syntax = &input_format_properties;
175 	break;
176 
177       case 's':
178 	sort_by_msgid = true;
179 	break;
180 
181       case 'S':
182 	message_print_style_uniforum ();
183 	break;
184 
185       case 't':
186 	to_code = optarg;
187 	break;
188 
189       case 'V':
190 	do_version = true;
191 	break;
192 
193       case 'w':
194 	{
195 	  int value;
196 	  char *endp;
197 	  value = strtol (optarg, &endp, 10);
198 	  if (endp != optarg)
199 	    message_page_width_set (value);
200 	}
201 	break;
202 
203       case CHAR_MAX + 1: /* --no-wrap */
204 	message_page_width_ignore ();
205 	break;
206 
207       case CHAR_MAX + 2: /* --stringtable-input */
208 	input_syntax = &input_format_stringtable;
209 	break;
210 
211       case CHAR_MAX + 3: /* --stringtable-output */
212 	output_syntax = &output_format_stringtable;
213 	break;
214 
215       default:
216 	usage (EXIT_FAILURE);
217 	break;
218       }
219 
220   /* Version information is requested.  */
221   if (do_version)
222     {
223       printf ("%s (GNU %s) %s\n", basename (program_name), PACKAGE, VERSION);
224       /* xgettext: no-wrap */
225       printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
226 This is free software; see the source for copying conditions.  There is NO\n\
227 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
228 "),
229 	      "2001-2006");
230       printf (_("Written by %s.\n"), proper_name ("Bruno Haible"));
231       exit (EXIT_SUCCESS);
232     }
233 
234   /* Help is requested.  */
235   if (do_help)
236     usage (EXIT_SUCCESS);
237 
238   /* Test whether we have an .po file name as argument.  */
239   if (optind == argc)
240     input_file = "-";
241   else if (optind + 1 == argc)
242     input_file = argv[optind];
243   else
244     {
245       error (EXIT_SUCCESS, 0, _("at most one input file allowed"));
246       usage (EXIT_FAILURE);
247     }
248 
249   /* Verify selected options.  */
250   if (!line_comment && sort_by_filepos)
251     error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"),
252 	   "--no-location", "--sort-by-file");
253 
254   if (sort_by_msgid && sort_by_filepos)
255     error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"),
256 	   "--sort-output", "--sort-by-file");
257 
258   /* Default for target encoding is current locale's encoding.  */
259   if (to_code == NULL)
260     to_code = locale_charset ();
261 
262   /* Read input file.  */
263   result = read_catalog_file (input_file, input_syntax);
264 
265   /* Convert if and only if the output syntax supports different encodings.  */
266   if (!output_syntax->requires_utf8)
267     result = iconv_msgdomain_list (result, to_code, input_file);
268 
269   /* Sort the results.  */
270   if (sort_by_filepos)
271     msgdomain_list_sort_by_filepos (result);
272   else if (sort_by_msgid)
273     msgdomain_list_sort_by_msgid (result);
274 
275   /* Write the merged message list out.  */
276   msgdomain_list_print (result, output_file, output_syntax, force_po, false);
277 
278   exit (EXIT_SUCCESS);
279 }
280 
281 
282 /* Display usage information and exit.  */
283 static void
usage(int status)284 usage (int status)
285 {
286   if (status != EXIT_SUCCESS)
287     fprintf (stderr, _("Try `%s --help' for more information.\n"),
288 	     program_name);
289   else
290     {
291       printf (_("\
292 Usage: %s [OPTION] [INPUTFILE]\n\
293 "), program_name);
294       printf ("\n");
295       printf (_("\
296 Converts a translation catalog to a different character encoding.\n\
297 "));
298       printf ("\n");
299       printf (_("\
300 Mandatory arguments to long options are mandatory for short options too.\n"));
301       printf ("\n");
302       printf (_("\
303 Input file location:\n"));
304       printf (_("\
305   INPUTFILE                   input PO file\n"));
306       printf (_("\
307   -D, --directory=DIRECTORY   add DIRECTORY to list for input files search\n"));
308       printf (_("\
309 If no input file is given or if it is -, standard input is read.\n"));
310       printf ("\n");
311       printf (_("\
312 Output file location:\n"));
313       printf (_("\
314   -o, --output-file=FILE      write output to specified file\n"));
315       printf (_("\
316 The results are written to standard output if no output file is specified\n\
317 or if it is -.\n"));
318       printf ("\n");
319       printf (_("\
320 Conversion target:\n"));
321       printf (_("\
322   -t, --to-code=NAME          encoding for output\n"));
323       printf (_("\
324 The default encoding is the current locale's encoding.\n"));
325       printf ("\n");
326       printf (_("\
327 Input file syntax:\n"));
328       printf (_("\
329   -P, --properties-input      input file is in Java .properties syntax\n"));
330       printf (_("\
331       --stringtable-input     input file is in NeXTstep/GNUstep .strings syntax\n"));
332       printf ("\n");
333       printf (_("\
334 Output details:\n"));
335       printf (_("\
336   -e, --no-escape             do not use C escapes in output (default)\n"));
337       printf (_("\
338   -E, --escape                use C escapes in output, no extended chars\n"));
339       printf (_("\
340       --force-po              write PO file even if empty\n"));
341       printf (_("\
342   -i, --indent                indented output style\n"));
343       printf (_("\
344       --no-location           suppress '#: filename:line' lines\n"));
345       printf (_("\
346       --add-location          preserve '#: filename:line' lines (default)\n"));
347       printf (_("\
348       --strict                strict Uniforum output style\n"));
349       printf (_("\
350   -p, --properties-output     write out a Java .properties file\n"));
351       printf (_("\
352       --stringtable-output    write out a NeXTstep/GNUstep .strings file\n"));
353       printf (_("\
354   -w, --width=NUMBER          set output page width\n"));
355       printf (_("\
356       --no-wrap               do not break long message lines, longer than\n\
357                               the output page width, into several lines\n"));
358       printf (_("\
359   -s, --sort-output           generate sorted output\n"));
360       printf (_("\
361   -F, --sort-by-file          sort output by file location\n"));
362       printf ("\n");
363       printf (_("\
364 Informative output:\n"));
365       printf (_("\
366   -h, --help                  display this help and exit\n"));
367       printf (_("\
368   -V, --version               output version information and exit\n"));
369       printf ("\n");
370       fputs (_("Report bugs to <bug-gnu-gettext@gnu.org>.\n"),
371 	     stdout);
372     }
373 
374   exit (status);
375 }
376