Imported Upstream version 0.18.3.2
[platform/upstream/gettext.git] / gettext-tools / src / msguniq.c
1 /* Remove, select or merge duplicate translations.
2    Copyright (C) 2001-2007, 2009-2010, 2012 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 3 of the License, or
8    (at your option) 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, see <http://www.gnu.org/licenses/>.  */
17
18
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #endif
22
23 #include <getopt.h>
24 #include <limits.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <locale.h>
28
29 #include "closeout.h"
30 #include "dir-list.h"
31 #include "str-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 "color.h"
47 #include "msgl-cat.h"
48 #include "propername.h"
49 #include "gettext.h"
50
51 #define _(str) gettext (str)
52
53
54 /* Force output of PO file even if empty.  */
55 static int force_po;
56
57 /* Target encoding.  */
58 static const char *to_code;
59
60 /* Long options.  */
61 static const struct option long_options[] =
62 {
63   { "add-location", no_argument, &line_comment, 1 },
64   { "color", optional_argument, NULL, CHAR_MAX + 5 },
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 + 2 },
73   { "output-file", required_argument, NULL, 'o' },
74   { "properties-input", no_argument, NULL, 'P' },
75   { "properties-output", no_argument, NULL, 'p' },
76   { "repeated", no_argument, NULL, 'd' },
77   { "sort-by-file", no_argument, NULL, 'F' },
78   { "sort-output", no_argument, NULL, 's' },
79   { "strict", no_argument, NULL, 'S' },
80   { "stringtable-input", no_argument, NULL, CHAR_MAX + 3 },
81   { "stringtable-output", no_argument, NULL, CHAR_MAX + 4 },
82   { "style", required_argument, NULL, CHAR_MAX + 6 },
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   { NULL, 0, NULL, 0 }
89 };
90
91
92 /* Forward declaration of local functions.  */
93 static void usage (int status)
94 #if defined __GNUC__ && ((__GNUC__ == 2 && __GNUC_MINOR__ >= 5) || __GNUC__ > 2)
95         __attribute__ ((noreturn))
96 #endif
97 ;
98
99
100 int
101 main (int argc, char **argv)
102 {
103   int optchar;
104   bool do_help;
105   bool do_version;
106   char *output_file;
107   const char *input_file;
108   string_list_ty *file_list;
109   msgdomain_list_ty *result;
110   catalog_input_format_ty input_syntax = &input_format_po;
111   catalog_output_format_ty output_syntax = &output_format_po;
112   bool sort_by_msgid = false;
113   bool sort_by_filepos = false;
114
115   /* Set program name for messages.  */
116   set_program_name (argv[0]);
117   error_print_progname = maybe_print_progname;
118
119 #ifdef HAVE_SETLOCALE
120   /* Set locale via LC_ALL.  */
121   setlocale (LC_ALL, "");
122 #endif
123
124   /* Set the text message domain.  */
125   bindtextdomain (PACKAGE, relocate (LOCALEDIR));
126   bindtextdomain ("bison-runtime", relocate (BISON_LOCALEDIR));
127   textdomain (PACKAGE);
128
129   /* Ensure that write errors on stdout are detected.  */
130   atexit (close_stdout);
131
132   /* Set default values for variables.  */
133   do_help = false;
134   do_version = false;
135   output_file = NULL;
136   input_file = NULL;
137   more_than = 0;
138   less_than = INT_MAX;
139   use_first = false;
140
141   while ((optchar = getopt_long (argc, argv, "dD:eEFhino:pPst:uVw:",
142                                  long_options, NULL)) != EOF)
143     switch (optchar)
144       {
145       case '\0':                /* Long option.  */
146         break;
147
148       case 'd':
149         more_than = 1;
150         less_than = INT_MAX;
151         break;
152
153       case 'D':
154         dir_list_append (optarg);
155         break;
156
157       case 'e':
158         message_print_style_escape (false);
159         break;
160
161       case 'E':
162         message_print_style_escape (true);
163         break;
164
165       case 'F':
166         sort_by_filepos = true;
167         break;
168
169       case 'h':
170         do_help = true;
171         break;
172
173       case 'i':
174         message_print_style_indent ();
175         break;
176
177       case 'n':
178         line_comment = 1;
179         break;
180
181       case 'o':
182         output_file = optarg;
183         break;
184
185       case 'p':
186         output_syntax = &output_format_properties;
187         break;
188
189       case 'P':
190         input_syntax = &input_format_properties;
191         break;
192
193       case 's':
194         sort_by_msgid = true;
195         break;
196
197       case 'S':
198         message_print_style_uniforum ();
199         break;
200
201       case 't':
202         to_code = optarg;
203         break;
204
205       case 'u':
206         more_than = 0;
207         less_than = 2;
208         break;
209
210       case 'V':
211         do_version = true;
212         break;
213
214       case 'w':
215         {
216           int value;
217           char *endp;
218           value = strtol (optarg, &endp, 10);
219           if (endp != optarg)
220             message_page_width_set (value);
221         }
222         break;
223
224       case CHAR_MAX + 1:
225         use_first = true;
226         break;
227
228       case CHAR_MAX + 2: /* --no-wrap */
229         message_page_width_ignore ();
230         break;
231
232       case CHAR_MAX + 3: /* --stringtable-input */
233         input_syntax = &input_format_stringtable;
234         break;
235
236       case CHAR_MAX + 4: /* --stringtable-output */
237         output_syntax = &output_format_stringtable;
238         break;
239
240       case CHAR_MAX + 5: /* --color */
241         if (handle_color_option (optarg) || color_test_mode)
242           usage (EXIT_FAILURE);
243         break;
244
245       case CHAR_MAX + 6: /* --style */
246         handle_style_option (optarg);
247         break;
248
249       default:
250         usage (EXIT_FAILURE);
251         /* NOTREACHED */
252       }
253
254   /* Version information requested.  */
255   if (do_version)
256     {
257       printf ("%s (GNU %s) %s\n", basename (program_name), PACKAGE, VERSION);
258       /* xgettext: no-wrap */
259       printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
260 License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n\
261 This is free software: you are free to change and redistribute it.\n\
262 There is NO WARRANTY, to the extent permitted by law.\n\
263 "),
264               "2001-2010");
265       printf (_("Written by %s.\n"), proper_name ("Bruno Haible"));
266       exit (EXIT_SUCCESS);
267     }
268
269   /* Help is requested.  */
270   if (do_help)
271     usage (EXIT_SUCCESS);
272
273   /* Test whether we have an .po file name as argument.  */
274   if (optind == argc)
275     input_file = "-";
276   else if (optind + 1 == argc)
277     input_file = argv[optind];
278   else
279     {
280       error (EXIT_SUCCESS, 0, _("at most one input file allowed"));
281       usage (EXIT_FAILURE);
282     }
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   /* Determine list of files we have to process: a single file.  */
294   file_list = string_list_alloc ();
295   string_list_append (file_list, input_file);
296
297   /* Read input files, then filter, convert and merge messages.  */
298   allow_duplicates = true;
299   result = catenate_msgdomain_list (file_list, input_syntax, to_code);
300
301   string_list_free (file_list);
302
303   /* Sorting the list of messages.  */
304   if (sort_by_filepos)
305     msgdomain_list_sort_by_filepos (result);
306   else if (sort_by_msgid)
307     msgdomain_list_sort_by_msgid (result);
308
309   /* Write the PO file.  */
310   msgdomain_list_print (result, output_file, output_syntax, force_po, false);
311
312   exit (EXIT_SUCCESS);
313 }
314
315
316 /* Display usage information and exit.  */
317 static void
318 usage (int status)
319 {
320   if (status != EXIT_SUCCESS)
321     fprintf (stderr, _("Try '%s --help' for more information.\n"),
322              program_name);
323   else
324     {
325       printf (_("\
326 Usage: %s [OPTION] [INPUTFILE]\n\
327 "), program_name);
328       printf ("\n");
329       /* xgettext: no-wrap */
330       printf (_("\
331 Unifies duplicate translations in a translation catalog.\n\
332 Finds duplicate translations of the same message ID.  Such duplicates are\n\
333 invalid input for other programs like msgfmt, msgmerge or msgcat.  By\n\
334 default, duplicates are merged together.  When using the --repeated option,\n\
335 only duplicates are output, and all other messages are discarded.  Comments\n\
336 and extracted comments will be cumulated, except that if --use-first is\n\
337 specified, they will be taken from the first translation.  File positions\n\
338 will be cumulated.  When using the --unique option, duplicates are discarded.\n\
339 "));
340       printf ("\n");
341       printf (_("\
342 Mandatory arguments to long options are mandatory for short options too.\n"));
343       printf ("\n");
344       printf (_("\
345 Input file location:\n"));
346       printf (_("\
347   INPUTFILE                   input PO file\n"));
348       printf (_("\
349   -D, --directory=DIRECTORY   add DIRECTORY to list for input files search\n"));
350       printf (_("\
351 If no input file is given or if it is -, standard input is read.\n"));
352       printf ("\n");
353       printf (_("\
354 Output file location:\n"));
355       printf (_("\
356   -o, --output-file=FILE      write output to specified file\n"));
357       printf (_("\
358 The results are written to standard output if no output file is specified\n\
359 or if it is -.\n"));
360       printf ("\n");
361       printf (_("\
362 Message selection:\n"));
363       printf (_("\
364   -d, --repeated              print only duplicates\n"));
365       printf (_("\
366   -u, --unique                print only unique messages, discard duplicates\n"));
367       printf ("\n");
368       printf (_("\
369 Input file syntax:\n"));
370       printf (_("\
371   -P, --properties-input      input file is in Java .properties syntax\n"));
372       printf (_("\
373       --stringtable-input     input file is in NeXTstep/GNUstep .strings syntax\n"));
374       printf ("\n");
375       printf (_("\
376 Output details:\n"));
377       printf (_("\
378   -t, --to-code=NAME          encoding for output\n"));
379       printf (_("\
380       --use-first             use first available translation for each\n\
381                               message, don't merge several translations\n"));
382       printf (_("\
383       --color                 use colors and other text attributes always\n\
384       --color=WHEN            use colors and other text attributes if WHEN.\n\
385                               WHEN may be 'always', 'never', 'auto', or 'html'.\n"));
386       printf (_("\
387       --style=STYLEFILE       specify CSS style rule file for --color\n"));
388       printf (_("\
389   -e, --no-escape             do not use C escapes in output (default)\n"));
390       printf (_("\
391   -E, --escape                use C escapes in output, no extended chars\n"));
392       printf (_("\
393       --force-po              write PO file even if empty\n"));
394       printf (_("\
395   -i, --indent                write the .po file using indented style\n"));
396       printf (_("\
397       --no-location           do not write '#: filename:line' lines\n"));
398       printf (_("\
399   -n, --add-location          generate '#: filename:line' lines (default)\n"));
400       printf (_("\
401       --strict                write out strict Uniforum conforming .po file\n"));
402       printf (_("\
403   -p, --properties-output     write out a Java .properties file\n"));
404       printf (_("\
405       --stringtable-output    write out a NeXTstep/GNUstep .strings file\n"));
406       printf (_("\
407   -w, --width=NUMBER          set output page width\n"));
408       printf (_("\
409       --no-wrap               do not break long message lines, longer than\n\
410                               the output page width, into several lines\n"));
411       printf (_("\
412   -s, --sort-output           generate sorted output\n"));
413       printf (_("\
414   -F, --sort-by-file          sort output by file location\n"));
415       printf ("\n");
416       printf (_("\
417 Informative output:\n"));
418       printf (_("\
419   -h, --help                  display this help and exit\n"));
420       printf (_("\
421   -V, --version               output version information and exit\n"));
422       printf ("\n");
423       /* TRANSLATORS: The placeholder indicates the bug-reporting address
424          for this package.  Please add _another line_ saying
425          "Report translation bugs to <...>\n" with the address for translation
426          bugs (typically your translation team's web or email address).  */
427       fputs (_("Report bugs to <bug-gnu-gettext@gnu.org>.\n"),
428              stdout);
429     }
430
431   exit (status);
432 }
433