~win-cross-dev/win-cross/gettext

« back to all changes in this revision

Viewing changes to gettext-runtime/src/ngettext.c

  • Committer: Nathan Osman
  • Date: 2012-08-11 05:06:52 UTC
  • Revision ID: admin@quickmediasolutions.com-20120811050652-ochkxjtonbw6kkve
Initial commit.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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.  */
 
42
static int do_expand;
 
43
 
 
44
/* Long options.  */
 
45
static 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.  */
 
54
static void usage (int status)
 
55
#if defined __GNUC__ && ((__GNUC__ == 2 && __GNUC_MINOR__ >= 5) || __GNUC__ > 2)
 
56
     __attribute__ ((noreturn))
 
57
#endif
 
58
;
 
59
static const char *expand_escape (const char *str);
 
60
 
 
61
int
 
62
main (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\
 
124
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n\
 
125
This is free software: you are free to change and redistribute it.\n\
 
126
There 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.  */
 
203
static void
 
204
usage (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 (_("\
 
213
Usage: %s [OPTION] [TEXTDOMAIN] MSGID MSGID-PLURAL COUNT\n\
 
214
"), program_name);
 
215
      printf ("\n");
 
216
      /* xgettext: no-wrap */
 
217
      printf (_("\
 
218
Display native language translation of a textual message whose grammatical\n\
 
219
form 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 (_("\
 
234
If the TEXTDOMAIN parameter is not given, the domain is determined from the\n\
 
235
environment variable TEXTDOMAIN.  If the message catalog is not found in the\n\
 
236
regular directory, another location can be specified with the environment\n\
 
237
variable TEXTDOMAINDIR.\n\
 
238
Standard 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.  */
 
253
static const char *
 
254
expand_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
}