~ubuntu-branches/ubuntu/breezy/gettext/breezy

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Santiago Vila
  • Date: 2004-03-14 17:40:02 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20040314174002-p1ad5ldve1hqzhye
Tags: 0.14.1-2
* Added libexpat1-dev to Build-Depends, for glade support.
* Added libc0.1-dev to Build-Depends, for GNU/kFreeBSD.
* Removed special-casing of knetbsd-gnu in debian/rules.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* gettext - retrieve text string from message catalog and print it.
 
2
   Copyright (C) 1995-1997, 2000-2004 Free Software Foundation, Inc.
 
3
   Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, May 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 Foundation,
 
17
   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 <getopt.h>
 
24
#include <stdbool.h>
 
25
#include <stdio.h>
 
26
#include <stdlib.h>
 
27
#include <string.h>
 
28
#include <locale.h>
 
29
 
 
30
#include "closeout.h"
 
31
#include "error.h"
 
32
#include "progname.h"
 
33
#include "relocatable.h"
 
34
#include "basename.h"
 
35
#include "xalloc.h"
 
36
#include "exit.h"
 
37
 
 
38
#include "gettext.h"
 
39
 
 
40
#define _(str) gettext (str)
 
41
 
 
42
/* If true, add newline after last string.  This makes only sense in
 
43
   the `echo' emulation mode.  */
 
44
static bool add_newline;
 
45
 
 
46
/* If true, expand escape sequences in strings before looking in the
 
47
   message catalog.  */
 
48
static bool do_expand;
 
49
 
 
50
/* Long options.  */
 
51
static const struct option long_options[] =
 
52
{
 
53
  { "domain", required_argument, NULL, 'd' },
 
54
  { "help", no_argument, NULL, 'h' },
 
55
  { "shell-script", no_argument, NULL, 's' },
 
56
  { "version", no_argument, NULL, 'V' },
 
57
  { NULL, 0, NULL, 0 }
 
58
};
 
59
 
 
60
/* Forward declaration of local functions.  */
 
61
static void usage (int status)
 
62
#if defined __GNUC__ && ((__GNUC__ == 2 && __GNUC_MINOR__ >= 5) || __GNUC__ > 2)
 
63
     __attribute__ ((noreturn))
 
64
#endif
 
65
;
 
66
static const char *expand_escape (const char *str);
 
67
 
 
68
int
 
69
main (int argc, char *argv[])
 
70
{
 
71
  int optchar;
 
72
  const char *msgid;
 
73
 
 
74
  /* Default values for command line options.  */
 
75
  bool do_help = false;
 
76
  bool do_shell = false;
 
77
  bool do_version = false;
 
78
  const char *domain = getenv ("TEXTDOMAIN");
 
79
  const char *domaindir = getenv ("TEXTDOMAINDIR");
 
80
  add_newline = true;
 
81
  do_expand = false;
 
82
 
 
83
  /* Set program name for message texts.  */
 
84
  set_program_name (argv[0]);
 
85
 
 
86
#ifdef HAVE_SETLOCALE
 
87
  /* Set locale via LC_ALL.  */
 
88
  setlocale (LC_ALL, "");
 
89
#endif
 
90
 
 
91
  /* Set the text message domain.  */
 
92
  bindtextdomain (PACKAGE, relocate (LOCALEDIR));
 
93
  textdomain (PACKAGE);
 
94
 
 
95
  /* Ensure that write errors on stdout are detected.  */
 
96
  atexit (close_stdout);
 
97
 
 
98
  /* Parse command line options.  */
 
99
  while ((optchar = getopt_long (argc, argv, "+d:eEhnsV", long_options, NULL))
 
100
         != EOF)
 
101
    switch (optchar)
 
102
    {
 
103
    case '\0':          /* Long option.  */
 
104
      break;
 
105
    case 'd':
 
106
      domain = optarg;
 
107
      break;
 
108
    case 'e':
 
109
      do_expand = true;
 
110
      break;
 
111
    case 'E':
 
112
      /* Ignore.  Just for compatibility.  */
 
113
      break;
 
114
    case 'h':
 
115
      do_help = true;
 
116
      break;
 
117
    case 'n':
 
118
      add_newline = false;
 
119
      break;
 
120
    case 's':
 
121
      do_shell = true;
 
122
      break;
 
123
    case 'V':
 
124
      do_version = true;
 
125
      break;
 
126
    default:
 
127
      usage (EXIT_FAILURE);
 
128
    }
 
129
 
 
130
  /* Version information is requested.  */
 
131
  if (do_version)
 
132
    {
 
133
      printf ("%s (GNU %s) %s\n", basename (program_name), PACKAGE, VERSION);
 
134
      /* xgettext: no-wrap */
 
135
      printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
 
136
This is free software; see the source for copying conditions.  There is NO\n\
 
137
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
 
138
"),
 
139
              "1995-1997, 2000-2004");
 
140
      printf (_("Written by %s.\n"), "Ulrich Drepper");
 
141
      exit (EXIT_SUCCESS);
 
142
    }
 
