• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/ap/gpl/timemachine/gettext-0.17/gettext-runtime/src/
1/* ngettext - retrieve plural form string from message catalog and print it.
2   Copyright (C) 1995-1997, 2000-2007 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 <http://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 "closeout.h"
30#include "error.h"
31#include "progname.h"
32#include "relocatable.h"
33#include "basename.h"
34#include "xalloc.h"
35#include "propername.h"
36#include "gettext.h"
37
38#define _(str) gettext (str)
39
40/* If true, expand escape sequences in strings before looking in the
41   message catalog.  */
42static int do_expand;
43
44/* Long options.  */
45static const struct option long_options[] =
46{
47  { "domain", required_argument, NULL, 'd' },
48  { "help", no_argument, NULL, 'h' },
49  { "version", no_argument, NULL, 'V' },
50  { NULL, 0, NULL, 0 }
51};
52
53/* Forward declaration of local functions.  */
54static void usage (int status)
55#if defined __GNUC__ && ((__GNUC__ == 2 && __GNUC_MINOR__ >= 5) || __GNUC__ > 2)
56     __attribute__ ((noreturn))
57#endif
58;
59static const char *expand_escape (const char *str);
60
61int
62main (int argc, char *argv[])
63{
64  int optchar;
65  const char *msgid;
66  const char *msgid_plural;
67  const char *count;
68  unsigned long n;
69
70  /* Default values for command line options.  */
71  bool do_help = false;
72  bool do_version = false;
73  const char *domain = getenv ("TEXTDOMAIN");
74  const char *domaindir = getenv ("TEXTDOMAINDIR");
75  do_expand = false;
76
77  /* Set program name for message texts.  */
78  set_program_name (argv[0]);
79
80#ifdef HAVE_SETLOCALE
81  /* Set locale via LC_ALL.  */
82  setlocale (LC_ALL, "");
83#endif
84
85  /* Set the text message domain.  */
86  bindtextdomain (PACKAGE, relocate (LOCALEDIR));
87  textdomain (PACKAGE);
88
89  /* Ensure that write errors on stdout are detected.  */
90  atexit (close_stdout);
91
92  /* Parse command line options.  */
93  while ((optchar = getopt_long (argc, argv, "+d:eEhV", long_options, NULL))
94	 != EOF)
95    switch (optchar)
96    {
97    case '\0':		/* Long option.  */
98      break;
99    case 'd':
100      domain = optarg;
101      break;
102    case 'e':
103      do_expand = true;
104      break;
105    case 'E':
106      /* Ignore.  Just for compatibility.  */
107      break;
108    case 'h':
109      do_help = true;
110      break;
111    case 'V':
112      do_version = true;
113      break;
114    default:
115      usage (EXIT_FAILURE);
116    }
117
118  /* Version information is requested.  */
119  if (do_version)
120    {
121      printf ("%s (GNU %s) %s\n", basename (program_name), PACKAGE, VERSION);
122      /* xgettext: no-wrap */
123      printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
124License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n\
125This is free software: you are free to change and redistribute it.\n\
126There is NO WARRANTY, to the extent permitted by law.\n\
127"),
128	      "1995-1997, 2000-2007");
129      printf (_("Written by %s.\n"), proper_name ("Ulrich Drepper"));
130      exit (EXIT_SUCCESS);
131    }
132
133  /* Help is requested.  */
134  if (do_help)
135    usage (EXIT_SUCCESS);
136
137  /* More optional command line options.  */
138  switch (argc - optind)
139    {
140    default:
141      error (EXIT_FAILURE, 0, _("too many arguments"));
142
143    case 4:
144      domain = argv[optind++];
145      /* FALLTHROUGH */
146
147    case 3:
148      break;
149
150    case 2:
151    case 1:
152    case 0:
153      error (EXIT_FAILURE, 0, _("missing arguments"));
154    }
155
156  /* Now the mandatory command line options.  */
157  msgid = argv[optind++];
158  msgid_plural = argv[optind++];
159  count = argv[optind++];
160
161  if (optind != argc)
162    abort ();
163
164  {
165    char *endp;
166    unsigned long tmp_val;
167
168    errno = 0;
169    tmp_val = strtoul (count, &endp, 10);
170    if (errno == 0 && count[0] != '\0' && endp[0] == '\0')
171      n = tmp_val;
172    else
173      /* When COUNT is not valid, use plural.  */
174      n = 99;
175  }
176
177  /* Expand escape sequences if enabled.  */
178  if (do_expand)
179    {
180      msgid = expand_escape (msgid);
181      msgid_plural = expand_escape (msgid_plural);
182    }
183
184  /* If no domain name is given we don't translate, and we use English
185     plural form handling.  */
186  if (domain == NULL || domain[0] == '\0')
187    fputs (n == 1 ? msgid : msgid_plural, stdout);
188  else
189    {
190      /* Bind domain to appropriate directory.  */
191      if (domaindir != NULL && domaindir[0] != '\0')
192	bindtextdomain (domain, domaindir);
193
194      /* Write out the result.  */
195      fputs (dngettext (domain, msgid, msgid_plural, n), stdout);
196    }
197
198  exit (EXIT_SUCCESS);
199}
200
201
202/* Display usage information and exit.  */
203static void
204usage (int status)
205{
206  if (status != EXIT_SUCCESS)
207    fprintf (stderr, _("Try `%s --help' for more information.\n"),
208	     program_name);
209  else
210    {
211      /* xgettext: no-wrap */
212      printf (_("\
213Usage: %s [OPTION] [TEXTDOMAIN] MSGID MSGID-PLURAL COUNT\n\
214"), program_name);
215      printf ("\n");
216      /* xgettext: no-wrap */
217      printf (_("\
218Display native language translation of a textual message whose grammatical\n\
219form depends on a number.\n"));
220      printf ("\n");
221      /* xgettext: no-wrap */
222      printf (_("\
223  -d, --domain=TEXTDOMAIN   retrieve translated message from TEXTDOMAIN\n\
224  -e                        enable expansion of some escape sequences\n\
225  -E                        (ignored for compatibility)\n\
226  -h, --help                display this help and exit\n\
227  -V, --version             display version information and exit\n\
228  [TEXTDOMAIN]              retrieve translated message from TEXTDOMAIN\n\
229  MSGID MSGID-PLURAL        translate MSGID (singular) / MSGID-PLURAL (plural)\n\
230  COUNT                     choose singular/plural form based on this value\n"));
231      printf ("\n");
232      /* xgettext: no-wrap */
233      printf (_("\
234If the TEXTDOMAIN parameter is not given, the domain is determined from the\n\
235environment variable TEXTDOMAIN.  If the message catalog is not found in the\n\
236regular directory, another location can be specified with the environment\n\
237variable TEXTDOMAINDIR.\n\
238Standard search directory: %s\n"),
239	      getenv ("IN_HELP2MAN") == NULL ? LOCALEDIR : "@localedir@");
240      printf ("\n");
241      /* TRANSLATORS: The placeholder indicates the bug-reporting address
242         for this package.  Please add _another line_ saying
243         "Report translation bugs to <...>\n" with the address for translation
244         bugs (typically your translation team's web or email address).  */
245      fputs (_("Report bugs to <bug-gnu-gettext@gnu.org>.\n"), stdout);
246    }
247
248  exit (status);
249}
250
251
252/* Expand some escape sequences found in the argument string.  */
253static const char *
254expand_escape (const char *str)
255{
256  char *retval, *rp;
257  const char *cp = str;
258
259  for (;;)
260    {
261      while (cp[0] != '\0' && cp[0] != '\\')
262	++cp;
263      if (cp[0] == '\0')
264	return str;
265      /* Found a backslash.  */
266      if (cp[1] == '\0')
267	return str;
268      if (strchr ("abcfnrtv\\01234567", cp[1]) != NULL)
269	break;
270      ++cp;
271    }
272
273  retval = XNMALLOC (strlen (str), char);
274
275  rp = retval + (cp - str);
276  memcpy (retval, str, cp - str);
277
278  do
279    {
280      /* Here cp[0] == '\\'.  */
281      switch (*++cp)
282	{
283	case 'a':		/* alert */
284	  *rp++ = '\a';
285	  ++cp;
286	  break;
287	case 'b':		/* backspace */
288	  *rp++ = '\b';
289	  ++cp;
290	  break;
291	case 'f':		/* form feed */
292	  *rp++ = '\f';
293	  ++cp;
294	  break;
295	case 'n':		/* new line */
296	  *rp++ = '\n';
297	  ++cp;
298	  break;
299	case 'r':		/* carriage return */
300	  *rp++ = '\r';
301	  ++cp;
302	  break;
303	case 't':		/* horizontal tab */
304	  *rp++ = '\t';
305	  ++cp;
306	  break;
307	case 'v':		/* vertical tab */
308	  *rp++ = '\v';
309	  ++cp;
310	  break;
311	case '\\':
312	  *rp = '\\';
313	  ++cp;
314	  break;
315	case '0': case '1': case '2': case '3':
316	case '4': case '5': case '6': case '7':
317	  {
318	    int ch = *cp++ - '0';
319
320	    if (*cp >= '0' && *cp <= '7')
321	      {
322		ch *= 8;
323		ch += *cp++ - '0';
324
325		if (*cp >= '0' && *cp <= '7')
326		  {
327		    ch *= 8;
328		    ch += *cp++ - '0';
329		  }
330	      }
331	    *rp = ch;
332	  }
333	  break;
334	default:
335	  *rp = '\\';
336	  break;
337	}
338
339      while (cp[0] != '\0' && cp[0] != '\\')
340	*rp++ = *cp++;
341    }
342  while (cp[0] != '\0');
343
344  /* Terminate string.  */
345  *rp = '\0';
346
347  return (const char *) retval;
348}
349