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