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