1 /* ngettext - retrieve plural form strings from message catalog and print them.
2 Copyright (C) 1995-1997, 2000-2007, 2012, 2018-2020 Free Software
3 Foundation, Inc.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21
22 #include <getopt.h>
23 #include <stdbool.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <locale.h>
28 #include <errno.h>
29
30 #include "attribute.h"
31 #include "noreturn.h"
32 #include "closeout.h"
33 #include "error.h"
34 #include "progname.h"
35 #include "relocatable.h"
36 #include "basename-lgpl.h"
37 #include "propername.h"
38 #include "xsetenv.h"
39
40 /* Make sure we use the included libintl, not the system's one. */
41 #undef _LIBINTL_H
42 #include "libgnuintl.h"
43
44 #if defined _WIN32 && !defined __CYGWIN__
45 # undef setlocale
46 # define setlocale fake_setlocale
47 extern char *setlocale (int category, const char *locale);
48 #endif
49
50 #define _(str) gettext (str)
51
52 /* Long options. */
53 static const struct option long_options[] =
54 {
55 { "domain", required_argument, NULL, 'd' },
56 { "env", required_argument, NULL, '=' },
57 { "help", no_argument, NULL, 'h' },
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
66 main (int argc, char *argv[])
67 {
68 int optchar;
69 const char *msgid;
70 const char *msgid_plural;
71 const char *count;
72 unsigned long n;
73
74 /* Default values for command line options. */
75 bool do_help = false;
76 bool do_version = false;
77 bool environ_changed = false;
78 const char *domain = getenv ("TEXTDOMAIN");
79 const char *domaindir = getenv ("TEXTDOMAINDIR");
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, "+d:hV", long_options, NULL))
96 != EOF)
97 switch (optchar)
98 {
99 case '\0': /* Long option. */
100 break;
101 case 'd':
102 domain = optarg;
103 break;
104 case 'h':
105 do_help = true;
106 break;
107 case 'V':
108 do_version = true;
109 break;
110 case '=':
111 {
112 /* Undocumented option --env sets an environment variable. */
113 char *separator = strchr (optarg, '=');
114 if (separator != NULL)
115 {
116 *separator = '\0';
117 xsetenv (optarg, separator + 1, 1);
118 environ_changed = true;
119 break;
120 }
121 }
122 FALLTHROUGH;
123 default:
124 usage (EXIT_FAILURE);
125 }
126
127 if (environ_changed)
128 /* Set locale again via LC_ALL. */
129 setlocale (LC_ALL, "");
130
131 /* Version information is requested. */
132 if (do_version)
133 {
134 printf ("%s (GNU %s) %s\n", last_component (program_name),
135 PACKAGE, VERSION);
136 /* xgettext: no-wrap */
137 printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
138 License GPLv3+: GNU GPL version 3 or later <%s>\n\
139 This is free software: you are free to change and redistribute it.\n\
140 There is NO WARRANTY, to the extent permitted by law.\n\
141 "),
142 "1995-1997, 2000-2006", "https://gnu.org/licenses/gpl.html");
143 printf (_("Written by %s.\n"), proper_name ("Ulrich Drepper"));
144 exit (EXIT_SUCCESS);
145 }
146
147 /* Help is requested. */
148 if (do_help)
149 usage (EXIT_SUCCESS);
150
151 /* More optional command line options. */
152 if (argc - optind <= 2)
153 error (EXIT_FAILURE, 0, _("missing arguments"));
154
155 /* Now the mandatory command line options. */
156 msgid = argv[optind++];
157 msgid_plural = argv[optind++];
158
159 /* If no domain name is given we print the original string.
160 We mark this assigning NULL to domain. */
161 if (domain == NULL || domain[0] == '\0')
162 domain = NULL;
163 else
164 /* Bind domain to appropriate directory. */
165 if (domaindir != NULL && domaindir[0] != '\0')
166 bindtextdomain (domain, domaindir);
167
168 /* To speed up the plural-2 test, we accept more than one COUNT in one
169 call. */
170 while (optind < argc)
171 {
172 count = argv[optind++];
173
174 {
175 char *endp;
176 unsigned long tmp_val;
177
178 errno = 0;
179 tmp_val = strtoul (count, &endp, 10);
180 if (errno == 0 && count[0] != '\0' && endp[0] == '\0')
181 n = tmp_val;
182 else
183 /* When COUNT is not valid, use plural. */
184 n = 99;
185 }
186
187 /* If no domain name is given we don't translate, and we use English
188 plural form handling. */
189 if (domain == NULL)
190 fputs (n == 1 ? msgid : msgid_plural, stdout);
191 else
192 /* Write out the result. */
193 fputs (dngettext (domain, msgid, msgid_plural, n), stdout);
194 }
195
196 exit (EXIT_SUCCESS);
197 }
198
199
200 /* Display usage information and exit. */
201 static void
202 usage (int status)
203 {
204 if (status != EXIT_SUCCESS)
205 fprintf (stderr, _("Try '%s --help' for more information.\n"),
206 program_name);
207 else
208 {
209 /* xgettext: no-wrap */
210 printf (_("\
211 Usage: %s [OPTION] MSGID MSGID-PLURAL COUNT...\n\
212 -d, --domain=TEXTDOMAIN retrieve translated message from TEXTDOMAIN\n\
213 -h, --help display this help and exit\n\
214 -V, --version display version information and exit\n\
215 MSGID MSGID-PLURAL translate MSGID (singular) / MSGID-PLURAL (plural)\n\
216 COUNT choose singular/plural form based on this value\n"),
217 program_name);
218 /* xgettext: no-wrap */
219 printf (_("\
220 \n\
221 If the TEXTDOMAIN parameter is not given, the domain is determined from the\n\
222 environment variable TEXTDOMAIN. If the message catalog is not found in the\n\
223 regular directory, another location can be specified with the environment\n\
224 variable TEXTDOMAINDIR.\n\
225 Standard search directory: %s\n"), LOCALEDIR);
226 /* TRANSLATORS: The first placeholder is the web address of the Savannah
227 project of this package. The second placeholder is the bug-reporting
228 email address for this package. Please add _another line_ saying
229 "Report translation bugs to <...>\n" with the address for translation
230 bugs (typically your translation team's web or email address). */
231 printf(_("\
232 Report bugs in the bug tracker at <%s>\n\
233 or by email to <%s>.\n"),
234 "https://savannah.gnu.org/projects/gettext",
235 "bug-gettext@gnu.org");
236 }
237
238 exit (status);
239 }