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