xref: /netbsd-src/external/gpl2/gettext/dist/gettext-tools/src/msgcat.c (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
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