2002-12-11 Bruno Haible <bruno@clisp.org>
[kopensolaris-gnu/glibc.git] / intl / plural-exp.c
1 /* Expression parsing for plural form selection.
2    Copyright (C) 2000, 2001 Free Software Foundation, Inc.
3    Written by Ulrich Drepper <drepper@cygnus.com>, 2000.
4    This file is part of the GNU C Library.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10
11    The GNU C Library 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 GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; if not, write to the Free
18    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19    02111-1307 USA.  */
20
21 #ifdef HAVE_CONFIG_H
22 # include <config.h>
23 #endif
24
25 #include <ctype.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include "plural-exp.h"
30
31 #if (defined __GNUC__ && !defined __APPLE_CC__) \
32     || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)
33
34 /* These structs are the constant expression for the germanic plural
35    form determination.  It represents the expression  "n != 1".  */
36 static const struct expression plvar =
37 {
38   .nargs = 0,
39   .operation = var,
40 };
41 static const struct expression plone =
42 {
43   .nargs = 0,
44   .operation = num,
45   .val =
46   {
47     .num = 1
48   }
49 };
50 struct expression GERMANIC_PLURAL =
51 {
52   .nargs = 2,
53   .operation = not_equal,
54   .val =
55   {
56     .args =
57     {
58       [0] = (struct expression *) &plvar,
59       [1] = (struct expression *) &plone
60     }
61   }
62 };
63
64 # define INIT_GERMANIC_PLURAL()
65
66 #else
67
68 /* For compilers without support for ISO C 99 struct/union initializers:
69    Initialization at run-time.  */
70
71 static struct expression plvar;
72 static struct expression plone;
73 struct expression GERMANIC_PLURAL;
74
75 static void
76 init_germanic_plural ()
77 {
78   if (plone.val.num == 0)
79     {
80       plvar.nargs = 0;
81       plvar.operation = var;
82
83       plone.nargs = 0;
84       plone.operation = num;
85       plone.val.num = 1;
86
87       GERMANIC_PLURAL.nargs = 2;
88       GERMANIC_PLURAL.operation = not_equal;
89       GERMANIC_PLURAL.val.args[0] = &plvar;
90       GERMANIC_PLURAL.val.args[1] = &plone;
91     }
92 }
93
94 # define INIT_GERMANIC_PLURAL() init_germanic_plural ()
95
96 #endif
97
98 void
99 internal_function
100 EXTRACT_PLURAL_EXPRESSION (nullentry, pluralp, npluralsp)
101      const char *nullentry;
102      struct expression **pluralp;
103      unsigned long int *npluralsp;
104 {
105   if (nullentry != NULL)
106     {
107       const char *plural;
108       const char *nplurals;
109
110       plural = strstr (nullentry, "plural=");
111       nplurals = strstr (nullentry, "nplurals=");
112       if (plural == NULL || nplurals == NULL)
113         goto no_plural;
114       else
115         {
116           char *endp;
117           unsigned long int n;
118           struct parse_args args;
119
120           /* First get the number.  */
121           nplurals += 9;
122           while (*nplurals != '\0' && isspace ((unsigned char) *nplurals))
123             ++nplurals;
124           if (!(*nplurals >= '0' && *nplurals <= '9'))
125             goto no_plural;
126 #if defined HAVE_STRTOUL || defined _LIBC
127           n = strtoul (nplurals, &endp, 10);
128 #else
129           for (endp = nplurals, n = 0; *endp >= '0' && *endp <= '9'; endp++)
130             n = n * 10 + (*endp - '0');
131 #endif
132           if (nplurals == endp)
133             goto no_plural;
134           *npluralsp = n;
135
136           /* Due to the restrictions bison imposes onto the interface of the
137              scanner function we have to put the input string and the result
138              passed up from the parser into the same structure which address
139              is passed down to the parser.  */
140           plural += 7;
141           args.cp = plural;
142           if (PLURAL_PARSE (&args) != 0)
143             goto no_plural;
144           *pluralp = args.res;
145         }
146     }
147   else
148     {
149       /* By default we are using the Germanic form: singular form only
150          for `one', the plural form otherwise.  Yes, this is also what
151          English is using since English is a Germanic language.  */
152     no_plural:
153       INIT_GERMANIC_PLURAL ();
154       *pluralp = &GERMANIC_PLURAL;
155       *npluralsp = 2;
156     }
157 }