946a37548e576198e2211593bdf35e599320f673
[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 defined HAVE_STRTOUL || defined _LIBC
125           n = strtoul (nplurals, &endp, 10);
126 #else
127           for (endp = nplurals, n = 0; *endp >= '0' && *endp <= '9'; endp++)
128             n = n * 10 + (*endp - '0');
129 #endif
130           if (nplurals == endp)
131             goto no_plural;
132           *npluralsp = n;
133
134           /* Due to the restrictions bison imposes onto the interface of the
135              scanner function we have to put the input string and the result
136              passed up from the parser into the same structure which address
137              is passed down to the parser.  */
138           plural += 7;
139           args.cp = plural;
140           if (PLURAL_PARSE (&args) != 0)
141             goto no_plural;
142           *pluralp = args.res;
143         }
144     }
145   else
146     {
147       /* By default we are using the Germanic form: singular form only
148          for `one', the plural form otherwise.  Yes, this is also what
149          English is using since English is a Germanic language.  */
150     no_plural:
151       INIT_GERMANIC_PLURAL ();
152       *pluralp = &GERMANIC_PLURAL;
153       *npluralsp = 2;
154     }
155 }