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