(root)/
gettext-0.22.4/
gettext-runtime/
src/
ngettext.c
       1  /* ngettext - retrieve plural form string from message catalog and print it.
       2     Copyright (C) 1995-1997, 2000-2007, 2012, 2018-2023 Free Software Foundation, Inc.
       3  
       4     This program is free software: you can redistribute it and/or modify
       5     it under the terms of the GNU General Public License as published by
       6     the Free Software Foundation; either version 3 of the License, or
       7     (at your option) any later version.
       8  
       9     This program is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12     GNU General Public License for more details.
      13  
      14     You should have received a copy of the GNU General Public License
      15     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      16  
      17  #ifdef HAVE_CONFIG_H
      18  # include <config.h>
      19  #endif
      20  
      21  #include <getopt.h>
      22  #include <stdbool.h>
      23  #include <stdio.h>
      24  #include <stdlib.h>
      25  #include <string.h>
      26  #include <locale.h>
      27  #include <errno.h>
      28  
      29  #include "attribute.h"
      30  #include "noreturn.h"
      31  #include "closeout.h"
      32  #include "error.h"
      33  #include "progname.h"
      34  #include "relocatable.h"
      35  #include "basename-lgpl.h"
      36  #include "xalloc.h"
      37  #include "propername.h"
      38  #include "escapes.h"
      39  #include "gettext.h"
      40  
      41  #define _(str) gettext (str)
      42  
      43  /* If true, expand escape sequences in strings before looking in the
      44     message catalog.  */
      45  static int do_expand;
      46  
      47  /* Long options.  */
      48  static const struct option long_options[] =
      49  {
      50    { "context", required_argument, NULL, 'c' },
      51    { "domain", required_argument, NULL, 'd' },
      52    { "help", no_argument, NULL, 'h' },
      53    { "version", no_argument, NULL, 'V' },
      54    { NULL, 0, NULL, 0 }
      55  };
      56  
      57  /* Forward declaration of local functions.  */
      58  _GL_NORETURN_FUNC static void usage (int status);
      59  
      60  int
      61  main (int argc, char *argv[])
      62  {
      63    int optchar;
      64    const char *msgid;
      65    const char *msgid_plural;
      66    const char *count;
      67    unsigned long n;
      68  
      69    /* Default values for command line options.  */
      70    bool do_help = false;
      71    bool do_version = false;
      72    const char *domain = getenv ("TEXTDOMAIN");
      73    const char *domaindir = getenv ("TEXTDOMAINDIR");
      74    const char *context = NULL;
      75    do_expand = false;
      76  
      77    /* Set program name for message texts.  */
      78    set_program_name (argv[0]);
      79  
      80    /* Set locale via LC_ALL.  */
      81    setlocale (LC_ALL, "");
      82  
      83    /* Set the text message domain.  */
      84    bindtextdomain (PACKAGE, relocate (LOCALEDIR));
      85    textdomain (PACKAGE);
      86  
      87    /* Ensure that write errors on stdout are detected.  */
      88    atexit (close_stdout);
      89  
      90    /* Parse command line options.  */
      91    while ((optchar = getopt_long (argc, argv, "+c:d:eEhV", long_options, NULL))
      92           != EOF)
      93      switch (optchar)
      94      {
      95      case '\0':          /* Long option.  */
      96        break;
      97      case 'c':
      98        context = optarg;
      99        break;
     100      case 'd':
     101        domain = optarg;
     102        break;
     103      case 'e':
     104        do_expand = true;
     105        break;
     106      case 'E':
     107        /* Ignore.  Just for compatibility.  */
     108        break;
     109      case 'h':
     110        do_help = true;
     111        break;
     112      case 'V':
     113        do_version = true;
     114        break;
     115      default:
     116        usage (EXIT_FAILURE);
     117      }
     118  
     119    /* Version information is requested.  */
     120    if (do_version)
     121      {
     122        printf ("%s (GNU %s) %s\n", last_component (program_name),
     123                PACKAGE, VERSION);
     124        /* xgettext: no-wrap */
     125        printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
     126  License GPLv3+: GNU GPL version 3 or later <%s>\n\
     127  This is free software: you are free to change and redistribute it.\n\
     128  There is NO WARRANTY, to the extent permitted by law.\n\
     129  "),
     130                "1995-1997, 2000-2023", "https://gnu.org/licenses/gpl.html");
     131        printf (_("Written by %s.\n"), proper_name ("Ulrich Drepper"));
     132        exit (EXIT_SUCCESS);
     133      }
     134  
     135    /* Help is requested.  */
     136    if (do_help)
     137      usage (EXIT_SUCCESS);
     138  
     139    /* More optional command line options.  */
     140    switch (argc - optind)
     141      {
     142      default:
     143        error (EXIT_FAILURE, 0, _("too many arguments"));
     144  
     145      case 4:
     146        domain = argv[optind++];
     147        FALLTHROUGH;
     148  
     149      case 3:
     150        break;
     151  
     152      case 2:
     153      case 1:
     154      case 0:
     155        error (EXIT_FAILURE, 0, _("missing arguments"));
     156      }
     157  
     158    /* Now the mandatory command line options.  */
     159    msgid = argv[optind++];
     160    msgid_plural = argv[optind++];
     161    count = argv[optind++];
     162  
     163    if (optind != argc)
     164      abort ();
     165  
     166    {
     167      char *endp;
     168      unsigned long tmp_val;
     169  
     170      errno = 0;
     171      tmp_val = strtoul (count, &endp, 10);
     172      if (errno == 0 && count[0] != '\0' && endp[0] == '\0')
     173        n = tmp_val;
     174      else
     175        /* When COUNT is not valid, use plural.  */
     176        n = 99;
     177    }
     178  
     179    /* Expand escape sequences if enabled.  */
     180    if (do_expand)
     181      {
     182        msgid = expand_escapes (msgid, NULL);
     183        msgid_plural = expand_escapes (msgid_plural, NULL);
     184      }
     185  
     186    /* If no domain name is given we don't translate, and we use English
     187       plural form handling.  */
     188    if (domain == NULL || domain[0] == '\0')
     189      fputs (n == 1 ? msgid : msgid_plural, stdout);
     190    else
     191      {
     192        /* Bind domain to appropriate directory.  */
     193        if (domaindir != NULL && domaindir[0] != '\0')
     194          bindtextdomain (domain, domaindir);
     195  
     196        /* Write out the result.  */
     197        fputs ((context != NULL
     198                ? dnpgettext_expr (domain, context, msgid, msgid_plural, n)
     199                : dngettext (domain, msgid, msgid_plural, n)),
     200               stdout);
     201      }
     202  
     203    exit (EXIT_SUCCESS);
     204  }
     205  
     206  
     207  /* Display usage information and exit.  */
     208  static void
     209  usage (int status)
     210  {
     211    if (status != EXIT_SUCCESS)
     212      fprintf (stderr, _("Try '%s --help' for more information.\n"),
     213               program_name);
     214    else
     215      {
     216        /* xgettext: no-wrap */
     217        printf (_("\
     218  Usage: %s [OPTION] [TEXTDOMAIN] MSGID MSGID-PLURAL COUNT\n\
     219  "), program_name);
     220        printf ("\n");
     221        /* xgettext: no-wrap */
     222        printf (_("\
     223  Display native language translation of a textual message whose grammatical\n\
     224  form depends on a number.\n"));
     225        printf ("\n");
     226        /* xgettext: no-wrap */
     227        printf (_("\
     228    -d, --domain=TEXTDOMAIN   retrieve translated message from TEXTDOMAIN\n"));
     229        printf (_("\
     230    -c, --context=CONTEXT     specify context for MSGID\n"));
     231        printf (_("\
     232    -e                        enable expansion of some escape sequences\n"));
     233        printf (_("\
     234    -E                        (ignored for compatibility)\n"));
     235        printf (_("\
     236    [TEXTDOMAIN]              retrieve translated message from TEXTDOMAIN\n"));
     237        printf (_("\
     238    MSGID MSGID-PLURAL        translate MSGID (singular) / MSGID-PLURAL (plural)\n"));
     239        printf (_("\
     240    COUNT                     choose singular/plural form based on this value\n"));
     241        printf ("\n");
     242        printf (_("\
     243  Informative output:\n"));
     244        printf (_("\
     245    -h, --help                display this help and exit\n"));
     246        printf (_("\
     247    -V, --version             display version information and exit\n"));
     248        printf ("\n");
     249        /* xgettext: no-wrap */
     250        printf (_("\
     251  If the TEXTDOMAIN parameter is not given, the domain is determined from the\n\
     252  environment variable TEXTDOMAIN.  If the message catalog is not found in the\n\
     253  regular directory, another location can be specified with the environment\n\
     254  variable TEXTDOMAINDIR.\n\
     255  Standard search directory: %s\n"),
     256                getenv ("IN_HELP2MAN") == NULL ? LOCALEDIR : "@localedir@");
     257        printf ("\n");
     258        /* TRANSLATORS: The first placeholder is the web address of the Savannah
     259           project of this package.  The second placeholder is the bug-reporting
     260           email address for this package.  Please add _another line_ saying
     261           "Report translation bugs to <...>\n" with the address for translation
     262           bugs (typically your translation team's web or email address).  */
     263        printf(_("\
     264  Report bugs in the bug tracker at <%s>\n\
     265  or by email to <%s>.\n"),
     266               "https://savannah.gnu.org/projects/gettext",
     267               "bug-gettext@gnu.org");
     268      }
     269  
     270    exit (status);
     271  }