1 /* gettext - retrieve text string from message catalog and print it.
2 Copyright (C) 1995-1997, 2000-2007, 2012, 2015 Free Software
4 Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, May 1995.
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.
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.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
33 #include "relocatable.h"
36 #include "propername.h"
39 #define HAVE_SETLOCALE 1
40 /* Make sure we use the included libintl, not the system's one. */
42 #include "libgnuintl.h"
44 #define _(str) gettext (str)
46 /* If true, add newline after last string. This makes only sense in
47 the 'echo' emulation mode. */
48 static bool add_newline;
50 /* If true, expand escape sequences in strings before looking in the
52 static bool do_expand;
55 static const struct option long_options[] =
57 { "domain", required_argument, NULL, 'd' },
58 { "env", required_argument, NULL, '=' },
59 { "help", no_argument, NULL, 'h' },
60 { "shell-script", no_argument, NULL, 's' },
61 { "version", no_argument, NULL, 'V' },
65 /* Forward declaration of local functions. */
66 static void usage (int status)
67 #if defined __GNUC__ && ((__GNUC__ == 2 && __GNUC_MINOR__ >= 5) || __GNUC__ > 2)
68 __attribute__ ((noreturn))
71 static const char *expand_escape (const char *str);
74 main (int argc, char *argv[])
79 /* Default values for command line options. */
81 bool do_shell = false;
82 bool do_version = false;
83 bool environ_changed = false;
84 const char *domain = getenv ("TEXTDOMAIN");
85 const char *domaindir = getenv ("TEXTDOMAINDIR");
89 /* Set program name for message texts. */
90 set_program_name (argv[0]);
93 /* Set locale via LC_ALL. */
94 setlocale (LC_ALL, "");
97 /* Set the text message domain. */
98 bindtextdomain (PACKAGE, relocate (LOCALEDIR));
101 /* Ensure that write errors on stdout are detected. */
102 atexit (close_stdout);
104 /* Parse command line options. */
105 while ((optchar = getopt_long (argc, argv, "+d:eEhnsV", long_options, NULL))
109 case '\0': /* Long option. */
118 /* Ignore. Just for compatibility. */
134 /* Undocumented option --env sets an environment variable. */
135 char *separator = strchr (optarg, '=');
136 if (separator != NULL)
139 xsetenv (optarg, separator + 1, 1);
140 environ_changed = true;
146 usage (EXIT_FAILURE);
149 #ifdef HAVE_SETLOCALE
151 /* Set locale again via LC_ALL. */
152 setlocale (LC_ALL, "");
155 /* Version information is requested. */
158 printf ("%s (GNU %s) %s\n", basename (program_name), PACKAGE, VERSION);
159 /* xgettext: no-wrap */
160 printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
161 License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n\
162 This is free software: you are free to change and redistribute it.\n\
163 There is NO WARRANTY, to the extent permitted by law.\n\
165 "1995-1997, 2000-2006");
166 printf (_("Written by %s.\n"), proper_name ("Ulrich Drepper"));
170 /* Help is requested. */
172 usage (EXIT_SUCCESS);
174 /* We have two major modes: use following Uniforum spec and as
175 internationalized 'echo' program. */
178 /* We have to write a single strings translation to stdout. */
181 switch (argc - optind)
184 error (EXIT_FAILURE, 0, _("too many arguments"));
187 domain = argv[optind++];
194 error (EXIT_FAILURE, 0, _("missing arguments"));
197 msgid = argv[optind++];
199 /* Expand escape sequences if enabled. */
201 msgid = expand_escape (msgid);
203 /* If no domain name is given we don't translate. */
204 if (domain == NULL || domain[0] == '\0')
206 fputs (msgid, stdout);
210 /* Bind domain to appropriate directory. */
211 if (domaindir != NULL && domaindir[0] != '\0')
212 bindtextdomain (domain, domaindir);
214 /* Write out the result. */
215 fputs (dgettext (domain, msgid), stdout);
222 /* If no domain name is given we print the original string.
223 We mark this assigning NULL to domain. */
224 if (domain == NULL || domain[0] == '\0')
227 /* Bind domain to appropriate directory. */
228 if (domaindir != NULL && domaindir[0] != '\0')
229 bindtextdomain (domain, domaindir);
231 /* We have to simulate 'echo'. All arguments are strings. */
234 msgid = argv[optind++];
236 /* Expand escape sequences if enabled. */
238 msgid = expand_escape (msgid);
240 /* Write out the result. */
241 fputs (domain == NULL ? msgid : dgettext (domain, msgid),
244 /* We separate the arguments by a single ' '. */
248 while (optind < argc);
251 /* If not otherwise told: add trailing newline. */
253 fputc ('\n', stdout);
260 /* Display usage information and exit. */
264 if (status != EXIT_SUCCESS)
265 fprintf (stderr, _("Try '%s --help' for more information.\n"),
269 /* xgettext: no-wrap */
271 Usage: %s [OPTION] [[TEXTDOMAIN] MSGID]\n\
272 or: %s [OPTION] -s [MSGID]...\n\
273 "), program_name, program_name);
275 /* xgettext: no-wrap */
277 Display native language translation of a textual message.\n"));
279 /* xgettext: no-wrap */
281 -d, --domain=TEXTDOMAIN retrieve translated messages from TEXTDOMAIN\n\
282 -e enable expansion of some escape sequences\n\
283 -E (ignored for compatibility)\n\
284 -h, --help display this help and exit\n\
285 -n suppress trailing newline\n\
286 -V, --version display version information and exit\n\
287 [TEXTDOMAIN] MSGID retrieve translated message corresponding\n\
288 to MSGID from TEXTDOMAIN\n"));
290 /* xgettext: no-wrap */
292 If the TEXTDOMAIN parameter is not given, the domain is determined from the\n\
293 environment variable TEXTDOMAIN. If the message catalog is not found in the\n\
294 regular directory, another location can be specified with the environment\n\
295 variable TEXTDOMAINDIR.\n\
296 When used with the -s option the program behaves like the 'echo' command.\n\
297 But it does not simply copy its arguments to stdout. Instead those messages\n\
298 found in the selected catalog are translated.\n\
299 Standard search directory: %s\n"),
300 getenv ("IN_HELP2MAN") == NULL ? LOCALEDIR : "@localedir@");
302 /* TRANSLATORS: The placeholder indicates the bug-reporting address
303 for this package. Please add _another line_ saying
304 "Report translation bugs to <...>\n" with the address for translation
305 bugs (typically your translation team's web or email address). */
306 fputs (_("Report bugs to <bug-gnu-gettext@gnu.org>.\n"), stdout);
313 /* Expand some escape sequences found in the argument string. */
315 expand_escape (const char *str)
318 const char *cp = str;
322 while (cp[0] != '\0' && cp[0] != '\\')
326 /* Found a backslash. */
329 if (strchr ("abcfnrtv\\01234567", cp[1]) != NULL)
334 retval = XNMALLOC (strlen (str), char);
336 rp = retval + (cp - str);
337 memcpy (retval, str, cp - str);
341 /* Here cp[0] == '\\'. */
344 case 'a': /* alert */
348 case 'b': /* backspace */
352 case 'c': /* suppress trailing newline */
356 case 'f': /* form feed */
360 case 'n': /* new line */
364 case 'r': /* carriage return */
368 case 't': /* horizontal tab */
372 case 'v': /* vertical tab */
380 case '0': case '1': case '2': case '3':
381 case '4': case '5': case '6': case '7':
383 int ch = *cp++ - '0';
385 if (*cp >= '0' && *cp <= '7')
390 if (*cp >= '0' && *cp <= '7')
404 while (cp[0] != '\0' && cp[0] != '\\')
407 while (cp[0] != '\0');
409 /* Terminate string. */
412 return (const char *) retval;