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