• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* gettext - retrieve text string from message catalog and print it.
2    Copyright (C) 1995-1997, 2000-2007, 2012, 2018-2020 Free Software
3    Foundation, Inc.
4    Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, May 1995.
5 
6    This program is free software: you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
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 "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 false, add newline after last string.  This makes only sense in
44    the 'echo' emulation mode.  */
45 static bool inhibit_added_newline;
46 
47 /* If true, expand escape sequences in strings before looking in the
48    message catalog.  */
49 static bool do_expand;
50 
51 /* Long options.  */
52 static const struct option long_options[] =
53 {
54   { "context", required_argument, NULL, 'c' },
55   { "domain", required_argument, NULL, 'd' },
56   { "help", no_argument, NULL, 'h' },
57   { "shell-script", no_argument, NULL, 's' },
58   { "version", no_argument, NULL, 'V' },
59   { NULL, 0, NULL, 0 }
60 };
61 
62 /* Forward declaration of local functions.  */
63 _GL_NORETURN_FUNC static void usage (int status);
64 
65 int
main(int argc,char * argv[])66 main (int argc, char *argv[])
67 {
68   int optchar;
69   const char *msgid;
70 
71   /* Default values for command line options.  */
72   bool do_help = false;
73   bool do_shell = false;
74   bool do_version = false;
75   const char *domain = getenv ("TEXTDOMAIN");
76   const char *domaindir = getenv ("TEXTDOMAINDIR");
77   const char *context = NULL;
78   inhibit_added_newline = false;
79   do_expand = false;
80 
81   /* Set program name for message texts.  */
82   set_program_name (argv[0]);
83 
84   /* Set locale via LC_ALL.  */
85   setlocale (LC_ALL, "");
86 
87   /* Set the text message domain.  */
88   bindtextdomain (PACKAGE, relocate (LOCALEDIR));
89   textdomain (PACKAGE);
90 
91   /* Ensure that write errors on stdout are detected.  */
92   atexit (close_stdout);
93 
94   /* Parse command line options.  */
95   while ((optchar = getopt_long (argc, argv, "+c:d:eEhnsV", long_options, NULL))
96          != EOF)
97     switch (optchar)
98     {
99     case '\0':          /* Long option.  */
100       break;
101     case 'c':
102       context = optarg;
103       break;
104     case 'd':
105       domain = optarg;
106       break;
107     case 'e':
108       do_expand = true;
109       break;
110     case 'E':
111       /* Ignore.  Just for compatibility.  */
112       break;
113     case 'h':
114       do_help = true;
115       break;
116     case 'n':
117       inhibit_added_newline = true;
118       break;
119     case 's':
120       do_shell = true;
121       break;
122     case 'V':
123       do_version = true;
124       break;
125     default:
126       usage (EXIT_FAILURE);
127     }
128 
129   /* Version information is requested.  */
130   if (do_version)
131     {
132       printf ("%s (GNU %s) %s\n", last_component (program_name),
133               PACKAGE, VERSION);
134       /* xgettext: no-wrap */
135       printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
136 License GPLv3+: GNU GPL version 3 or later <%s>\n\
137 This is free software: you are free to change and redistribute it.\n\
138 There is NO WARRANTY, to the extent permitted by law.\n\
139 "),
140               "1995-2020", "https://gnu.org/licenses/gpl.html");
141       printf (_("Written by %s.\n"), proper_name ("Ulrich Drepper"));
142       exit (EXIT_SUCCESS);
143     }
144 
145   /* Help is requested.  */
146   if (do_help)
147     usage (EXIT_SUCCESS);
148 
149   /* We have two major modes: use following Uniforum spec and as
150      internationalized 'echo' program.  */
151   if (!do_shell)
152     {
153       /* We have to write a single strings translation to stdout.  */
154 
155       /* Get arguments.  */
156       switch (argc - optind)
157         {
158           default:
159             error (EXIT_FAILURE, 0, _("too many arguments"));
160 
161           case 2:
162             domain = argv[optind++];
163             /* FALLTHROUGH */
164 
165           case 1:
166             break;
167 
168           case 0:
169             error (EXIT_FAILURE, 0, _("missing arguments"));
170         }
171 
172       msgid = argv[optind++];
173 
174       /* Expand escape sequences if enabled.  */
175       if (do_expand)
176         msgid = expand_escapes (msgid, &inhibit_added_newline);
177 
178       /* If no domain name is given we don't translate.  */
179       if (domain == NULL || domain[0] == '\0')
180         {
181           fputs (msgid, stdout);
182         }
183       else
184         {
185           /* Bind domain to appropriate directory.  */
186           if (domaindir != NULL && domaindir[0] != '\0')
187             bindtextdomain (domain, domaindir);
188 
189           /* Write out the result.  */
190           fputs ((context != NULL
191                   ? dpgettext_expr (domain, context, msgid)
192                   : dgettext (domain, msgid)),
193                  stdout);
194         }
195     }
196   else
197     {
198       if (optind < argc)
199         {
200           /* If no domain name is given we print the original string.
201              We mark this assigning NULL to domain.  */
202           if (domain == NULL || domain[0] == '\0')
203             domain = NULL;
204           else
205             /* Bind domain to appropriate directory.  */
206             if (domaindir != NULL && domaindir[0] != '\0')
207               bindtextdomain (domain, domaindir);
208 
209           /* We have to simulate 'echo'.  All arguments are strings.  */
210           do
211             {
212               msgid = argv[optind++];
213 
214               /* Expand escape sequences if enabled.  */
215               if (do_expand)
216                 msgid = expand_escapes (msgid, &inhibit_added_newline);
217 
218               /* Write out the result.  */
219               fputs ((domain == NULL ? msgid :
220                       context != NULL
221                       ? dpgettext_expr (domain, context, msgid)
222                       : dgettext (domain, msgid)),
223                      stdout);
224 
225               /* We separate the arguments by a single ' '.  */
226               if (optind < argc)
227                 fputc (' ', stdout);
228             }
229           while (optind < argc);
230         }
231 
232       /* If not otherwise told: add trailing newline.  */
233       if (!inhibit_added_newline)
234         fputc ('\n', stdout);
235     }
236 
237   exit (EXIT_SUCCESS);
238 }
239 
240 
241 /* Display usage information and exit.  */
242 static void
usage(int status)243 usage (int status)
244 {
245   if (status != EXIT_SUCCESS)
246     fprintf (stderr, _("Try '%s --help' for more information.\n"),
247              program_name);
248   else
249     {
250       /* xgettext: no-wrap */
251       printf (_("\
252 Usage: %s [OPTION] [[TEXTDOMAIN] MSGID]\n\
253 or:    %s [OPTION] -s [MSGID]...\n\
254 "), program_name, program_name);
255       printf ("\n");
256       /* xgettext: no-wrap */
257       printf (_("\
258 Display native language translation of a textual message.\n"));
259       printf ("\n");
260       /* xgettext: no-wrap */
261       printf (_("\
262   -d, --domain=TEXTDOMAIN   retrieve translated messages from TEXTDOMAIN\n"));
263       printf (_("\
264   -c, --context=CONTEXT     specify context for MSGID\n"));
265       printf (_("\
266   -e                        enable expansion of some escape sequences\n"));
267       printf (_("\
268   -n                        suppress trailing newline\n"));
269       printf (_("\
270   -E                        (ignored for compatibility)\n"));
271       printf (_("\
272   [TEXTDOMAIN] MSGID        retrieve translated message corresponding\n\
273                             to MSGID from TEXTDOMAIN\n"));
274       printf ("\n");
275       printf (_("\
276 Informative output:\n"));
277       printf (_("\
278   -h, --help                display this help and exit\n"));
279       printf (_("\
280   -V, --version             display version information and exit\n"));
281       printf ("\n");
282       /* xgettext: no-wrap */
283       printf (_("\
284 If the TEXTDOMAIN parameter is not given, the domain is determined from the\n\
285 environment variable TEXTDOMAIN.  If the message catalog is not found in the\n\
286 regular directory, another location can be specified with the environment\n\
287 variable TEXTDOMAINDIR.\n\
288 When used with the -s option the program behaves like the 'echo' command.\n\
289 But it does not simply copy its arguments to stdout.  Instead those messages\n\
290 found in the selected catalog are translated.\n\
291 Standard search directory: %s\n"),
292               getenv ("IN_HELP2MAN") == NULL ? LOCALEDIR : "@localedir@");
293       printf ("\n");
294       /* TRANSLATORS: The first placeholder is the web address of the Savannah
295          project of this package.  The second placeholder is the bug-reporting
296          email address for this package.  Please add _another line_ saying
297          "Report translation bugs to <...>\n" with the address for translation
298          bugs (typically your translation team's web or email address).  */
299       printf(_("\
300 Report bugs in the bug tracker at <%s>\n\
301 or by email to <%s>.\n"),
302              "https://savannah.gnu.org/projects/gettext",
303              "bug-gettext@gnu.org");
304     }
305 
306   exit (status);
307 }
308