(root)/
gettext-0.22.4/
gettext-runtime/
intl/
plural-exp.c
       1  /* Expression parsing for plural form selection.
       2     Copyright (C) 2000-2016, 2021 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 HAVE_STRUCT_INITIALIZER
      29  
      30  /* These structs are the constant expression for the germanic plural
      31     form determination.  It represents the expression  "n != 1".  */
      32  static const struct expression plvar =
      33  {
      34    .nargs = 0,
      35    .operation = var,
      36  };
      37  static const struct expression plone =
      38  {
      39    .nargs = 0,
      40    .operation = num,
      41    .val =
      42    {
      43      .num = 1
      44    }
      45  };
      46  const struct expression GERMANIC_PLURAL =
      47  {
      48    .nargs = 2,
      49    .operation = not_equal,
      50    .val =
      51    {
      52      .args =
      53      {
      54        [0] = (struct expression *) &plvar,
      55        [1] = (struct expression *) &plone
      56      }
      57    }
      58  };
      59  
      60  # define INIT_GERMANIC_PLURAL()
      61  
      62  #else
      63  
      64  /* For compilers without support for ISO C 99 struct/union initializers:
      65     Initialization at run-time.  */
      66  
      67  static struct expression plvar;
      68  static struct expression plone;
      69  struct expression GERMANIC_PLURAL;
      70  
      71  static void
      72  init_germanic_plural (void)
      73  {
      74    if (plone.val.num == 0)
      75      {
      76        plvar.nargs = 0;
      77        plvar.operation = var;
      78  
      79        plone.nargs = 0;
      80        plone.operation = num;
      81        plone.val.num = 1;
      82  
      83        GERMANIC_PLURAL.nargs = 2;
      84        GERMANIC_PLURAL.operation = not_equal;
      85        GERMANIC_PLURAL.val.args[0] = &plvar;
      86        GERMANIC_PLURAL.val.args[1] = &plone;
      87      }
      88  }
      89  
      90  # define INIT_GERMANIC_PLURAL() init_germanic_plural ()
      91  
      92  #endif
      93  
      94  void
      95  internal_function
      96  EXTRACT_PLURAL_EXPRESSION (const char *nullentry,
      97  			   const struct expression **pluralp,
      98  			   unsigned long int *npluralsp)
      99  {
     100    if (nullentry != NULL)
     101      {
     102        const char *plural;
     103        const char *nplurals;
     104  
     105        plural = strstr (nullentry, "plural=");
     106        nplurals = strstr (nullentry, "nplurals=");
     107        if (plural == NULL || nplurals == NULL)
     108  	goto no_plural;
     109        else
     110  	{
     111  	  char *endp;
     112  	  unsigned long int n;
     113  	  struct parse_args args;
     114  
     115  	  /* First get the number.  */
     116  	  nplurals += 9;
     117  	  while (*nplurals != '\0' && isspace ((unsigned char) *nplurals))
     118  	    ++nplurals;
     119  	  if (!(*nplurals >= '0' && *nplurals <= '9'))
     120  	    goto no_plural;
     121  	  n = strtoul (nplurals, &endp, 10);
     122  	  if (nplurals == endp)
     123  	    goto no_plural;
     124  	  *npluralsp = n;
     125  
     126  	  /* Due to the restrictions bison imposes onto the interface of the
     127  	     scanner function we have to put the input string and the result
     128  	     passed up from the parser into the same structure which address
     129  	     is passed down to the parser.  */
     130  	  plural += 7;
     131  	  args.cp = plural;
     132  	  if (PLURAL_PARSE (&args) != 0)
     133  	    goto no_plural;
     134  	  *pluralp = args.res;
     135  	}
     136      }
     137    else
     138      {
     139        /* By default we are using the Germanic form: singular form only
     140           for `one', the plural form otherwise.  Yes, this is also what
     141           English is using since English is a Germanic language.  */
     142      no_plural:
     143        INIT_GERMANIC_PLURAL ();
     144        *pluralp = &GERMANIC_PLURAL;
     145        *npluralsp = 2;
     146      }
     147  }