1 /* Concatenates several translation catalogs.
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 "str-list.h"
33 #include "file-list.h"
34 #include "error.h"
35 #include "error-progname.h"
36 #include "progname.h"
37 #include "relocatable.h"
38 #include "basename.h"
39 #include "message.h"
40 #include "read-catalog.h"
41 #include "read-po.h"
42 #include "read-properties.h"
43 #include "read-stringtable.h"
44 #include "write-catalog.h"
45 #include "write-po.h"
46 #include "write-properties.h"
47 #include "write-stringtable.h"
48 #include "msgl-cat.h"
49 #include "exit.h"
50 #include "propername.h"
51 #include "gettext.h"
52
53 #define _(str) gettext (str)
54
55
56 /* Force output of PO file even if empty. */
57 static int force_po;
58
59 /* Target encoding. */
60 static const char *to_code;
61
62 /* Long options. */
63 static const struct option long_options[] =
64 {
65 { "add-location", no_argument, &line_comment, 1 },
66 { "directory", required_argument, NULL, 'D' },
67 { "escape", no_argument, NULL, 'E' },
68 { "files-from", required_argument, NULL, 'f' },
69 { "force-po", no_argument, &force_po, 1 },
70 { "help", no_argument, NULL, 'h' },
71 { "indent", no_argument, NULL, 'i' },
72 { "no-escape", no_argument, NULL, 'e' },
73 { "no-location", no_argument, &line_comment, 0 },
74 { "no-wrap", no_argument, NULL, CHAR_MAX + 2 },
75 { "output-file", required_argument, NULL, 'o' },
76 { "properties-input", no_argument, NULL, 'P' },
77 { "properties-output", no_argument, NULL, 'p' },
78 { "sort-by-file", no_argument, NULL, 'F' },
79 { "sort-output", no_argument, NULL, 's' },
80 { "strict", no_argument, NULL, 'S' },
81 { "stringtable-input", no_argument, NULL, CHAR_MAX + 3 },
82 { "stringtable-output", no_argument, NULL, CHAR_MAX + 4 },
83 { "to-code", required_argument, NULL, 't' },
84 { "unique", no_argument, NULL, 'u' },
85 { "use-first", no_argument, NULL, CHAR_MAX + 1 },
86 { "version", no_argument, NULL, 'V' },
87 { "width", required_argument, NULL, 'w', },
88 { "more-than", required_argument, NULL, '>', },
89 { "less-than", required_argument, NULL, '<', },
90 { NULL, 0, NULL, 0 }
91 };
92
93
94 /* Forward declaration of local functions. */
95 static void usage (int status)
96 #if defined __GNUC__ && ((__GNUC__ == 2 && __GNUC_MINOR__ >= 5) || __GNUC__ > 2)
97 __attribute__ ((noreturn))
98 #endif
99 ;
100
101
102 int
main(int argc,char ** argv)103 main (int argc, char **argv)
104 {
105 int cnt;
106 int optchar;
107 bool do_help;
108 bool do_version;
109 char *output_file;
110 const char *files_from;
111 string_list_ty *file_list;
112 msgdomain_list_ty *result;
113 catalog_input_format_ty input_syntax = &input_format_po;
114 catalog_output_format_ty output_syntax = &output_format_po;
115 bool sort_by_msgid = false;
116 bool sort_by_filepos = false;
117
118 /* Set program name for messages. */
119 set_program_name (argv[0]);
120 error_print_progname = maybe_print_progname;
121
122 #ifdef HAVE_SETLOCALE
123 /* Set locale via LC_ALL. */
124 setlocale (LC_ALL, "");
125 #endif
126
127 /* Set the text message domain. */
128 bindtextdomain (PACKAGE, relocate (LOCALEDIR));
129 bindtextdomain ("bison-runtime", relocate (BISON_LOCALEDIR));
130 textdomain (PACKAGE);
131
132 /* Ensure that write errors on stdout are detected. */
133 atexit (close_stdout);
134
135 /* Set default values for variables. */
136 do_help = false;
137 do_version = false;
138 output_file = NULL;
139 files_from = NULL;
140 more_than = 0;
141 less_than = INT_MAX;
142 use_first = false;
143
144 while ((optchar = getopt_long (argc, argv, "<:>:D:eEf:Fhino:pPst:uVw:",
145 long_options, NULL)) != EOF)
146 switch (optchar)
147 {
148 case '\0': /* Long option. */
149 break;
150
151 case '>':
152 {
153 int value;
154 char *endp;
155 value = strtol (optarg, &endp, 10);
156 if (endp != optarg)
157 more_than = value;
158 }
159 break;
160
161 case '<':
162 {
163 int value;
164 char *endp;
165 value = strtol (optarg, &endp, 10);
166 if (endp != optarg)
167 less_than = value;
168 }
169 break;
170
171 case 'D':
172 dir_list_append (optarg);
173 break;
174
175 case 'e':
176 message_print_style_escape (false);
177 break;
178
179 case 'E':
180 message_print_style_escape (true);
181 break;
182
183 case 'f':
184 files_from = optarg;
185 break;
186
187 case 'F':
188 sort_by_filepos = true;
189 break;
190
191 case 'h':
192 do_help = true;
193 break;
194
195 case 'i':
196 message_print_style_indent ();
197 break;
198
199 case 'n':
200 line_comment = 1;
201 break;
202
203 case 'o':
204 output_file = optarg;
205 break;
206
207 case 'p':
208 output_syntax = &output_format_properties;
209 break;
210
211 case 'P':
212 input_syntax = &input_format_properties;
213 break;
214
215 case 's':
216 sort_by_msgid = true;
217 break;
218
219 case 'S':
220 message_print_style_uniforum ();
221 break;
222
223 case 't':
224 to_code = optarg;
225 break;
226
227 case 'u':
228 less_than = 2;
229 break;
230
231 case 'V':
232 do_version = true;
233 break;
234
235 case 'w':
236 {
237 int value;
238 char *endp;
239 value = strtol (optarg, &endp, 10);
240 if (endp != optarg)
241 message_page_width_set (value);
242 }
243 break;
244
245 case CHAR_MAX + 1:
246 use_first = true;
247 break;
248
249 case CHAR_MAX + 2: /* --no-wrap */
250 message_page_width_ignore ();
251 break;
252
253 case CHAR_MAX + 3: /* --stringtable-input */
254 input_syntax = &input_format_stringtable;
255 break;
256
257 case CHAR_MAX + 4: /* --stringtable-output */
258 output_syntax = &output_format_stringtable;
259 break;
260
261 default:
262 usage (EXIT_FAILURE);
263 /* NOTREACHED */
264 }
265
266 /* Version information requested. */
267 if (do_version)
268 {
269 printf ("%s (GNU %s) %s\n", basename (program_name), PACKAGE, VERSION);
270 /* xgettext: no-wrap */
271 printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
272 This is free software; see the source for copying conditions. There is NO\n\
273 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
274 "),
275 "2001-2006");
276 printf (_("Written by %s.\n"), proper_name ("Bruno Haible"));
277 exit (EXIT_SUCCESS);
278 }
279
280 /* Help is requested. */
281 if (do_help)
282 usage (EXIT_SUCCESS);
283
284 /* Verify selected options. */
285 if (!line_comment && sort_by_filepos)
286 error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"),
287 "--no-location", "--sort-by-file");
288
289 if (sort_by_msgid && sort_by_filepos)
290 error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"),
291 "--sort-output", "--sort-by-file");
292
293 /* Check the message selection criteria for sanity. */
294 if (more_than >= less_than || less_than < 2)
295 error (EXIT_FAILURE, 0,
296 _("impossible selection criteria specified (%d < n < %d)"),
297 more_than, less_than);
298
299 /* Determine list of files we have to process. */
300 if (files_from != NULL)
301 file_list = read_names_from_file (files_from);
302 else
303 file_list = string_list_alloc ();
304 /* Append names from command line. */
305 for (cnt = optind; cnt < argc; ++cnt)
306 string_list_append_unique (file_list, argv[cnt]);
307
308 /* Read input files, then filter, convert and merge messages. */
309 result =
310 catenate_msgdomain_list (file_list, input_syntax,
311 output_syntax->requires_utf8 ? "UTF-8" : to_code);
312
313 string_list_free (file_list);
314
315 /* Sorting the list of messages. */
316 if (sort_by_filepos)
317 msgdomain_list_sort_by_filepos (result);
318 else if (sort_by_msgid)
319 msgdomain_list_sort_by_msgid (result);
320
321 /* Write the PO file. */
322 msgdomain_list_print (result, output_file, output_syntax, force_po, false);
323
324 exit (EXIT_SUCCESS);
325 }
326
327
328 /* Display usage information and exit. */
329 static void
usage(int status)330 usage (int status)
331 {
332 if (status != EXIT_SUCCESS)
333 fprintf (stderr, _("Try `%s --help' for more information.\n"),
334 program_name);
335 else
336 {
337 printf (_("\
338 Usage: %s [OPTION] [INPUTFILE]...\n\
339 "), program_name);
340 printf ("\n");
341 /* xgettext: no-wrap */
342 printf (_("\
343 Concatenates and merges the specified PO files.\n\
344 Find messages which are common to two or more of the specified PO files.\n\
345 By using the --more-than option, greater commonality may be requested\n\
346 before messages are printed. Conversely, the --less-than option may be\n\
347 used to specify less commonality before messages are printed (i.e.\n\
348 --less-than=2 will only print the unique messages). Translations,\n\
349 comments and extract comments will be cumulated, except that if --use-first\n\
350 is specified, they will be taken from the first PO file to define them.\n\
351 File positions from all PO files will be cumulated.\n\
352 "));
353 printf ("\n");
354 printf (_("\
355 Mandatory arguments to long options are mandatory for short options too.\n"));
356 printf ("\n");
357 printf (_("\
358 Input file location:\n"));
359 printf (_("\
360 INPUTFILE ... input files\n"));
361 printf (_("\
362 -f, --files-from=FILE get list of input files from FILE\n"));
363 printf (_("\
364 -D, --directory=DIRECTORY add DIRECTORY to list for input files search\n"));
365 printf (_("\
366 If input file is -, standard input is read.\n"));
367 printf ("\n");
368 printf (_("\
369 Output file location:\n"));
370 printf (_("\
371 -o, --output-file=FILE write output to specified file\n"));
372 printf (_("\
373 The results are written to standard output if no output file is specified\n\
374 or if it is -.\n"));
375 printf ("\n");
376 printf (_("\
377 Message selection:\n"));
378 printf (_("\
379 -<, --less-than=NUMBER print messages with less than this many\n\
380 definitions, defaults to infinite if not set\n"));
381 printf (_("\
382 ->, --more-than=NUMBER print messages with more than this many\n\
383 definitions, defaults to 0 if not set\n"));
384 printf (_("\
385 -u, --unique shorthand for --less-than=2, requests\n\
386 that only unique messages be printed\n"));
387 printf ("\n");
388 printf (_("\
389 Input file syntax:\n"));
390 printf (_("\
391 -P, --properties-input input files are in Java .properties syntax\n"));
392 printf (_("\
393 --stringtable-input input files are in NeXTstep/GNUstep .strings\n\
394 syntax\n"));
395 printf ("\n");
396 printf (_("\
397 Output details:\n"));
398 printf (_("\
399 -t, --to-code=NAME encoding for output\n"));
400 printf (_("\
401 --use-first use first available translation for each\n\
402 message, don't merge several translations\n"));
403 printf (_("\
404 -e, --no-escape do not use C escapes in output (default)\n"));
405 printf (_("\
406 -E, --escape use C escapes in output, no extended chars\n"));
407 printf (_("\
408 --force-po write PO file even if empty\n"));
409 printf (_("\
410 -i, --indent write the .po file using indented style\n"));
411 printf (_("\
412 --no-location do not write '#: filename:line' lines\n"));
413 printf (_("\
414 -n, --add-location generate '#: filename:line' lines (default)\n"));
415 printf (_("\
416 --strict write out strict Uniforum conforming .po file\n"));
417 printf (_("\
418 -p, --properties-output write out a Java .properties file\n"));
419 printf (_("\
420 --stringtable-output write out a NeXTstep/GNUstep .strings file\n"));
421 printf (_("\
422 -w, --width=NUMBER set output page width\n"));
423 printf (_("\
424 --no-wrap do not break long message lines, longer than\n\
425 the output page width, into several lines\n"));
426 printf (_("\
427 -s, --sort-output generate sorted output\n"));
428 printf (_("\
429 -F, --sort-by-file sort output by file location\n"));
430 printf ("\n");
431 printf (_("\
432 Informative output:\n"));
433 printf (_("\
434 -h, --help display this help and exit\n"));
435 printf (_("\
436 -V, --version output version information and exit\n"));
437 printf ("\n");
438 fputs (_("Report bugs to <bug-gnu-gettext@gnu.org>.\n"),
439 stdout);
440 }
441
442 exit (status);
443 }
444