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