nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* ngettext - retrieve plural form string from message catalog and print it. |
2 | Copyright (C) 1995-1997, 2000-2007, 2015-2016 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 <http://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 "closeout.h" |
||
30 | #include "error.h" |
||
31 | #include "progname.h" |
||
32 | #include "relocatable.h" |
||
33 | #include "basename.h" |
||
34 | #include "xalloc.h" |
||
35 | #include "propername.h" |
||
36 | #include "gettext.h" |
||
37 | |||
38 | #define _(str) gettext (str) |
||
39 | |||
40 | /* If true, expand escape sequences in strings before looking in the |
||
41 | message catalog. */ |
||
42 | static int do_expand; |
||
43 | |||
44 | /* Long options. */ |
||
45 | static const struct option long_options[] = |
||
46 | { |
||
47 | { "domain", required_argument, NULL, 'd' }, |
||
48 | { "help", no_argument, NULL, 'h' }, |
||
49 | { "version", no_argument, NULL, 'V' }, |
||
50 | { NULL, 0, NULL, 0 } |
||
51 | }; |
||
52 | |||
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)) |
||
57 | #endif |
||
58 | ; |
||
59 | static const char *expand_escape (const char *str); |
||
60 | |||
61 | int |
||
62 | main (int argc, char *argv[]) |
||
63 | { |
||
64 | int optchar; |
||
65 | const char *msgid; |
||
66 | const char *msgid_plural; |
||
67 | const char *count; |
||
68 | unsigned long n; |
||
69 | |||
70 | /* Default values for command line options. */ |
||
71 | bool do_help = false; |
||
72 | bool do_version = false; |
||
73 | const char *domain = getenv ("TEXTDOMAIN"); |
||
74 | const char *domaindir = getenv ("TEXTDOMAINDIR"); |
||
75 | do_expand = false; |
||
76 | |||
77 | /* Set program name for message texts. */ |
||
78 | set_program_name (argv[0]); |
||
79 | |||
80 | #ifdef HAVE_SETLOCALE |
||
81 | /* Set locale via LC_ALL. */ |
||
82 | setlocale (LC_ALL, ""); |
||
83 | #endif |
||
84 | |||
85 | /* Set the text message domain. */ |
||
86 | bindtextdomain (PACKAGE, relocate (LOCALEDIR)); |
||
87 | textdomain (PACKAGE); |
||
88 | |||
89 | /* Ensure that write errors on stdout are detected. */ |
||
90 | atexit (close_stdout); |
||
91 | |||
92 | /* Parse command line options. */ |
||
93 | while ((optchar = getopt_long (argc, argv, "+d:eEhV", long_options, NULL)) |
||
94 | != EOF) |
||
95 | switch (optchar) |
||
96 | { |
||
97 | case '\0': /* Long option. */ |
||
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", 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\ |
||
127 | "), |
||
128 | "1995-1997, 2000-2007"); |
||
129 | printf (_("Written by %s.\n"), proper_name ("Ulrich Drepper")); |
||
130 | exit (EXIT_SUCCESS); |
||
131 | } |
||
132 | |||
133 | /* Help is requested. */ |
||
134 | if (do_help) |
||
135 | usage (EXIT_SUCCESS); |
||
136 | |||
137 | /* More optional command line options. */ |
||
138 | switch (argc - optind) |
||
139 | { |
||
140 | default: |
||
141 | error (EXIT_FAILURE, 0, _("too many arguments")); |
||
142 | |||
143 | case 4: |
||
144 | domain = argv[optind++]; |
||
145 | /* FALLTHROUGH */ |
||
146 | |||
147 | case 3: |
||
148 | break; |
||
149 | |||
150 | case 2: |
||
151 | case 1: |
||
152 | case 0: |
||
153 | error (EXIT_FAILURE, 0, _("missing arguments")); |
||
154 | } |
||
155 | |||
156 | /* Now the mandatory command line options. */ |
||
157 | msgid = argv[optind++]; |
||
158 | msgid_plural = argv[optind++]; |
||
159 | count = argv[optind++]; |
||
160 | |||
161 | if (optind != argc) |
||
162 | abort (); |
||
163 | |||
164 | { |
||
165 | char *endp; |
||
166 | unsigned long tmp_val; |
||
167 | |||
168 | errno = 0; |
||
169 | tmp_val = strtoul (count, &endp, 10); |
||
170 | if (errno == 0 && count[0] != '\0' && endp[0] == '\0') |
||
171 | n = tmp_val; |
||
172 | else |
||
173 | /* When COUNT is not valid, use plural. */ |
||
174 | n = 99; |
||
175 | } |
||
176 | |||
177 | /* Expand escape sequences if enabled. */ |
||
178 | if (do_expand) |
||
179 | { |
||
180 | msgid = expand_escape (msgid); |
||
181 | msgid_plural = expand_escape (msgid_plural); |
||
182 | } |
||
183 | |||
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); |
||
188 | else |
||
189 | { |
||
190 | /* Bind domain to appropriate directory. */ |
||
191 | if (domaindir != NULL && domaindir[0] != '\0') |
||
192 | bindtextdomain (domain, domaindir); |
||
193 | |||
194 | /* Write out the result. */ |
||
195 | fputs (dngettext (domain, msgid, msgid_plural, n), stdout); |
||
196 | } |
||
197 | |||
198 | exit (EXIT_SUCCESS); |
||
199 | } |
||
200 | |||
201 | |||
202 | /* Display usage information and exit. */ |
||
203 | static void |
||
204 | usage (int status) |
||
205 | { |
||
206 | if (status != EXIT_SUCCESS) |
||
207 | fprintf (stderr, _("Try '%s --help' for more information.\n"), |
||
208 | program_name); |
||
209 | else |
||
210 | { |
||
211 | /* xgettext: no-wrap */ |
||
212 | printf (_("\ |
||
213 | Usage: %s [OPTION] [TEXTDOMAIN] MSGID MSGID-PLURAL COUNT\n\ |
||
214 | "), program_name); |
||
215 | printf ("\n"); |
||
216 | /* xgettext: no-wrap */ |
||
217 | printf (_("\ |
||
218 | Display native language translation of a textual message whose grammatical\n\ |
||
219 | form depends on a number.\n")); |
||
220 | printf ("\n"); |
||
221 | /* xgettext: no-wrap */ |
||
222 | printf (_("\ |
||
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")); |
||
231 | printf ("\n"); |
||
232 | /* xgettext: no-wrap */ |
||
233 | printf (_("\ |
||
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@"); |
||
240 | printf ("\n"); |
||
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); |
||
246 | } |
||
247 | |||
248 | exit (status); |
||
249 | } |
||
250 | |||
251 | |||
252 | /* Expand some escape sequences found in the argument string. */ |
||
253 | static const char * |
||
254 | expand_escape (const char *str) |
||
255 | { |
||
256 | char *retval, *rp; |
||
257 | const char *cp = str; |
||
258 | |||
259 | for (;;) |
||
260 | { |
||
261 | while (cp[0] != '\0' && cp[0] != '\\') |
||
262 | ++cp; |
||
263 | if (cp[0] == '\0') |
||
264 | return str; |
||
265 | /* Found a backslash. */ |
||
266 | if (cp[1] == '\0') |
||
267 | return str; |
||
268 | if (strchr ("abcfnrtv\\01234567", cp[1]) != NULL) |
||
269 | break; |
||
270 | ++cp; |
||
271 | } |
||
272 | |||
273 | retval = XNMALLOC (strlen (str), char); |
||
274 | |||
275 | rp = retval + (cp - str); |
||
276 | memcpy (retval, str, cp - str); |
||
277 | |||
278 | do |
||
279 | { |
||
280 | /* Here cp[0] == '\\'. */ |
||
281 | switch (*++cp) |
||
282 | { |
||
283 | case 'a': /* alert */ |
||
284 | *rp++ = '\a'; |
||
285 | ++cp; |
||
286 | break; |
||
287 | case 'b': /* backspace */ |
||
288 | *rp++ = '\b'; |
||
289 | ++cp; |
||
290 | break; |
||
291 | case 'f': /* form feed */ |
||
292 | *rp++ = '\f'; |
||
293 | ++cp; |
||
294 | break; |
||
295 | case 'n': /* new line */ |
||
296 | *rp++ = '\n'; |
||
297 | ++cp; |
||
298 | break; |
||
299 | case 'r': /* carriage return */ |
||
300 | *rp++ = '\r'; |
||
301 | ++cp; |
||
302 | break; |
||
303 | case 't': /* horizontal tab */ |
||
304 | *rp++ = '\t'; |
||
305 | ++cp; |
||
306 | break; |
||
307 | case 'v': /* vertical tab */ |
||
308 | *rp++ = '\v'; |
||
309 | ++cp; |
||
310 | break; |
||
311 | case '\\': |
||
312 | *rp = '\\'; |
||
313 | ++cp; |
||
314 | break; |
||
315 | case '0': case '1': case '2': case '3': |
||
316 | case '4': case '5': case '6': case '7': |
||
317 | { |
||
318 | int ch = *cp++ - '0'; |
||
319 | |||
320 | if (*cp >= '0' && *cp <= '7') |
||
321 | { |
||
322 | ch *= 8; |
||
323 | ch += *cp++ - '0'; |
||
324 | |||
325 | if (*cp >= '0' && *cp <= '7') |
||
326 | { |
||
327 | ch *= 8; |
||
328 | ch += *cp++ - '0'; |
||
329 | } |
||
330 | } |
||
331 | *rp = ch; |
||
332 | } |
||
333 | break; |
||
334 | default: |
||
335 | *rp = '\\'; |
||
336 | break; |
||
337 | } |
||
338 | |||
339 | while (cp[0] != '\0' && cp[0] != '\\') |
||
340 | *rp++ = *cp++; |
||
341 | } |
||
342 | while (cp[0] != '\0'); |
||
343 | |||
344 | /* Terminate string. */ |
||
345 | *rp = '\0'; |
||
346 | |||
347 | return (const char *) retval; |
||
348 | } |