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