1 /* Converts a translation catalog to a different character encoding. 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 "error.h" 33 #include "error-progname.h" 34 #include "progname.h" 35 #include "relocatable.h" 36 #include "basename.h" 37 #include "message.h" 38 #include "read-catalog.h" 39 #include "read-po.h" 40 #include "read-properties.h" 41 #include "read-stringtable.h" 42 #include "write-catalog.h" 43 #include "write-po.h" 44 #include "write-properties.h" 45 #include "write-stringtable.h" 46 #include "msgl-iconv.h" 47 #include "localcharset.h" 48 #include "exit.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. */ 56 static int force_po; 57 58 /* Target encoding. */ 59 static const char *to_code; 60 61 /* Long options. */ 62 static const struct option long_options[] = 63 { 64 { "add-location", no_argument, &line_comment, 1 }, 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 { "no-escape", no_argument, NULL, 'e' }, 71 { "no-location", no_argument, &line_comment, 0 }, 72 { "no-wrap", no_argument, NULL, CHAR_MAX + 1 }, 73 { "output-file", required_argument, NULL, 'o' }, 74 { "properties-input", no_argument, NULL, 'P' }, 75 { "properties-output", no_argument, NULL, 'p' }, 76 { "sort-by-file", no_argument, NULL, 'F' }, 77 { "sort-output", no_argument, NULL, 's' }, 78 { "strict", no_argument, NULL, 'S' }, 79 { "stringtable-input", no_argument, NULL, CHAR_MAX + 2 }, 80 { "stringtable-output", no_argument, NULL, CHAR_MAX + 3 }, 81 { "to-code", required_argument, NULL, 't' }, 82 { "version", no_argument, NULL, 'V' }, 83 { "width", required_argument, NULL, 'w', }, 84 { NULL, 0, NULL, 0 } 85 }; 86 87 88 /* Forward declaration of local functions. */ 89 static void usage (int status) 90 #if defined __GNUC__ && ((__GNUC__ == 2 && __GNUC_MINOR__ >= 5) || __GNUC__ > 2) 91 __attribute__ ((noreturn)) 92 #endif 93 ; 94 95 96 int 97 main (int argc, char **argv) 98 { 99 int opt; 100 bool do_help; 101 bool do_version; 102 char *output_file; 103 const char *input_file; 104 msgdomain_list_ty *result; 105 catalog_input_format_ty input_syntax = &input_format_po; 106 catalog_output_format_ty output_syntax = &output_format_po; 107 bool sort_by_filepos = false; 108 bool sort_by_msgid = false; 109 110 /* Set program name for messages. */ 111 set_program_name (argv[0]); 112 error_print_progname = maybe_print_progname; 113 114 #ifdef HAVE_SETLOCALE 115 /* Set locale via LC_ALL. */ 116 setlocale (LC_ALL, ""); 117 #endif 118 119 /* Set the text message domain. */ 120 bindtextdomain (PACKAGE, relocate (LOCALEDIR)); 121 bindtextdomain ("bison-runtime", relocate (BISON_LOCALEDIR)); 122 textdomain (PACKAGE); 123 124 /* Ensure that write errors on stdout are detected. */ 125 atexit (close_stdout); 126 127 /* Set default values for variables. */ 128 do_help = false; 129 do_version = false; 130 output_file = NULL; 131 input_file = NULL; 132 133 while ((opt = getopt_long (argc, argv, "D:eEFhio:pPst:Vw:", long_options, 134 NULL)) 135 != EOF) 136 switch (opt) 137 { 138 case '\0': /* Long option. */ 139 break; 140 141 case 'D': 142 dir_list_append (optarg); 143 break; 144 145 case 'e': 146 message_print_style_escape (false); 147 break; 148 149 case 'E': 150 message_print_style_escape (true); 151 break; 152 153 case 'F': 154 sort_by_filepos = true; 155 break; 156 157 case 'h': 158 do_help = true; 159 break; 160 161 case 'i': 162 message_print_style_indent (); 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 't': 186 to_code = optarg; 187 break; 188 189 case 'V': 190 do_version = true; 191 break; 192 193 case 'w': 194 { 195 int value; 196 char *endp; 197 value = strtol (optarg, &endp, 10); 198 if (endp != optarg) 199 message_page_width_set (value); 200 } 201 break; 202 203 case CHAR_MAX + 1: /* --no-wrap */ 204 message_page_width_ignore (); 205 break; 206 207 case CHAR_MAX + 2: /* --stringtable-input */ 208 input_syntax = &input_format_stringtable; 209 break; 210 211 case CHAR_MAX + 3: /* --stringtable-output */ 212 output_syntax = &output_format_stringtable; 213 break; 214 215 default: 216 usage (EXIT_FAILURE); 217 break; 218 } 219 220 /* Version information is requested. */ 221 if (do_version) 222 { 223 printf ("%s (GNU %s) %s\n", basename (program_name), PACKAGE, VERSION); 224 /* xgettext: no-wrap */ 225 printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\ 226 This is free software; see the source for copying conditions. There is NO\n\ 227 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ 228 "), 229 "2001-2006"); 230 printf (_("Written by %s.\n"), proper_name ("Bruno Haible")); 231 exit (EXIT_SUCCESS); 232 } 233 234 /* Help is requested. */ 235 if (do_help) 236 usage (EXIT_SUCCESS); 237 238 /* Test whether we have an .po file name as argument. */ 239 if (optind == argc) 240 input_file = "-"; 241 else if (optind + 1 == argc) 242 input_file = argv[optind]; 243 else 244 { 245 error (EXIT_SUCCESS, 0, _("at most one input file allowed")); 246 usage (EXIT_FAILURE); 247 } 248 249 /* Verify selected options. */ 250 if (!line_comment && sort_by_filepos) 251 error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"), 252 "--no-location", "--sort-by-file"); 253 254 if (sort_by_msgid && sort_by_filepos) 255 error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"), 256 "--sort-output", "--sort-by-file"); 257 258 /* Default for target encoding is current locale's encoding. */ 259 if (to_code == NULL) 260 to_code = locale_charset (); 261 262 /* Read input file. */ 263 result = read_catalog_file (input_file, input_syntax); 264 265 /* Convert if and only if the output syntax supports different encodings. */ 266 if (!output_syntax->requires_utf8) 267 result = iconv_msgdomain_list (result, to_code, input_file); 268 269 /* Sort the results. */ 270 if (sort_by_filepos) 271 msgdomain_list_sort_by_filepos (result); 272 else if (sort_by_msgid) 273 msgdomain_list_sort_by_msgid (result); 274 275 /* Write the merged message list out. */ 276 msgdomain_list_print (result, output_file, output_syntax, force_po, false); 277 278 exit (EXIT_SUCCESS); 279 } 280 281 282 /* Display usage information and exit. */ 283 static void 284 usage (int status) 285 { 286 if (status != EXIT_SUCCESS) 287 fprintf (stderr, _("Try `%s --help' for more information.\n"), 288 program_name); 289 else 290 { 291 printf (_("\ 292 Usage: %s [OPTION] [INPUTFILE]\n\ 293 "), program_name); 294 printf ("\n"); 295 printf (_("\ 296 Converts a translation catalog to a different character encoding.\n\ 297 ")); 298 printf ("\n"); 299 printf (_("\ 300 Mandatory arguments to long options are mandatory for short options too.\n")); 301 printf ("\n"); 302 printf (_("\ 303 Input file location:\n")); 304 printf (_("\ 305 INPUTFILE input PO file\n")); 306 printf (_("\ 307 -D, --directory=DIRECTORY add DIRECTORY to list for input files search\n")); 308 printf (_("\ 309 If no input file is given or if it is -, standard input is read.\n")); 310 printf ("\n"); 311 printf (_("\ 312 Output file location:\n")); 313 printf (_("\ 314 -o, --output-file=FILE write output to specified file\n")); 315 printf (_("\ 316 The results are written to standard output if no output file is specified\n\ 317 or if it is -.\n")); 318 printf ("\n"); 319 printf (_("\ 320 Conversion target:\n")); 321 printf (_("\ 322 -t, --to-code=NAME encoding for output\n")); 323 printf (_("\ 324 The default encoding is the current locale's encoding.\n")); 325 printf ("\n"); 326 printf (_("\ 327 Input file syntax:\n")); 328 printf (_("\ 329 -P, --properties-input input file is in Java .properties syntax\n")); 330 printf (_("\ 331 --stringtable-input input file is in NeXTstep/GNUstep .strings syntax\n")); 332 printf ("\n"); 333 printf (_("\ 334 Output details:\n")); 335 printf (_("\ 336 -e, --no-escape do not use C escapes in output (default)\n")); 337 printf (_("\ 338 -E, --escape use C escapes in output, no extended chars\n")); 339 printf (_("\ 340 --force-po write PO file even if empty\n")); 341 printf (_("\ 342 -i, --indent indented output style\n")); 343 printf (_("\ 344 --no-location suppress '#: filename:line' lines\n")); 345 printf (_("\ 346 --add-location preserve '#: filename:line' lines (default)\n")); 347 printf (_("\ 348 --strict strict Uniforum output style\n")); 349 printf (_("\ 350 -p, --properties-output write out a Java .properties file\n")); 351 printf (_("\ 352 --stringtable-output write out a NeXTstep/GNUstep .strings file\n")); 353 printf (_("\ 354 -w, --width=NUMBER set output page width\n")); 355 printf (_("\ 356 --no-wrap do not break long message lines, longer than\n\ 357 the output page width, into several lines\n")); 358 printf (_("\ 359 -s, --sort-output generate sorted output\n")); 360 printf (_("\ 361 -F, --sort-by-file sort output by file location\n")); 362 printf ("\n"); 363 printf (_("\ 364 Informative output:\n")); 365 printf (_("\ 366 -h, --help display this help and exit\n")); 367 printf (_("\ 368 -V, --version output version information and exit\n")); 369 printf ("\n"); 370 fputs (_("Report bugs to <bug-gnu-gettext@gnu.org>.\n"), 371 stdout); 372 } 373 374 exit (status); 375 } 376