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