Imported Upstream version 0.18.3.2
[platform/upstream/gettext.git] / gettext-tools / src / msgcomm.c
1 /* GNU gettext - internationalization aids
2    Copyright (C) 1997-1998, 2000-2007, 2009-2012 Free Software Foundation, Inc.
3
4    This file was written by Peter Miller <millerp@canb.auug.org.au>
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 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22
23 #include <getopt.h>
24 #include <limits.h>
25 #include <locale.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28
29 #include "closeout.h"
30 #include "dir-list.h"
31 #include "str-list.h"
32 #include "file-list.h"
33 #include "error.h"
34 #include "error-progname.h"
35 #include "progname.h"
36 #include "relocatable.h"
37 #include "basename.h"
38 #include "message.h"
39 #include "read-catalog.h"
40 #include "read-po.h"
41 #include "read-properties.h"
42 #include "read-stringtable.h"
43 #include "write-catalog.h"
44 #include "write-po.h"
45 #include "write-properties.h"
46 #include "write-stringtable.h"
47 #include "color.h"
48 #include "msgl-cat.h"
49 #include "propername.h"
50 #include "gettext.h"
51
52
53 /* A convenience macro.  I don't like writing gettext() every time.  */
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", no_argument, &line_comment, 1 },
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   { "no-escape", no_argument, NULL, 'e' },
75   { "no-location", no_argument, &line_comment, 0 },
76   { "no-wrap", no_argument, NULL, CHAR_MAX + 2 },
77   { "omit-header", no_argument, NULL, CHAR_MAX + 1 },
78   { "output", required_argument, NULL, 'o' }, /* for backward compatibility */
79   { "output-file", required_argument, NULL, 'o' },
80   { "properties-input", no_argument, NULL, 'P' },
81   { "properties-output", no_argument, NULL, 'p' },
82   { "sort-by-file", no_argument, NULL, 'F' },
83   { "sort-output", no_argument, NULL, 's' },
84   { "strict", no_argument, NULL, 'S' },
85   { "stringtable-input", no_argument, NULL, CHAR_MAX + 3 },
86   { "stringtable-output", no_argument, NULL, CHAR_MAX + 4 },
87   { "style", required_argument, NULL, CHAR_MAX + 6 },
88   { "to-code", required_argument, NULL, 't' },
89   { "unique", no_argument, NULL, 'u' },
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__ > 4) || __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 = false;
112   bool do_version = false;
113   msgdomain_list_ty *result;
114   catalog_input_format_ty input_syntax = &input_format_po;
115   catalog_output_format_ty output_syntax = &output_format_po;
116   bool sort_by_msgid = false;
117   bool sort_by_filepos = false;
118   const char *files_from = NULL;
119   string_list_ty *file_list;
120   char *output_file = NULL;
121
122   /* Set program name for messages.  */
123   set_program_name (argv[0]);
124   error_print_progname = maybe_print_progname;
125
126 #ifdef HAVE_SETLOCALE
127   /* Set locale via LC_ALL.  */
128   setlocale (LC_ALL, "");
129 #endif
130
131   /* Set the text message domain.  */
132   bindtextdomain (PACKAGE, relocate (LOCALEDIR));
133   bindtextdomain ("bison-runtime", relocate (BISON_LOCALEDIR));
134   textdomain (PACKAGE);
135
136   /* Ensure that write errors on stdout are detected.  */
137   atexit (close_stdout);
138
139   /* Set default values for variables.  */
140   more_than = -1;
141   less_than = -1;
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         omit_header = 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       case CHAR_MAX + 5: /* --color */
262         if (handle_color_option (optarg) || color_test_mode)
263           usage (EXIT_FAILURE);
264         break;
265
266       case CHAR_MAX + 6: /* --style */
267         handle_style_option (optarg);
268         break;
269
270       default:
271         usage (EXIT_FAILURE);
272         /* NOTREACHED */
273       }
274
275   /* Version information requested.  */
276   if (do_version)
277     {
278       printf ("%s (GNU %s) %s\n", basename (program_name), PACKAGE, VERSION);
279       /* xgettext: no-wrap */
280       printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
281 License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n\
282 This is free software: you are free to change and redistribute it.\n\
283 There is NO WARRANTY, to the extent permitted by law.\n\
284 "),
285               "1995-1998, 2000-2010");
286       printf (_("Written by %s.\n"), proper_name ("Peter Miller"));
287       exit (EXIT_SUCCESS);
288     }
289
290   /* Help is requested.  */
291   if (do_help)
292     usage (EXIT_SUCCESS);
293
294   /* Verify selected options.  */
295   if (!line_comment && sort_by_filepos)
296     error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"),
297            "--no-location", "--sort-by-file");
298
299   if (sort_by_msgid && sort_by_filepos)
300     error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"),
301            "--sort-output", "--sort-by-file");
302
303   /* Determine list of files we have to process.  */
304   if (files_from != NULL)
305     file_list = read_names_from_file (files_from);
306   else
307     file_list = string_list_alloc ();
308   /* Append names from command line.  */
309   for (cnt = optind; cnt < argc; ++cnt)
310     string_list_append_unique (file_list, argv[cnt]);
311
312   /* Test whether sufficient input files were given.  */
313   if (file_list->nitems < 2)
314     {
315       error (EXIT_SUCCESS, 0, _("at least two files must be specified"));
316       usage (EXIT_FAILURE);
317     }
318
319   /* Default the message selection criteria, and check them for sanity.  */
320   if (more_than < 0)
321     more_than = (less_than < 0 ? 1 : 0);
322   if (less_than < 0)
323     less_than = INT_MAX;
324   if (more_than >= less_than || less_than < 2)
325     error (EXIT_FAILURE, 0,
326            _("impossible selection criteria specified (%d < n < %d)"),
327            more_than, less_than);
328
329   /* Read input files, then filter, convert and merge messages.  */
330   allow_duplicates = true;
331   msgcomm_mode = true;
332   result = catenate_msgdomain_list (file_list, input_syntax, to_code);
333
334   string_list_free (file_list);
335
336   /* Sorting the list of messages.  */
337   if (sort_by_filepos)
338     msgdomain_list_sort_by_filepos (result);
339   else if (sort_by_msgid)
340     msgdomain_list_sort_by_msgid (result);
341
342   /* Write the PO file.  */
343   msgdomain_list_print (result, output_file, output_syntax, force_po, false);
344
345   exit (EXIT_SUCCESS);
346 }
347
348
349 /* Display usage information and exit.  */
350 static void
351 usage (int status)
352 {
353   if (status != EXIT_SUCCESS)
354     fprintf (stderr, _("Try '%s --help' for more information.\n"),
355              program_name);
356   else
357     {
358       printf (_("\
359 Usage: %s [OPTION] [INPUTFILE]...\n\
360 "), program_name);
361       printf ("\n");
362       /* xgettext: no-wrap */
363       printf (_("\
364 Find messages which are common to two or more of the specified PO files.\n\
365 By using the --more-than option, greater commonality may be requested\n\
366 before messages are printed.  Conversely, the --less-than option may be\n\
367 used to specify less commonality before messages are printed (i.e.\n\
368 --less-than=2 will only print the unique messages).  Translations,\n\
369 comments and extracted comments will be preserved, but only from the first\n\
370 PO file to define them.  File positions from all PO files will be\n\
371 cumulated.\n\
372 "));
373       printf ("\n");
374       printf (_("\
375 Mandatory arguments to long options are mandatory for short options too.\n"));
376       printf ("\n");
377       printf (_("\
378 Input file location:\n"));
379       printf (_("\
380   INPUTFILE ...               input files\n"));
381       printf (_("\
382   -f, --files-from=FILE       get list of input files from FILE\n"));
383       printf (_("\
384   -D, --directory=DIRECTORY   add DIRECTORY to list for input files search\n"));
385       printf (_("\
386 If input file is -, standard input is read.\n"));
387       printf ("\n");
388       printf (_("\
389 Output file location:\n"));
390       printf (_("\
391   -o, --output-file=FILE      write output to specified file\n"));
392       printf (_("\
393 The results are written to standard output if no output file is specified\n\
394 or if it is -.\n"));
395       printf ("\n");
396       printf (_("\
397 Message selection:\n"));
398       printf (_("\
399   -<, --less-than=NUMBER      print messages with less than this many\n\
400                               definitions, defaults to infinite if not set\n"));
401       printf (_("\
402   ->, --more-than=NUMBER      print messages with more than this many\n\
403                               definitions, defaults to 1 if not set\n"));
404       printf (_("\
405   -u, --unique                shorthand for --less-than=2, requests\n\
406                               that only unique messages be printed\n"));
407       printf ("\n");
408       printf (_("\
409 Input file syntax:\n"));
410       printf (_("\
411   -P, --properties-input      input files are in Java .properties syntax\n"));
412       printf (_("\
413       --stringtable-input     input files are in NeXTstep/GNUstep .strings\n\
414                               syntax\n"));
415       printf ("\n");
416       printf (_("\
417 Output details:\n"));
418       printf (_("\
419       --color                 use colors and other text attributes always\n\
420       --color=WHEN            use colors and other text attributes if WHEN.\n\
421                               WHEN may be 'always', 'never', 'auto', or 'html'.\n"));
422       printf (_("\
423       --style=STYLEFILE       specify CSS style rule file for --color\n"));
424       printf (_("\
425   -e, --no-escape             do not use C escapes in output (default)\n"));
426       printf (_("\
427   -E, --escape                use C escapes in output, no extended chars\n"));
428       printf (_("\
429       --force-po              write PO file even if empty\n"));
430       printf (_("\
431   -i, --indent                write the .po file using indented style\n"));
432       printf (_("\
433       --no-location           do not write '#: filename:line' lines\n"));
434       printf (_("\
435   -n, --add-location          generate '#: filename:line' lines (default)\n"));
436       printf (_("\
437       --strict                write out strict Uniforum conforming .po file\n"));
438       printf (_("\
439   -p, --properties-output     write out a Java .properties file\n"));
440       printf (_("\
441       --stringtable-output    write out a NeXTstep/GNUstep .strings file\n"));
442       printf (_("\
443   -w, --width=NUMBER          set output page width\n"));
444       printf (_("\
445       --no-wrap               do not break long message lines, longer than\n\
446                               the output page width, into several lines\n"));
447       printf (_("\
448   -s, --sort-output           generate sorted output\n"));
449       printf (_("\
450   -F, --sort-by-file          sort output by file location\n"));
451       printf (_("\
452       --omit-header           don't write header with 'msgid \"\"' entry\n"));
453       printf ("\n");
454       printf (_("\
455 Informative output:\n"));
456       printf (_("\
457   -h, --help                  display this help and exit\n"));
458       printf (_("\
459   -V, --version               output version information and exit\n"));
460       printf ("\n");
461       /* TRANSLATORS: The placeholder indicates the bug-reporting address
462          for this package.  Please add _another line_ saying
463          "Report translation bugs to <...>\n" with the address for translation
464          bugs (typically your translation team's web or email address).  */
465       fputs (_("Report bugs to <bug-gnu-gettext@gnu.org>.\n"),
466              stdout);
467     }
468
469   exit (status);
470 }