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. */ 57static int force_po; 58 59/* Target encoding. */ 60static const char *to_code; 61 62/* Long options. */ 63static 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. */ 95static void usage (int status) 96#if defined __GNUC__ && ((__GNUC__ == 2 && __GNUC_MINOR__ >= 5) || __GNUC__ > 2) 97 __attribute__ ((noreturn)) 98#endif 99; 100 101 102int 103main (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\ 272This is free software; see the source for copying conditions. There is NO\n\ 273warranty; 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. */ 329static void 330usage (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 (_("\ 338Usage: %s [OPTION] [INPUTFILE]...\n\ 339"), program_name); 340 printf ("\n"); 341 /* xgettext: no-wrap */ 342 printf (_("\ 343Concatenates and merges the specified PO files.\n\ 344Find messages which are common to two or more of the specified PO files.\n\ 345By using the --more-than option, greater commonality may be requested\n\ 346before messages are printed. Conversely, the --less-than option may be\n\ 347used to specify less commonality before messages are printed (i.e.\n\ 348--less-than=2 will only print the unique messages). Translations,\n\ 349comments and extract comments will be cumulated, except that if --use-first\n\ 350is specified, they will be taken from the first PO file to define them.\n\ 351File positions from all PO files will be cumulated.\n\ 352")); 353 printf ("\n"); 354 printf (_("\ 355Mandatory arguments to long options are mandatory for short options too.\n")); 356 printf ("\n"); 357 printf (_("\ 358Input 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 (_("\ 366If input file is -, standard input is read.\n")); 367 printf ("\n"); 368 printf (_("\ 369Output file location:\n")); 370 printf (_("\ 371 -o, --output-file=FILE write output to specified file\n")); 372 printf (_("\ 373The results are written to standard output if no output file is specified\n\ 374or if it is -.\n")); 375 printf ("\n"); 376 printf (_("\ 377Message 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 (_("\ 389Input 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 (_("\ 397Output 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 (_("\ 432Informative 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