• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Creates an English translation catalog.
2    Copyright (C) 2001-2007, 2009-2010, 2012, 2014, 2016, 2018-2020 Free Software
3    Foundation, 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 <https://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 <textstyle.h>
31 
32 #include "noreturn.h"
33 #include "closeout.h"
34 #include "dir-list.h"
35 #include "error.h"
36 #include "error-progname.h"
37 #include "progname.h"
38 #include "relocatable.h"
39 #include "basename-lgpl.h"
40 #include "message.h"
41 #include "read-catalog.h"
42 #include "read-po.h"
43 #include "read-properties.h"
44 #include "read-stringtable.h"
45 #include "msgl-english.h"
46 #include "msgl-header.h"
47 #include "write-catalog.h"
48 #include "write-po.h"
49 #include "write-properties.h"
50 #include "write-stringtable.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 /* Long options.  */
61 static const struct option long_options[] =
62 {
63   { "add-location", optional_argument, NULL, 'n' },
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   { "lang", required_argument, NULL, CHAR_MAX + 4 },
71   { "no-escape", no_argument, NULL, 'e' },
72   { "no-location", no_argument, NULL, CHAR_MAX + 7 },
73   { "no-wrap", no_argument, NULL, CHAR_MAX + 1 },
74   { "output-file", required_argument, NULL, 'o' },
75   { "properties-input", no_argument, NULL, 'P' },
76   { "properties-output", no_argument, NULL, 'p' },
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 + 2 },
81   { "stringtable-output", no_argument, NULL, CHAR_MAX + 3 },
82   { "style", required_argument, NULL, CHAR_MAX + 6 },
83   { "version", no_argument, NULL, 'V' },
84   { "width", required_argument, NULL, 'w' },
85   { NULL, 0, NULL, 0 }
86 };
87 
88 
89 /* Forward declaration of local functions.  */
90 _GL_NORETURN_FUNC static void usage (int status);
91 
92 
93 int
main(int argc,char ** argv)94 main (int argc, char **argv)
95 {
96   int opt;
97   bool do_help;
98   bool do_version;
99   char *output_file;
100   msgdomain_list_ty *result;
101   catalog_input_format_ty input_syntax = &input_format_po;
102   catalog_output_format_ty output_syntax = &output_format_po;
103   bool sort_by_filepos = false;
104   bool sort_by_msgid = false;
105   /* Language (ISO-639 code) and optional territory (ISO-3166 code).  */
106   const char *catalogname = NULL;
107 
108   /* Set program name for messages.  */
109   set_program_name (argv[0]);
110   error_print_progname = maybe_print_progname;
111 
112   /* Set locale via LC_ALL.  */
113   setlocale (LC_ALL, "");
114 
115   /* Set the text message domain.  */
116   bindtextdomain (PACKAGE, relocate (LOCALEDIR));
117   bindtextdomain ("bison-runtime", relocate (BISON_LOCALEDIR));
118   textdomain (PACKAGE);
119 
120   /* Ensure that write errors on stdout are detected.  */
121   atexit (close_stdout);
122 
123   /* Set default values for variables.  */
124   do_help = false;
125   do_version = false;
126   output_file = NULL;
127 
128   while ((opt = getopt_long (argc, argv,
129                              "D:eEFhin:o:pPsVw:",
130                              long_options, NULL)) != EOF)
131     switch (opt)
132       {
133       case '\0':                /* Long option.  */
134         break;
135 
136       case 'D':
137         dir_list_append (optarg);
138         break;
139 
140       case 'e':
141         message_print_style_escape (false);
142         break;
143 
144       case 'E':
145         message_print_style_escape (true);
146         break;
147 
148       case 'F':
149         sort_by_filepos = true;
150         break;
151 
152       case 'h':
153         do_help = true;
154         break;
155 
156       case 'i':
157         message_print_style_indent ();
158         break;
159 
160       case 'n':
161         if (handle_filepos_comment_option (optarg))
162           usage (EXIT_FAILURE);
163         break;
164 
165       case 'o':
166         output_file = optarg;
167         break;
168 
169       case 'p':
170         output_syntax = &output_format_properties;
171         break;
172 
173       case 'P':
174         input_syntax = &input_format_properties;
175         break;
176 
177       case 's':
178         sort_by_msgid = true;
179         break;
180 
181       case 'S':
182         message_print_style_uniforum ();
183         break;
184 
185       case 'V':
186         do_version = true;
187         break;
188 
189       case 'w':
190         {
191           int value;
192           char *endp;
193           value = strtol (optarg, &endp, 10);
194           if (endp != optarg)
195             message_page_width_set (value);
196         }
197         break;
198 
199       case CHAR_MAX + 1: /* --no-wrap */
200         message_page_width_ignore ();
201         break;
202 
203       case CHAR_MAX + 2: /* --stringtable-input */
204         input_syntax = &input_format_stringtable;
205         break;
206 
207       case CHAR_MAX + 3: /* --stringtable-output */
208         output_syntax = &output_format_stringtable;
209         break;
210 
211       case CHAR_MAX + 4: /* --lang */
212         catalogname = optarg;
213         break;
214 
215       case CHAR_MAX + 5: /* --color */
216         if (handle_color_option (optarg) || color_test_mode)
217           usage (EXIT_FAILURE);
218         break;
219 
220       case CHAR_MAX + 6: /* --style */
221         handle_style_option (optarg);
222         break;
223 
224       case CHAR_MAX + 7: /* --no-location */
225         message_print_style_filepos (filepos_comment_none);
226         break;
227 
228       default:
229         usage (EXIT_FAILURE);
230         break;
231       }
232 
233   /* Version information is requested.  */
234   if (do_version)
235     {
236       printf ("%s (GNU %s) %s\n", last_component (program_name),
237               PACKAGE, VERSION);
238       /* xgettext: no-wrap */
239       printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
240 License GPLv3+: GNU GPL version 3 or later <%s>\n\
241 This is free software: you are free to change and redistribute it.\n\
242 There is NO WARRANTY, to the extent permitted by law.\n\
243 "),
244               "2001-2020", "https://gnu.org/licenses/gpl.html");
245       printf (_("Written by %s.\n"), proper_name ("Bruno Haible"));
246       exit (EXIT_SUCCESS);
247     }
248 
249   /* Help is requested.  */
250   if (do_help)
251     usage (EXIT_SUCCESS);
252 
253   /* Test whether we have an .po file name as argument.  */
254   if (optind >= argc)
255     {
256       error (EXIT_SUCCESS, 0, _("no input file given"));
257       usage (EXIT_FAILURE);
258     }
259   if (optind + 1 != argc)
260     {
261       error (EXIT_SUCCESS, 0, _("exactly one input file required"));
262       usage (EXIT_FAILURE);
263     }
264 
265   /* Verify selected options.  */
266   if (sort_by_msgid && sort_by_filepos)
267     error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"),
268            "--sort-output", "--sort-by-file");
269 
270   /* Read input file.  */
271   result = read_catalog_file (argv[optind], input_syntax);
272 
273   /* Add English translations.  */
274   result = msgdomain_list_english (result);
275 
276   /* Sort the results.  */
277   if (sort_by_filepos)
278     msgdomain_list_sort_by_filepos (result);
279   else if (sort_by_msgid)
280     msgdomain_list_sort_by_msgid (result);
281 
282   /* Set the Language field in the header.  */
283   if (catalogname != NULL)
284     msgdomain_list_set_header_field (result, "Language:", catalogname);
285 
286   /* Write the merged message list out.  */
287   msgdomain_list_print (result, output_file, output_syntax, force_po, false);
288 
289   exit (EXIT_SUCCESS);
290 }
291 
292 
293 /* Display usage information and exit.  */
294 static void
usage(int status)295 usage (int status)
296 {
297   if (status != EXIT_SUCCESS)
298     fprintf (stderr, _("Try '%s --help' for more information.\n"),
299              program_name);
300   else
301     {
302       printf (_("\
303 Usage: %s [OPTION] INPUTFILE\n\
304 "), program_name);
305       printf ("\n");
306       /* xgettext: no-wrap */
307       printf (_("\
308 Creates an English translation catalog.  The input file is the last\n\
309 created English PO file, or a PO Template file (generally created by\n\
310 xgettext).  Untranslated entries are assigned a translation that is\n\
311 identical to the msgid.\n\
312 "));
313       printf ("\n");
314       printf (_("\
315 Mandatory arguments to long options are mandatory for short options too.\n"));
316       printf ("\n");
317       printf (_("\
318 Input file location:\n"));
319       printf (_("\
320   INPUTFILE                   input PO or POT file\n"));
321       printf (_("\
322   -D, --directory=DIRECTORY   add DIRECTORY to list for input files search\n"));
323       printf (_("\
324 If input file is -, standard input is read.\n"));
325       printf ("\n");
326       printf (_("\
327 Output file location:\n"));
328       printf (_("\
329   -o, --output-file=FILE      write output to specified file\n"));
330       printf (_("\
331 The results are written to standard output if no output file is specified\n\
332 or if it is -.\n"));
333       printf ("\n");
334       printf (_("\
335 Input file syntax:\n"));
336       printf (_("\
337   -P, --properties-input      input file is in Java .properties syntax\n"));
338       printf (_("\
339       --stringtable-input     input file is in NeXTstep/GNUstep .strings syntax\n"));
340       printf ("\n");
341       printf (_("\
342 Output details:\n"));
343       printf (_("\
344       --lang=CATALOGNAME      set 'Language' field in the header entry\n"));
345       printf (_("\
346       --color                 use colors and other text attributes always\n\
347       --color=WHEN            use colors and other text attributes if WHEN.\n\
348                               WHEN may be 'always', 'never', 'auto', or 'html'.\n"));
349       printf (_("\
350       --style=STYLEFILE       specify CSS style rule file for --color\n"));
351       printf (_("\
352   -e, --no-escape             do not use C escapes in output (default)\n"));
353       printf (_("\
354   -E, --escape                use C escapes in output, no extended chars\n"));
355       printf (_("\
356       --force-po              write PO file even if empty\n"));
357       printf (_("\
358   -i, --indent                indented output style\n"));
359       printf (_("\
360       --no-location           suppress '#: filename:line' lines\n"));
361       printf (_("\
362   -n, --add-location          preserve '#: filename:line' lines (default)\n"));
363       printf (_("\
364       --strict                strict Uniforum output style\n"));
365       printf (_("\
366   -p, --properties-output     write out a Java .properties file\n"));
367       printf (_("\
368       --stringtable-output    write out a NeXTstep/GNUstep .strings file\n"));
369       printf (_("\
370   -w, --width=NUMBER          set output page width\n"));
371       printf (_("\
372       --no-wrap               do not break long message lines, longer than\n\
373                               the output page width, into several lines\n"));
374       printf (_("\
375   -s, --sort-output           generate sorted output\n"));
376       printf (_("\
377   -F, --sort-by-file          sort output by file location\n"));
378       printf ("\n");
379       printf (_("\
380 Informative output:\n"));
381       printf (_("\
382   -h, --help                  display this help and exit\n"));
383       printf (_("\
384   -V, --version               output version information and exit\n"));
385       printf ("\n");
386       /* TRANSLATORS: The first placeholder is the web address of the Savannah
387          project of this package.  The second placeholder is the bug-reporting
388          email address for this package.  Please add _another line_ saying
389          "Report translation bugs to <...>\n" with the address for translation
390          bugs (typically your translation team's web or email address).  */
391       printf(_("\
392 Report bugs in the bug tracker at <%s>\n\
393 or by email to <%s>.\n"),
394              "https://savannah.gnu.org/projects/gettext",
395              "bug-gettext@gnu.org");
396     }
397 
398   exit (status);
399 }
400