home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / gettext-0.10.24-src.tgz / tar.out / fsf / gettext / src / msgunfmt.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  10KB  |  399 lines

  1. /* msgunfmt - converts binary .mo files to Uniforum style .po files
  2.    Copyright (C) 1995, 1996 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
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
  18.  
  19. #ifdef HAVE_CONFIG_H
  20. # include <config.h>
  21. #endif
  22.  
  23. #include <ctype.h>
  24. #include <errno.h>
  25. #include <getopt.h>
  26. #include <stdio.h>
  27. #include <sys/param.h>
  28. #include <sys/types.h>
  29.  
  30. #ifdef STDC_HEADERS
  31. # include <stdlib.h>
  32. #endif
  33.  
  34. #ifdef HAVE_LOCALE_H
  35. # include <locale.h>
  36. #endif
  37.  
  38. #include "hash.h"
  39.  
  40. #include "error.h"
  41. #include "getline.h"
  42. #include "printf.h"
  43. #include <system.h>
  44.  
  45. #include "gettext.h"
  46. #include "domain.h"
  47. #include "hash-string.h"
  48. #include <libintl.h>
  49. #include "message.h"
  50.  
  51. #define _(str) gettext (str)
  52.  
  53. #ifndef errno
  54. extern int errno;
  55. #endif
  56.  
  57.  
  58. /* String containing name the program is called with.  */
  59. const char *program_name;
  60.  
  61. /* Long options.  */
  62. static const struct option long_options[] =
  63. {
  64.   { "escape", no_argument, NULL, 'E' },
  65.   { "help", no_argument, NULL, 'h' },
  66.   { "indent", no_argument, NULL, 'i' },
  67.   { "no-escape", no_argument, NULL, 'e' },
  68.   { "output-file", required_argument, NULL, 'o' },
  69.   { "strict", no_argument, NULL, 'S' },
  70.   { "version", no_argument, NULL, 'V' },
  71.   { "width", required_argument, NULL, 'w', },
  72.   { NULL, 0, NULL, 0 }
  73. };
  74.  
  75.  
  76. /* This defines the byte order within the file.  It needs to be set
  77.    appropriately once we have the file open.  */
  78. static enum { MO_LITTLE_ENDIAN, MO_BIG_ENDIAN } endian;
  79.  
  80.  
  81. /* Prototypes for local functions.  */
  82. static void usage PARAMS ((int __status));
  83. static void error_print PARAMS ((void));
  84. static nls_uint32 read32 PARAMS ((FILE *__fp, const char *__fn));
  85. static void seek32 PARAMS ((FILE *__fp, const char *__fn, long __offset));
  86. static char *string32 PARAMS ((FILE *__fp, const char *__fn, long __offset));
  87. static message_list_ty *read_mo_file PARAMS ((message_list_ty *__mlp,
  88.                           const char *__fn));
  89.  
  90.  
  91. int
  92. main (argc, argv)
  93.      int argc;
  94.      char **argv;
  95. {
  96.   int optchar;
  97.   int do_help = 0;
  98.   int do_version = 0;
  99.   const char *output_file = "-";
  100.   message_list_ty *mlp = NULL;
  101.  
  102.   /* Set program name for messages.  */
  103.   program_name = argv[0];
  104.   error_print_progname = error_print;
  105.  
  106. #ifdef HAVE_SETLOCALE
  107.   /* Set locale via LC_ALL.  */
  108.   setlocale (LC_ALL, "");
  109. #endif
  110.  
  111.   /* Set the text message domain.  */
  112.   bindtextdomain (PACKAGE, LOCALEDIR);
  113.   textdomain (PACKAGE);
  114.  
  115.   while ((optchar = getopt_long (argc, argv, "hio:Vw:", long_options, NULL))
  116.      != EOF)
  117.     switch (optchar)
  118.       {
  119.       case '\0':
  120.     /* long option */
  121.     break;
  122.  
  123.       case 'e':
  124.     message_print_style_escape (0);
  125.     break;
  126.  
  127.       case 'E':
  128.     message_print_style_escape (1);
  129.     break;
  130.  
  131.       case 'h':
  132.     do_help = 1;
  133.     break;
  134.  
  135.       case 'i':
  136.     message_print_style_indent ();
  137.     break;
  138.  
  139.       case 'o':
  140.     output_file = optarg;
  141.     break;
  142.  
  143.       case 'S':
  144.     message_print_style_uniforum ();
  145.     break;
  146.  
  147.       case 'V':
  148.     do_version = 1;
  149.     break;
  150.  
  151.       case 'w':
  152.     {
  153.       int value;
  154.       char *endp;
  155.       value = strtol (optarg, &endp, 10);
  156.       if (endp != optarg)
  157.         message_page_width_set (value);
  158.     }
  159.     break;
  160.  
  161.       default:
  162.     usage (EXIT_FAILURE);
  163.     break;
  164.       }
  165.  
  166.   /* Version information is requested.  */
  167.   if (do_version)
  168.     {
  169.       fprintf (stderr, "%s - GNU %s %s\n", program_name, PACKAGE, VERSION);
  170.       exit (EXIT_SUCCESS);
  171.     }
  172.  
  173.   /* Help is requested.  */
  174.   if (do_help)
  175.     usage (EXIT_SUCCESS);
  176.  
  177.   /* Read the given .mo file. */
  178.   if (optind < argc)
  179.     do
  180.       mlp = read_mo_file (mlp, argv[optind]);
  181.     while (++optind < argc);
  182.   else
  183.     mlp = read_mo_file (NULL, "-");
  184.  
  185.   /* Write the resulting message list to the given .po file.  */
  186.   message_list_print (mlp, output_file, 0, 0);
  187.  
  188.   /* No problems.  */
  189.   exit (EXIT_SUCCESS);
  190. }
  191.  
  192.  
  193. /* Display usage information and exit.  */
  194. static void
  195. usage (status)
  196.      int status;
  197. {
  198.   if (status != EXIT_SUCCESS)
  199.     fprintf (stderr, _("Try `%s --help' for more information\n"),
  200.          program_name);
  201.   else
  202.     {
  203.       /* xgettext: no-wrap */
  204.       printf (_("\
  205. Usage: %s [OPTION] [FILE]...\n\
  206. Mandatory arguments to long options are mandatory for short options too.\n\
  207.   -e, --no-escape          do not use C escapes in output (default)\n\
  208.   -E, --escape             use C escapes in output, no extended chars\n\
  209.   -h, --help               display this help and exit\n\
  210.   -i, --indent             write indented output style\n\
  211.   -o, --output-file=FILE   write output into FILE instead of standard output\n\
  212.       --strict             write strict uniforum style\n\
  213.   -V, --version            output version information and exit\n\
  214.   -w, --width=NUMBER       set output page width\n"),
  215.           program_name);
  216.       /* xgettext: no-wrap */
  217.       fputs (_("\n\
  218. Convert binary .mo files to Uniforum style .po files.\n\
  219. Both little-endian and big-endian .mo files are handled.\n\
  220. If no input file is given or it is -, standard input is read.\n\
  221. By default the output is written to standard output.\n"),
  222.          stdout);
  223.     }
  224.  
  225.   exit (status);
  226. }
  227.  
  228.  
  229. /* The address of this function will be assigned to the hook in the error
  230.    functions.  */
  231. static void
  232. error_print ()
  233. {
  234.   /* We don't want the program name to be printed in messages.  Emacs'
  235.      compile.el does not like this.  */
  236. }
  237.  
  238.  
  239. /* This function reads a 32-bit number from the file, and assembles it
  240.    according to the current ``endian'' setting.  */
  241. static nls_uint32
  242. read32 (fp, fn)
  243.      FILE *fp;
  244.      const char *fn;
  245. {
  246.   int c1, c2, c3, c4;
  247.  
  248.   c1 = getc (fp);
  249.   if (c1 == EOF)
  250.     {
  251.     bomb:
  252.       if (ferror (fp))
  253.     error (EXIT_FAILURE, errno, _("error while reading \"%s\""), fn);
  254.       error (EXIT_FAILURE, 0, _("file \"%s\" truncated"), fn);
  255.     }
  256.   c2 = getc (fp);
  257.   if (c2 == EOF)
  258.     goto bomb;
  259.   c3 = getc (fp);
  260.   if (c3 == EOF)
  261.     goto bomb;
  262.   c4 = getc (fp);
  263.   if (c4 == EOF)
  264.     goto bomb;
  265.   if (endian == MO_LITTLE_ENDIAN)
  266.     return (((nls_uint32) c1)
  267.         | ((nls_uint32) c2 << 8)
  268.         | ((nls_uint32) c3 << 16)
  269.         | ((nls_uint32) c4 << 24));
  270.  
  271.   return (((nls_uint32) c1 << 24)
  272.       | ((nls_uint32) c2 << 16)
  273.       | ((nls_uint32) c3 << 8)
  274.       | ((nls_uint32) c4));
  275. }
  276.  
  277.  
  278. static void
  279. seek32 (fp, fn, offset)
  280.      FILE *fp;
  281.      const char *fn;
  282.      long offset;
  283. {
  284.   if (fseek (fp, offset, 0) < 0)
  285.     error (EXIT_FAILURE, errno, _("seek \"%s\" offset %ld failed"),
  286.        fn, offset);
  287. }
  288.  
  289.  
  290. static char *
  291. string32 (fp, fn, offset)
  292.      FILE *fp;
  293.      const char *fn;
  294.      long offset;
  295. {
  296.   long length;
  297.   char *buffer;
  298.   long n;
  299.  
  300.   /* Read the string_desc structure, describing where in the file to
  301.      find the string.  */
  302.   seek32 (fp, fn, offset);
  303.   length = read32 (fp, fn);
  304.   offset = read32 (fp, fn);
  305.  
  306.   /* Allocate memory for the string to be read into.  Leave space for
  307.      the NUL on the end.  */
  308.   buffer = xmalloc (length + 1);
  309.  
  310.   /* Read in the string.  Complain if there is an error or it comes up
  311.      short.  Add the NUL ourselves.  */
  312.   seek32 (fp, fn, offset);
  313.   n = fread (buffer, 1, length, fp);
  314.   if (n != length)
  315.     {
  316.       if (ferror (fp))
  317.     error (EXIT_FAILURE, errno, _("error while reading \"%s\""), fn);
  318.       error (EXIT_FAILURE, 0, _("file \"%s\" truncated"), fn);
  319.     }
  320.   buffer[length] = 0;
  321.  
  322.   /* Return the string to the caller.  */
  323.   return buffer;
  324. }
  325.  
  326.  
  327. /* This function reads and existing .mo file.  Return a message list.  */
  328. static message_list_ty *
  329. read_mo_file (mlp, fn)
  330.      message_list_ty *mlp;
  331.      const char *fn;
  332. {
  333.   FILE *fp;
  334.   struct mo_file_header header;
  335.   int j;
  336.  
  337.   if (strcmp (fn, "-") == 0 || strcmp (fn, "/dev/stdout") == 0)
  338.     fp = stdin;
  339.   else
  340.     {
  341.       fp = fopen (fn, "rb");
  342.       if (fp == NULL)
  343.     error (EXIT_FAILURE, errno,
  344.            _("error while opening \"%s\" for reading"), fn);
  345.     }
  346.  
  347.   /* We must grope the file to determine which endian it is.
  348.      Perversity of the universe tends towards maximum, so it will
  349.      probably not match the currently executing architecture.  */
  350.   endian = MO_BIG_ENDIAN;
  351.   header.magic = read32 (fp, fn);
  352.   if (header.magic != _MAGIC)
  353.     {
  354.       endian = MO_LITTLE_ENDIAN;
  355.       seek32 (fp, fn, 0L);
  356.       header.magic = read32 (fp, fn);
  357.       if (header.magic != _MAGIC)
  358.     {
  359.     unrecognised:
  360.       error (EXIT_FAILURE, 0, _("file \"%s\" is not in GNU .mo format"),
  361.          fn);
  362.     }
  363.     }
  364.  
  365.   /* Fill the structure describing the header.  */
  366.   header.revision = read32 (fp, fn);
  367.   if (header.revision != MO_REVISION_NUMBER)
  368.     goto unrecognised;
  369.   header.nstrings = read32 (fp, fn);
  370.   header.orig_tab_offset = read32 (fp, fn);
  371.   header.trans_tab_offset = read32 (fp, fn);
  372.   header.hash_tab_size = read32 (fp, fn);
  373.   header.hash_tab_offset = read32 (fp, fn);
  374.  
  375.   if (mlp == NULL)
  376.     mlp = message_list_alloc ();
  377.   for (j = 0; j < header.nstrings; ++j)
  378.     {
  379.       static lex_pos_ty pos = { __FILE__, __LINE__ };
  380.       message_ty *mp;
  381.       char *msgid;
  382.       char *msgstr;
  383.  
  384.       /* Read the msgid.  */
  385.       msgid = string32 (fp, fn, header.orig_tab_offset + j * 8);
  386.  
  387.       /* Read the msgstr.  */
  388.       msgstr = string32 (fp, fn, header.trans_tab_offset + j * 8);
  389.  
  390.       mp = message_alloc (msgid);
  391.       message_variant_append (mp, MESSAGE_DOMAIN_DEFAULT, msgstr, &pos);
  392.       message_list_append (mlp, mp);
  393.     }
  394.  
  395.   if (fp != stdin)
  396.     fclose (fp);
  397.   return mlp;
  398. }
  399.