1 /* ngettext - retrieve plural form string from message catalog and print it.
2 Copyright (C) 1995-1997, 2000-2007 Free Software Foundation, Inc.
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.
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.
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/>. */
32 #include "relocatable.h"
35 #include "propername.h"
38 #define _(str) gettext (str)
40 /* If true, expand escape sequences in strings before looking in the
45 static const struct option long_options[] =
47 { "domain", required_argument, NULL, 'd' },
48 { "help", no_argument, NULL, 'h' },
49 { "version", no_argument, NULL, 'V' },
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))
59 static const char *expand_escape (const char *str);
62 main (int argc, char *argv[])
66 const char *msgid_plural;
70 /* Default values for command line options. */
72 bool do_version = false;
73 const char *domain = getenv ("TEXTDOMAIN");
74 const char *domaindir = getenv ("TEXTDOMAINDIR");
77 /* Set program name for message texts. */
78 set_program_name (argv[0]);
81 /* Set locale via LC_ALL. */
82 setlocale (LC_ALL, "");
85 /* Set the text message domain. */
86 bindtextdomain (PACKAGE, relocate (LOCALEDIR));
89 /* Ensure that write errors on stdout are detected. */
90 atexit (close_stdout);
92 /* Parse command line options. */
93 while ((optchar = getopt_long (argc, argv, "+d:eEhV", long_options, NULL))
97 case '\0': /* Long option. */
106 /* Ignore. Just for compatibility. */
115 usage (EXIT_FAILURE);
118 /* Version information is requested. */
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\
128 "1995-1997, 2000-2007");
129 printf (_("Written by %s.\n"), proper_name ("Ulrich Drepper"));
133 /* Help is requested. */
135 usage (EXIT_SUCCESS);
137 /* More optional command line options. */
138 switch (argc - optind)
141 error (EXIT_FAILURE, 0, _("too many arguments"));
144 domain = argv[optind++];
153 error (EXIT_FAILURE, 0, _("missing arguments"));
156 /* Now the mandatory command line options. */
157 msgid = argv[optind++];
158 msgid_plural = argv[optind++];
159 count = argv[optind++];
166 unsigned long tmp_val;
169 tmp_val = strtoul (count, &endp, 10);
170 if (errno == 0 && count[0] != '\0' && endp[0] == '\0')
173 /* When COUNT is not valid, use plural. */
177 /* Expand escape sequences if enabled. */
180 msgid = expand_escape (msgid);
181 msgid_plural = expand_escape (msgid_plural);
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);
190 /* Bind domain to appropriate directory. */
191 if (domaindir != NULL && domaindir[0] != '\0')
192 bindtextdomain (domain, domaindir);
194 /* Write out the result. */
195 fputs (dngettext (domain, msgid, msgid_plural, n), stdout);
202 /* Display usage information and exit. */
206 if (status != EXIT_SUCCESS)
207 fprintf (stderr, _("Try '%s --help' for more information.\n"),
211 /* xgettext: no-wrap */
213 Usage: %s [OPTION] [TEXTDOMAIN] MSGID MSGID-PLURAL COUNT\n\
216 /* xgettext: no-wrap */
218 Display native language translation of a textual message whose grammatical\n\
219 form depends on a number.\n"));
221 /* xgettext: no-wrap */
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"));
232 /* xgettext: no-wrap */
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@");
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);
252 /* Expand some escape sequences found in the argument string. */
254 expand_escape (const char *str)
257 const char *cp = str;
261 while (cp[0] != '\0' && cp[0] != '\\')
265 /* Found a backslash. */
268 if (strchr ("abcfnrtv\\01234567", cp[1]) != NULL)
273 retval = XNMALLOC (strlen (str), char);
275 rp = retval + (cp - str);
276 memcpy (retval, str, cp - str);
280 /* Here cp[0] == '\\'. */
283 case 'a': /* alert */
287 case 'b': /* backspace */
291 case 'f': /* form feed */
295 case 'n': /* new line */
299 case 'r': /* carriage return */
303 case 't': /* horizontal tab */
307 case 'v': /* vertical tab */
315 case '0': case '1': case '2': case '3':
316 case '4': case '5': case '6': case '7':
318 int ch = *cp++ - '0';
320 if (*cp >= '0' && *cp <= '7')
325 if (*cp >= '0' && *cp <= '7')
339 while (cp[0] != '\0' && cp[0] != '\\')
342 while (cp[0] != '\0');
344 /* Terminate string. */
347 return (const char *) retval;