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