1/* msgunfmt - converts binary .mo files to Uniforum style .po files 2 Copyright (C) 1995-1998, 2000-2007 Free Software Foundation, Inc. 3 Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, April 1995. 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#ifdef HAVE_CONFIG_H 19# include <config.h> 20#endif 21 22#include <getopt.h> 23#include <limits.h> 24#include <stdbool.h> 25#include <stdio.h> 26#include <stdlib.h> 27#include <locale.h> 28 29#include "closeout.h" 30#include "error.h" 31#include "error-progname.h" 32#include "progname.h" 33#include "relocatable.h" 34#include "basename.h" 35#include "message.h" 36#include "msgunfmt.h" 37#include "read-mo.h" 38#include "read-java.h" 39#include "read-csharp.h" 40#include "read-resources.h" 41#include "read-tcl.h" 42#include "write-catalog.h" 43#include "write-po.h" 44#include "write-properties.h" 45#include "write-stringtable.h" 46#include "propername.h" 47#include "gettext.h" 48 49#define _(str) gettext (str) 50 51 52/* Be more verbose. */ 53bool verbose; 54 55/* Java mode input file specification. */ 56static bool java_mode; 57static const char *java_resource_name; 58static const char *java_locale_name; 59 60/* C# mode input file specification. */ 61static bool csharp_mode; 62static const char *csharp_resource_name; 63static const char *csharp_locale_name; 64static const char *csharp_base_directory; 65 66/* C# resources mode input file specification. */ 67static bool csharp_resources_mode; 68 69/* Tcl mode input file specification. */ 70static bool tcl_mode; 71static const char *tcl_locale_name; 72static const char *tcl_base_directory; 73 74/* Force output of PO file even if empty. */ 75static int force_po; 76 77/* Long options. */ 78static const struct option long_options[] = 79{ 80 { "csharp", no_argument, NULL, CHAR_MAX + 4 }, 81 { "csharp-resources", no_argument, NULL, CHAR_MAX + 5 }, 82 { "escape", no_argument, NULL, 'E' }, 83 { "force-po", no_argument, &force_po, 1 }, 84 { "help", no_argument, NULL, 'h' }, 85 { "indent", no_argument, NULL, 'i' }, 86 { "java", no_argument, NULL, 'j' }, 87 { "locale", required_argument, NULL, 'l' }, 88 { "no-escape", no_argument, NULL, 'e' }, 89 { "no-wrap", no_argument, NULL, CHAR_MAX + 2 }, 90 { "output-file", required_argument, NULL, 'o' }, 91 { "properties-output", no_argument, NULL, 'p' }, 92 { "resource", required_argument, NULL, 'r' }, 93 { "sort-output", no_argument, NULL, 's' }, 94 { "strict", no_argument, NULL, 'S' }, 95 { "stringtable-output", no_argument, NULL, CHAR_MAX + 3 }, 96 { "tcl", no_argument, NULL, CHAR_MAX + 1 }, 97 { "verbose", no_argument, NULL, 'v' }, 98 { "version", no_argument, NULL, 'V' }, 99 { "width", required_argument, NULL, 'w', }, 100 { NULL, 0, NULL, 0 } 101}; 102 103 104/* Forward declaration of local functions. */ 105static void usage (int status) 106#if defined __GNUC__ && ((__GNUC__ == 2 && __GNUC_MINOR__ >= 5) || __GNUC__ > 2) 107 __attribute__ ((noreturn)) 108#endif 109; 110static void read_one_file (message_list_ty *mlp, const char *filename); 111 112 113int 114main (int argc, char **argv) 115{ 116 int optchar; 117 bool do_help = false; 118 bool do_version = false; 119 const char *output_file = "-"; 120 msgdomain_list_ty *result; 121 catalog_output_format_ty output_syntax = &output_format_po; 122 bool sort_by_msgid = false; 123 124 /* Set program name for messages. */ 125 set_program_name (argv[0]); 126 error_print_progname = maybe_print_progname; 127 128#ifdef HAVE_SETLOCALE 129 /* Set locale via LC_ALL. */ 130 setlocale (LC_ALL, ""); 131#endif 132 133 /* Set the text message domain. */ 134 bindtextdomain (PACKAGE, relocate (LOCALEDIR)); 135 bindtextdomain ("bison-runtime", relocate (BISON_LOCALEDIR)); 136 textdomain (PACKAGE); 137 138 /* Ensure that write errors on stdout are detected. */ 139 atexit (close_stdout); 140 141 while ((optchar = getopt_long (argc, argv, "d:eEhijl:o:pr:svVw:", 142 long_options, NULL)) 143 != EOF) 144 switch (optchar) 145 { 146 case '\0': 147 /* long option */ 148 break; 149 150 case 'd': 151 csharp_base_directory = optarg; 152 tcl_base_directory = optarg; 153 break; 154 155 case 'e': 156 message_print_style_escape (false); 157 break; 158 159 case 'E': 160 message_print_style_escape (true); 161 break; 162 163 case 'h': 164 do_help = true; 165 break; 166 167 case 'i': 168 message_print_style_indent (); 169 break; 170 171 case 'j': 172 java_mode = true; 173 break; 174 175 case 'l': 176 java_locale_name = optarg; 177 csharp_locale_name = optarg; 178 tcl_locale_name = optarg; 179 break; 180 181 case 'o': 182 output_file = optarg; 183 break; 184 185 case 'p': 186 output_syntax = &output_format_properties; 187 break; 188 189 case 'r': 190 java_resource_name = optarg; 191 csharp_resource_name = optarg; 192 break; 193 194 case 's': 195 sort_by_msgid = true; 196 break; 197 198 case 'S': 199 message_print_style_uniforum (); 200 break; 201 202 case 'v': 203 verbose = true; 204 break; 205 206 case 'V': 207 do_version = true; 208 break; 209 210 case 'w': 211 { 212 int value; 213 char *endp; 214 value = strtol (optarg, &endp, 10); 215 if (endp != optarg) 216 message_page_width_set (value); 217 } 218 break; 219 220 case CHAR_MAX + 1: /* --tcl */ 221 tcl_mode = true; 222 break; 223 224 case CHAR_MAX + 2: /* --no-wrap */ 225 message_page_width_ignore (); 226 break; 227 228 case CHAR_MAX + 3: /* --stringtable-output */ 229 output_syntax = &output_format_stringtable; 230 break; 231 232 case CHAR_MAX + 4: /* --csharp */ 233 csharp_mode = true; 234 break; 235 236 case CHAR_MAX + 5: /* --csharp-resources */ 237 csharp_resources_mode = true; 238 break; 239 240 default: 241 usage (EXIT_FAILURE); 242 break; 243 } 244 245 /* Version information is requested. */ 246 if (do_version) 247 { 248 printf ("%s (GNU %s) %s\n", basename (program_name), PACKAGE, VERSION); 249 /* xgettext: no-wrap */ 250 printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\ 251License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n\ 252This is free software: you are free to change and redistribute it.\n\ 253There is NO WARRANTY, to the extent permitted by law.\n\ 254"), 255 "1995-1998, 2000-2007"); 256 printf (_("Written by %s.\n"), proper_name ("Ulrich Drepper")); 257 exit (EXIT_SUCCESS); 258 } 259 260 /* Help is requested. */ 261 if (do_help) 262 usage (EXIT_SUCCESS); 263 264 /* Check for contradicting options. */ 265 { 266 unsigned int modes = 267 (java_mode ? 1 : 0) 268 | (csharp_mode ? 2 : 0) 269 | (csharp_resources_mode ? 4 : 0) 270 | (tcl_mode ? 8 : 0); 271 static const char *mode_options[] = 272 { "--java", "--csharp", "--csharp-resources", "--tcl" }; 273 /* More than one bit set? */ 274 if (modes & (modes - 1)) 275 { 276 const char *first_option; 277 const char *second_option; 278 unsigned int i; 279 for (i = 0; ; i++) 280 if (modes & (1 << i)) 281 break; 282 first_option = mode_options[i]; 283 for (i = i + 1; ; i++) 284 if (modes & (1 << i)) 285 break; 286 second_option = mode_options[i]; 287 error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"), 288 first_option, second_option); 289 } 290 } 291 if (java_mode) 292 { 293 if (optind < argc) 294 { 295 error (EXIT_FAILURE, 0, 296 _("%s and explicit file names are mutually exclusive"), 297 "--java"); 298 } 299 } 300 else if (csharp_mode) 301 { 302 if (optind < argc) 303 { 304 error (EXIT_FAILURE, 0, 305 _("%s and explicit file names are mutually exclusive"), 306 "--csharp"); 307 } 308 if (csharp_locale_name == NULL) 309 { 310 error (EXIT_SUCCESS, 0, 311 _("%s requires a \"-l locale\" specification"), 312 "--csharp"); 313 usage (EXIT_FAILURE); 314 } 315 if (csharp_base_directory == NULL) 316 { 317 error (EXIT_SUCCESS, 0, 318 _("%s requires a \"-d directory\" specification"), 319 "--csharp"); 320 usage (EXIT_FAILURE); 321 } 322 } 323 else if (tcl_mode) 324 { 325 if (optind < argc) 326 { 327 error (EXIT_FAILURE, 0, 328 _("%s and explicit file names are mutually exclusive"), 329 "--tcl"); 330 } 331 if (tcl_locale_name == NULL) 332 { 333 error (EXIT_SUCCESS, 0, 334 _("%s requires a \"-l locale\" specification"), 335 "--tcl"); 336 usage (EXIT_FAILURE); 337 } 338 if (tcl_base_directory == NULL) 339 { 340 error (EXIT_SUCCESS, 0, 341 _("%s requires a \"-d directory\" specification"), 342 "--tcl"); 343 usage (EXIT_FAILURE); 344 } 345 } 346 else 347 { 348 if (java_resource_name != NULL) 349 { 350 error (EXIT_SUCCESS, 0, _("%s is only valid with %s or %s"), 351 "--resource", "--java", "--csharp"); 352 usage (EXIT_FAILURE); 353 } 354 if (java_locale_name != NULL) 355 { 356 error (EXIT_SUCCESS, 0, _("%s is only valid with %s or %s"), 357 "--locale", "--java", "--csharp"); 358 usage (EXIT_FAILURE); 359 } 360 } 361 362 /* Read the given .mo file. */ 363 if (java_mode) 364 { 365 result = msgdomain_read_java (java_resource_name, java_locale_name); 366 } 367 else if (csharp_mode) 368 { 369 result = msgdomain_read_csharp (csharp_resource_name, csharp_locale_name, 370 csharp_base_directory); 371 } 372 else if (tcl_mode) 373 { 374 result = msgdomain_read_tcl (tcl_locale_name, tcl_base_directory); 375 } 376 else 377 { 378 message_list_ty *mlp; 379 380 mlp = message_list_alloc (false); 381 if (optind < argc) 382 { 383 do 384 read_one_file (mlp, argv[optind]); 385 while (++optind < argc); 386 } 387 else 388 read_one_file (mlp, "-"); 389 390 result = msgdomain_list_alloc (false); 391 result->item[0]->messages = mlp; 392 } 393 394 /* Sorting the list of messages. */ 395 if (sort_by_msgid) 396 msgdomain_list_sort_by_msgid (result); 397 398 /* Write the resulting message list to the given .po file. */ 399 msgdomain_list_print (result, output_file, output_syntax, force_po, false); 400 401 /* No problems. */ 402 exit (EXIT_SUCCESS); 403} 404 405 406/* Display usage information and exit. */ 407static void 408usage (int status) 409{ 410 if (status != EXIT_SUCCESS) 411 fprintf (stderr, _("Try `%s --help' for more information.\n"), 412 program_name); 413 else 414 { 415 printf (_("\ 416Usage: %s [OPTION] [FILE]...\n\ 417"), program_name); 418 printf ("\n"); 419 printf (_("\ 420Convert binary message catalog to Uniforum style .po file.\n\ 421")); 422 printf ("\n"); 423 printf (_("\ 424Mandatory arguments to long options are mandatory for short options too.\n")); 425 printf ("\n"); 426 printf (_("\ 427Operation mode:\n")); 428 printf (_("\ 429 -j, --java Java mode: input is a Java ResourceBundle class\n")); 430 printf (_("\ 431 --csharp C# mode: input is a .NET .dll file\n")); 432 printf (_("\ 433 --csharp-resources C# resources mode: input is a .NET .resources file\n")); 434 printf (_("\ 435 --tcl Tcl mode: input is a tcl/msgcat .msg file\n")); 436 printf ("\n"); 437 printf (_("\ 438Input file location:\n")); 439 printf (_("\ 440 FILE ... input .mo files\n")); 441 printf (_("\ 442If no input file is given or if it is -, standard input is read.\n")); 443 printf ("\n"); 444 printf (_("\ 445Input file location in Java mode:\n")); 446 printf (_("\ 447 -r, --resource=RESOURCE resource name\n")); 448 printf (_("\ 449 -l, --locale=LOCALE locale name, either language or language_COUNTRY\n")); 450 printf (_("\ 451The class name is determined by appending the locale name to the resource name,\n\ 452separated with an underscore. The class is located using the CLASSPATH.\n\ 453")); 454 printf ("\n"); 455 printf (_("\ 456Input file location in C# mode:\n")); 457 printf (_("\ 458 -r, --resource=RESOURCE resource name\n")); 459 printf (_("\ 460 -l, --locale=LOCALE locale name, either language or language_COUNTRY\n")); 461 printf (_("\ 462 -d DIRECTORY base directory for locale dependent .dll files\n")); 463 printf (_("\ 464The -l and -d options are mandatory. The .dll file is located in a\n\ 465subdirectory of the specified directory whose name depends on the locale.\n")); 466 printf ("\n"); 467 printf (_("\ 468Input file location in Tcl mode:\n")); 469 printf (_("\ 470 -l, --locale=LOCALE locale name, either language or language_COUNTRY\n")); 471 printf (_("\ 472 -d DIRECTORY base directory of .msg message catalogs\n")); 473 printf (_("\ 474The -l and -d options are mandatory. The .msg file is located in the\n\ 475specified directory.\n")); 476 printf ("\n"); 477 printf (_("\ 478Output file location:\n")); 479 printf (_("\ 480 -o, --output-file=FILE write output to specified file\n")); 481 printf (_("\ 482The results are written to standard output if no output file is specified\n\ 483or if it is -.\n")); 484 printf ("\n"); 485 printf (_("\ 486Output details:\n")); 487 printf (_("\ 488 -e, --no-escape do not use C escapes in output (default)\n")); 489 printf (_("\ 490 -E, --escape use C escapes in output, no extended chars\n")); 491 printf (_("\ 492 --force-po write PO file even if empty\n")); 493 printf (_("\ 494 -i, --indent write indented output style\n")); 495 printf (_("\ 496 --strict write strict uniforum style\n")); 497 printf (_("\ 498 -p, --properties-output write out a Java .properties file\n")); 499 printf (_("\ 500 --stringtable-output write out a NeXTstep/GNUstep .strings file\n")); 501 printf (_("\ 502 -w, --width=NUMBER set output page width\n")); 503 printf (_("\ 504 --no-wrap do not break long message lines, longer than\n\ 505 the output page width, into several lines\n")); 506 printf (_("\ 507 -s, --sort-output generate sorted output\n")); 508 printf ("\n"); 509 printf (_("\ 510Informative output:\n")); 511 printf (_("\ 512 -h, --help display this help and exit\n")); 513 printf (_("\ 514 -V, --version output version information and exit\n")); 515 printf (_("\ 516 -v, --verbose increase verbosity level\n")); 517 printf ("\n"); 518 /* TRANSLATORS: The placeholder indicates the bug-reporting address 519 for this package. Please add _another line_ saying 520 "Report translation bugs to <...>\n" with the address for translation 521 bugs (typically your translation team's web or email address). */ 522 fputs (_("Report bugs to <bug-gnu-gettext@gnu.org>.\n"), 523 stdout); 524 } 525 526 exit (status); 527} 528 529 530static void 531read_one_file (message_list_ty *mlp, const char *filename) 532{ 533 if (csharp_resources_mode) 534 read_resources_file (mlp, filename); 535 else 536 read_mo_file (mlp, filename); 537} 538