143
 
 
144
  /* Help is requested.  */
 
145
  if (do_help)
 
146
    usage (EXIT_SUCCESS);
 
147
 
 
148
  /* We have two major modes: use following Uniforum spec and as
 
149
     internationalized `echo' program.  */
 
150
  if (!do_shell)
 
151
    {
 
152
      /* We have to write a single strings translation to stdout.  */
 
153
 
 
154
      /* Get arguments.  */
 
155
      switch (argc - optind)
 
156
        {
 
157
          default:
 
158
            error (EXIT_FAILURE, 0, _("too many arguments"));
 
159
 
 
160
          case 2:
 
161
            domain = argv[optind++];
 
162
            /* FALLTHROUGH */
 
163
 
 
164
          case 1:
 
165
            break;
 
166
 
 
167
          case 0:
 
168
            error (EXIT_FAILURE, 0, _("missing arguments"));
 
169
        }
 
170
 
 
171
      msgid = argv[optind++];
 
172
 
 
173
      /* Expand escape sequences if enabled.  */
 
174
      if (do_expand)
 
175
        msgid = expand_escape (msgid);
 
176
 
 
177
      /* If no domain name is given we don't translate.  */
 
178
      if (domain == NULL || domain[0] == '\0')
 
179
        {
 
180
          fputs (msgid, stdout);
 
181
        }
 
182
      else
 
183
        {
 
184
          /* Bind domain to appropriate directory.  */
 
185
          if (domaindir != NULL && domaindir[0] != '\0')
 
186
            bindtextdomain (domain, domaindir);
 
187
 
 
188
          /* Write out the result.  */
 
189
          fputs (dgettext (domain, msgid), stdout);
 
190
        }
 
191
    }
 
192
  else
 
193
    {
 
194
      if (optind < argc)
 
195
        {
 
196
          /* If no domain name is given we print the original string.
 
197
             We mark this assigning NULL to domain.  */
 
198
          if (domain == NULL || domain[0] == '\0')
 
199
            domain = NULL;
 
200
          else
 
201
            /* Bind domain to appropriate directory.  */
 
202
            if (domaindir != NULL && domaindir[0] != '\0')
 
203
              bindtextdomain (domain, domaindir);
 
204
 
 
205
          /* We have to simulate `echo'.  All arguments are strings.  */
 
206
          do
 
207
            {
 
208
              msgid = argv[optind++];
 
209
 
 
210
              /* Expand escape sequences if enabled.  */
 
211
              if (do_expand)
 
212
                msgid = expand_escape (msgid);
 
213
 
 
214
              /* Write out the result.  */
 
215
              fputs (domain == NULL ? msgid : dgettext (domain, msgid),
 
216
                     stdout);
 
217
 
 
218
              /* We separate the arguments by a single ' '.  */
 
219
              if (optind < argc)
 
220
                fputc (' ', stdout);
 
221
            }
 
222
          while (optind < argc);
 
223
        }
 
224
 
 
225
      /* If not otherwise told: add trailing newline.  */
 
226
      if (add_newline)
 
227
        fputc ('\n', stdout);
 
228
    }
 
229
 
 
230
  exit (EXIT_SUCCESS);
 
231
}
 
232
 
 
233
 
 
234
/* Display usage information and exit.  */
 
235
static void
 
236
usage (int status)
 
