1 /* ngettext - retrieve plural form string from message catalog and print it.
2 Copyright (C) 1995-1997, 2000-2007, 2012, 2018-2020 Free Software Foundation, Inc.
3
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.
8
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.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17 #ifdef HAVE_CONFIG_H
18 # include <config.h>
19 #endif
20
21 #include <getopt.h>
22 #include <stdbool.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <locale.h>
27 #include <errno.h>
28
29 #include "noreturn.h"
30 #include "closeout.h"
31 #include "error.h"
32 #include "progname.h"
33 #include "relocatable.h"
34 #include "basename-lgpl.h"
35 #include "xalloc.h"
36 #include "propername.h"
37 #include "escapes.h"
38 #include "gettext.h"
39
40 #define _(str) gettext (str)
41
42 /* If true, expand escape sequences in strings before looking in the
43 message catalog. */
44 static int do_expand;
45
46 /* Long options. */
47 static const struct option long_options[] =
48 {
49 { "context", required_argument, NULL, 'c' },
50 { "domain", required_argument, NULL, 'd' },
51 { "help", no_argument, NULL, 'h' },
52 { "version", no_argument, NULL, 'V' },
53 { NULL, 0, NULL, 0 }
54 };
55
56 /* Forward declaration of local functions. */
57 _GL_NORETURN_FUNC static void usage (int status);
58
59 int
main(int argc,char * argv[])60 main (int argc, char *argv[])
61 {
62 int optchar;
63 const char *msgid;
64 const char *msgid_plural;
65 const char *count;
66 unsigned long n;
67
68 /* Default values for command line options. */
69 bool do_help = false;
70 bool do_version = false;
71 const char *domain = getenv ("TEXTDOMAIN");
72 const char *domaindir = getenv ("TEXTDOMAINDIR");
73 const char *context = NULL;
74 do_expand = false;
75
76 /* Set program name for message texts. */
77 set_program_name (argv[0]);
78
79 /* Set locale via LC_ALL. */
80 setlocale (LC_ALL, "");
81
82 /* Set the text message domain. */
83 bindtextdomain (PACKAGE, relocate (LOCALEDIR));
84 textdomain (PACKAGE);
85
86 /* Ensure that write errors on stdout are detected. */
87 atexit (close_stdout);
88
89 /* Parse command line options. */
90 while ((optchar = getopt_long (argc, argv, "+c:d:eEhV", long_options, NULL))
91 != EOF)
92 switch (optchar)
93 {
94 case '\0': /* Long option. */
95 break;
96 case 'c':
97 context = optarg;
98 break;
99 case 'd':
100 domain = optarg;
101 break;
102 case 'e':
103 do_expand = true;
104 break;
105 case 'E':
106 /* Ignore. Just for compatibility. */
107 break;
108 case 'h':
109 do_help = true;
110 break;
111 case 'V':
112 do_version = true;
113 break;
114 default:
115 usage (EXIT_FAILURE);
116 }
117
118 /* Version information is requested. */
119 if (do_version)
120 {
121 printf ("%s (GNU %s) %s\n", last_component (program_name),
122 PACKAGE, VERSION);
123 /* xgettext: no-wrap */
124 printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
125 License GPLv3+: GNU GPL version 3 or later <%s>\n\
126 This is free software: you are free to change and redistribute it.\n\
127 There is NO WARRANTY, to the extent permitted by law.\n\
128 "),
129 "1995-1997, 2000-2020", "https://gnu.org/licenses/gpl.html");
130 printf (_("Written by %s.\n"), proper_name ("Ulrich Drepper"));
131 exit (EXIT_SUCCESS);
132 }
133
134 /* Help is requested. */
135 if (do_help)
136 usage (EXIT_SUCCESS);
137
138 /* More optional command line options. */
139 switch (argc - optind)
140 {
141 default:
142 error (EXIT_FAILURE, 0, _("too many arguments"));
143
144 case 4:
145 domain = argv[optind++];
146 /* FALLTHROUGH */
147
148 case 3:
149 break;
150
151 case 2:
152 case 1:
153 case 0:
154 error (EXIT_FAILURE, 0, _("missing arguments"));
155 }
156
157 /* Now the mandatory command line options. */
158 msgid = argv[optind++];
159 msgid_plural = argv[optind++];
160 count = argv[optind++];
161
162 if (optind != argc)
163 abort ();
164
165 {
166 char *endp;
167 unsigned long tmp_val;
168
169 errno = 0;
170 tmp_val = strtoul (count, &endp, 10);
171 if (errno == 0 && count[0] != '\0' && endp[0] == '\0')
172 n = tmp_val;
173 else
174 /* When COUNT is not valid, use plural. */
175 n = 99;
176 }
177
178 /* Expand escape sequences if enabled. */
179 if (do_expand)
180 {
181 msgid = expand_escapes (msgid, NULL);
182 msgid_plural = expand_escapes (msgid_plural, NULL);
183 }
184
185 /* If no domain name is given we don't translate, and we use English
186 plural form handling. */
187 if (domain == NULL || domain[0] == '\0')
188 fputs (n == 1 ? msgid : msgid_plural, stdout);
189 else
190 {
191 /* Bind domain to appropriate directory. */
192 if (domaindir != NULL && domaindir[0] != '\0')
193 bindtextdomain (domain, domaindir);
194
195 /* Write out the result. */
196 fputs ((context != NULL
197 ? dnpgettext_expr (domain, context, msgid, msgid_plural, n)
198 : dngettext (domain, msgid, msgid_plural, n)),
199 stdout);
200 }
201
202 exit (EXIT_SUCCESS);
203 }
204
205
206 /* Display usage information and exit. */
207 static void
usage(int status)208 usage (int status)
209 {
210 if (status != EXIT_SUCCESS)
211 fprintf (stderr, _("Try '%s --help' for more information.\n"),
212 program_name);
213 else
214 {
215 /* xgettext: no-wrap */
216 printf (_("\
217 Usage: %s [OPTION] [TEXTDOMAIN] MSGID MSGID-PLURAL COUNT\n\
218 "), program_name);
219 printf ("\n");
220 /* xgettext: no-wrap */
221 printf (_("\
222 Display native language translation of a textual message whose grammatical\n\
223 form depends on a number.\n"));
224 printf ("\n");
225 /* xgettext: no-wrap */
226 printf (_("\
227 -d, --domain=TEXTDOMAIN retrieve translated message from TEXTDOMAIN\n"));
228 printf (_("\
229 -c, --context=CONTEXT specify context for MSGID\n"));
230 printf (_("\
231 -e enable expansion of some escape sequences\n"));
232 printf (_("\
233 -E (ignored for compatibility)\n"));
234 printf (_("\
235 [TEXTDOMAIN] retrieve translated message from TEXTDOMAIN\n"));
236 printf (_("\
237 MSGID MSGID-PLURAL translate MSGID (singular) / MSGID-PLURAL (plural)\n"));
238 printf (_("\
239 COUNT choose singular/plural form based on this value\n"));
240 printf ("\n");
241 printf (_("\
242 Informative output:\n"));
243 printf (_("\
244 -h, --help display this help and exit\n"));
245 printf (_("\
246 -V, --version display version information and exit\n"));
247 printf ("\n");
248 /* xgettext: no-wrap */
249 printf (_("\
250 If the TEXTDOMAIN parameter is not given, the domain is determined from the\n\
251 environment variable TEXTDOMAIN. If the message catalog is not found in the\n\
252 regular directory, another location can be specified with the environment\n\
253 variable TEXTDOMAINDIR.\n\
254 Standard search directory: %s\n"),
255 getenv ("IN_HELP2MAN") == NULL ? LOCALEDIR : "@localedir@");
256 printf ("\n");
257 /* TRANSLATORS: The first placeholder is the web address of the Savannah
258 project of this package. The second placeholder is the bug-reporting
259 email address for this package. Please add _another line_ saying
260 "Report translation bugs to <...>\n" with the address for translation
261 bugs (typically your translation team's web or email address). */
262 printf(_("\
263 Report bugs in the bug tracker at <%s>\n\
264 or by email to <%s>.\n"),
265 "https://savannah.gnu.org/projects/gettext",
266 "bug-gettext@gnu.org");
267 }
268
269 exit (status);
270 }
271