1 /* Unicode CLDR plural rule parser and converter
2 Copyright (C) 2015 Free Software Foundation, Inc.
4 This file was written by Daiki Ueno <ueno@gnu.org>, 2015.
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/>. */
24 #include "cldr-plural-exp.h"
30 #include <libxml/tree.h>
31 #include <libxml/parser.h>
34 #include "propername.h"
35 #include "relocatable.h"
40 #define _(s) gettext(s)
44 extract_rules (FILE *fp,
45 const char *real_filename, const char *logical_filename,
51 char *buffer = NULL, *p;
55 doc = xmlReadFd (fileno (fp), logical_filename, NULL,
59 | XML_PARSE_NOBLANKS);
61 error (EXIT_FAILURE, 0, _("memory exhausted"));
63 node = xmlDocGetRootElement (doc);
64 if (!node || !xmlStrEqual (node->name, BAD_CAST "supplementalData"))
70 The root element must be <%s>"),
75 for (n = node->children; n; n = n->next)
77 if (n->type == XML_ELEMENT_NODE
78 && xmlStrEqual (n->name, BAD_CAST "plurals"))
83 error (0, 0, _("The element <%s> does not contain a <%s> element"),
84 "supplementalData", "plurals");
88 locale_length = strlen (locale);
89 for (n = n->children; n; n = n->next)
96 if (n->type != XML_ELEMENT_NODE
97 || !xmlStrEqual (n->name, BAD_CAST "pluralRules"))
100 if (!xmlHasProp (n, BAD_CAST "locales"))
106 The element <%s> does not have attribute <%s>"),
107 "pluralRules", "locales");
111 cp = locales = xmlGetProp (n, BAD_CAST "locales");
114 while (c_isspace (*cp))
116 if (xmlStrncmp (cp, BAD_CAST locale, locale_length) == 0
117 && (*(cp + locale_length) == '\0'
118 || c_isspace (*(cp + locale_length))))
123 while (*cp && !c_isspace (*cp))
131 for (n2 = n->children; n2; n2 = n2->next)
137 if (n2->type != XML_ELEMENT_NODE
138 || !xmlStrEqual (n2->name, BAD_CAST "pluralRule"))
141 if (!xmlHasProp (n2, BAD_CAST "count"))
147 The element <%s> does not have attribute <%s>"),
148 "pluralRule", "count");
152 count = xmlGetProp (n2, BAD_CAST "count");
153 content = xmlNodeGetContent (n2);
154 length = xmlStrlen (count) + strlen (": ")
155 + xmlStrlen (content) + strlen ("; ");
157 if (buflen + length + 1 > bufmax)
160 if (bufmax < buflen + length + 1)
161 bufmax = buflen + length + 1;
162 buffer = (char *) xrealloc (buffer, bufmax);
165 sprintf (buffer + buflen, "%s: %s; ", count, content);
175 /* Scrub the last semicolon, if any. */
176 p = strrchr (buffer, ';');
186 /* Display usage information and exit. */
190 if (status != EXIT_SUCCESS)
191 fprintf (stderr, _("Try '%s --help' for more information.\n"),
196 Usage: %s [OPTION...] [LOCALE RULES]...\n\
199 /* xgettext: no-wrap */
201 Extract or convert Unicode CLDR plural rules.\n\
203 If both LOCALE and RULES are specified, it reads CLDR plural rules for\n\
204 LOCALE from RULES and print them in a form suitable for gettext use.\n\
205 If no argument is given, it reads CLDR plural rules from the standard input.\n\
208 /* xgettext: no-wrap */
210 Mandatory arguments to long options are mandatory for short options too.\n\
211 Similarly for optional arguments.\n\
215 -c, --cldr print plural rules in the CLDR format\n"));
217 -h, --help display this help and exit\n"));
219 -V, --version output version information and exit\n"));
221 /* TRANSLATORS: The placeholder indicates the bug-reporting address
222 for this package. Please add _another line_ saying
223 "Report translation bugs to <...>\n" with the address for translation
224 bugs (typically your translation team's web or email address). */
225 fputs (_("Report bugs to <bug-gnu-gettext@gnu.org>.\n"),
232 static const struct option long_options[] =
234 { "cldr", no_argument, NULL, 'c' },
235 { "help", no_argument, NULL, 'h' },
236 { "version", no_argument, NULL, 'V' },
241 main (int argc, char **argv)
243 bool opt_cldr_format = false;
244 bool do_help = false;
245 bool do_version = false;
248 /* Set program name for messages. */
249 set_program_name (argv[0]);
251 #ifdef HAVE_SETLOCALE
252 /* Set locale via LC_ALL. */
253 setlocale (LC_ALL, "");
256 /* Set the text message domain. */
257 bindtextdomain (PACKAGE, relocate (LOCALEDIR));
258 bindtextdomain ("bison-runtime", relocate (BISON_LOCALEDIR));
259 textdomain (PACKAGE);
261 while ((optchar = getopt_long (argc, argv, "chV", long_options, NULL)) != EOF)
264 case '\0': /* Long option. */
268 opt_cldr_format = true;
280 usage (EXIT_FAILURE);
284 /* Version information requested. */
287 printf ("%s (GNU %s) %s\n", basename (program_name), PACKAGE, VERSION);
288 /* xgettext: no-wrap */
289 printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
290 License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n\
291 This is free software: you are free to change and redistribute it.\n\
292 There is NO WARRANTY, to the extent permitted by law.\n\
295 printf (_("Written by %s.\n"), proper_name ("Daiki Ueno"));
299 /* Help is requested. */
301 usage (EXIT_SUCCESS);
303 if (argc == optind + 2)
305 /* Two arguments: Read CLDR rules from a file. */
306 const char *locale = argv[optind];
307 const char *logical_filename = argv[optind + 1];
308 char *extracted_rules;
313 fp = fopen (logical_filename, "r");
315 error (1, 0, _("%s cannot be read"), logical_filename);
317 extracted_rules = extract_rules (fp, logical_filename, logical_filename,
320 if (extracted_rules == NULL)
321 error (1, 0, _("cannot extract rules for %s"), locale);
324 printf ("%s\n", extracted_rules);
327 struct cldr_plural_rule_list_ty *result;
329 result = cldr_plural_parse (extracted_rules);
331 error (1, 0, _("cannot parse CLDR rule"));
333 cldr_plural_rule_list_print (result, stdout);
334 cldr_plural_rule_list_free (result);
336 free (extracted_rules);
338 else if (argc == optind)
340 /* No argument: Read CLDR rules from standard input. */
342 size_t line_size = 0;
346 struct cldr_plural_rule_list_ty *result;
348 line_len = getline (&line, &line_size, stdin);
351 if (line_len > 0 && line[line_len - 1] == '\n')
352 line[--line_len] = '\0';
354 result = cldr_plural_parse (line);
357 cldr_plural_rule_list_print (result, stdout);
358 cldr_plural_rule_list_free (result);
366 error (1, 0, _("extra operand %s"), argv[optind]);