237
{
 
238
  if (status != EXIT_SUCCESS)
 
239
    fprintf (stderr, _("Try `%s --help' for more information.\n"),
 
240
             program_name);
 
241
  else
 
242
    {
 
243
      /* xgettext: no-wrap */
 
244
      printf (_("\
 
245
Usage: %s [OPTION] [[TEXTDOMAIN] MSGID]\n\
 
246
or:    %s [OPTION] -s [MSGID]...\n\
 
247
"), program_name, program_name);
 
248
      printf ("\n");
 
249
      /* xgettext: no-wrap */
 
250
      printf (_("\
 
251
Display native language translation of a textual message.\n"));
 
252
      printf ("\n");
 
253
      /* xgettext: no-wrap */
 
254
      printf (_("\
 
255
  -d, --domain=TEXTDOMAIN   retrieve translated messages from TEXTDOMAIN\n\
 
256
  -e                        enable expansion of some escape sequences\n\
 
257
  -E                        (ignored for compatibility)\n\
 
258
  -h, --help                display this help and exit\n\
 
259
  -n                        suppress trailing newline\n\
 
260
  -V, --version             display version information and exit\n\
 
261
  [TEXTDOMAIN] MSGID        retrieve translated message corresponding\n\
 
262
                            to MSGID from TEXTDOMAIN\n"));
 
263
      printf ("\n");
 
264
      /* xgettext: no-wrap */
 
265
      printf (_("\
 
266
If the TEXTDOMAIN parameter is not given, the domain is determined from the\n\
 
267
environment variable TEXTDOMAIN.  If the message catalog is not found in the\n\
 
268
regular directory, another location can be specified with the environment\n\
 
269
variable TEXTDOMAINDIR.\n\
 
270
When used with the -s option the program behaves like the `echo' command.\n\
 
271
But it does not simply copy its arguments to stdout.  Instead those messages\n\
 
272
found in the selected catalog are translated.\n\
 
273
Standard search directory: %s\n"),
 
274
              getenv ("IN_HELP2MAN") == NULL ? LOCALEDIR : "@localedir@");
 
275
      printf ("\n");
 
276
      fputs (_("Report bugs to <bug-gnu-gettext@gnu.org>.\n"), stdout);
 
277
    }
 
278
 
 
279
  exit (status);
 
280
}
 
281
 
 
282
 
 
283
/* Expand some escape sequences found in the argument string.  */
 
284
static const char *
 
285
expand_escape (const char *str)
 
286
{
 
287
  char *retval, *rp;
 
288
  const char *cp = str;
 
289
 
 
290
  do
 
291
    {
 
292
      while (cp[0] != '\0' && cp[0] != '\\')
 
293
        ++cp;
 
294
    }
 
295
  while (cp[0] != '\0' && cp[1] != '\0'
 
296
         && strchr ("bcfnrt\\01234567", cp[1]) == NULL);
 
297
 
 
298
  if (cp[0] == '\0')
 
299
    return str;
 
300
 
 
301
  retval = (char *) xmalloc (strlen (str));
 
302
 
 
303
  rp = retval + (cp - str);
 
304
  memcpy (retval, str, cp - str);
 
305
 
 
306
  do
 
307
    {
 
308
      switch (*++cp)
 
309
        {
 
310
        case 'b':               /* backspace */
 
311
          *rp++ = '\b';
 
312
          ++cp;
 
313
          break;
 
314
        case 'c':               /* suppress trailing newline */
 
315
          add_newline = false;
 
316
          ++cp;
 
317
          break;
 
318
        case 'f':               /* form feed */
 
319
          *rp++ = '\f';
 
320
          ++cp;
 
321
          break;
 
322
        case 'n':               /* new line */
 
323
          *rp++ = '\n';
 
324
          ++cp;
 
325
          break;
 
326
        case 'r':               /* carriage return */
 
327
          *rp++ = '\r';
 
328
          ++cp;
 
329
          break;
 
330
        case 't':               /* horizontal tab */
 
331
          *rp++ = '\t';
 
332
          ++cp;
 
333
          break;
 
334
        case '\\':
 
335
          *rp = '\\';
 
336
          ++cp;
 
337
          break;
 
338
        case '0': case '1': case '2': case '3':
 
339
        case '4': case '5': case '6': case '7':
 
340
          {
 
341
            int ch = *cp++ - '0';
 
342
 
 
343
            if (*cp >= '0' && *cp <= '7')
 
344
              {
 
345
                ch *= 8;
 
346
                ch += *cp++ - '0';
 
347
 
 
348
                if (*cp >= '0' && *cp <= '7')
 
349
                  {
 
350
                    ch *= 8;
 
351
                    ch += *cp++ - '0';
 
352
                  }
 
353
              }
 
354
            *rp = ch;
 
355
          }
 
356
          break;
 
357
        default:
 
358
          *rp = '\\';
 
359
          break;
 
360
        }
 
361
 
 
362
      while (cp[0] != '\0' && cp[0] != '\\')
 
363
        *rp++ = *cp++;
 
364
    }
 
365
  while (cp[0] != '\0');
 
366
 
 
367
  /* Terminate string.  */
 
368
  *rp = '\0';
 
369
 
 
370
  return (const char *) retval;
 
371
}