(root)/
gettext-0.22.4/
gettext-tools/
src/
cldr-plural-exp.c
       1  /* Unicode CLDR plural rule parser and converter
       2     Copyright (C) 2015, 2018-2020 Free Software Foundation, Inc.
       3  
       4     This file was written by Daiki Ueno <ueno@gnu.org>, 2015.
       5  
       6     This program is free software: you can redistribute it and/or modify
       7     it under the terms of the GNU General Public License as published by
       8     the Free Software Foundation; either version 3 of the License, or
       9     (at your option) any later version.
      10  
      11     This program 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
      14     GNU General Public License for more details.
      15  
      16     You should have received a copy of the GNU General Public License
      17     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      18  
      19  #ifdef HAVE_CONFIG_H
      20  # include <config.h>
      21  #endif
      22  
      23  #include <stdio.h>
      24  #include <stdlib.h>
      25  #include <string.h>
      26  #include <unistd.h>
      27  #include "unistr.h"
      28  #include "xalloc.h"
      29  
      30  #include "cldr-plural-exp.h"
      31  #include "cldr-plural.h"
      32  
      33  /* The grammar of Unicode CLDR plural rules is defined at:
      34     https://unicode.org/reports/tr35/tr35-numbers.html#Plural_rules_syntax
      35  
      36     This implementation only supports the "preferred" form, which
      37     doesn't support obsolete keywords "in", "is", "not", and "within".
      38  
      39     Unlike gettext, CLDR allows an unsigned decimal value as an
      40     operand, in addition to unsigned integers.  For simplicity, we
      41     treat decimal relations as if it has a constant truth value.
      42  
      43     The implementation is largely based on the idea of Michele Locati's
      44     cldr-to-gettext-plural-rules:
      45     https://github.com/mlocati/cldr-to-gettext-plural-rules  */
      46  
      47  void
      48  cldr_plural_range_free (struct cldr_plural_range_ty *range)
      49  {
      50    if (range->start != range->end)
      51      free (range->start);
      52    free (range->end);
      53    free (range);
      54  }
      55  
      56  void
      57  cldr_plural_range_list_free (struct cldr_plural_range_list_ty *ranges)
      58  {
      59    while (ranges->nitems-- > 0)
      60      cldr_plural_range_free (ranges->items[ranges->nitems]);
      61    free (ranges->items);
      62    free (ranges);
      63  }
      64  
      65  void
      66  cldr_plural_condition_free (struct cldr_plural_condition_ty *condition)
      67  {
      68    if (condition->type == CLDR_PLURAL_CONDITION_AND
      69        || condition->type == CLDR_PLURAL_CONDITION_OR)
      70      {
      71        cldr_plural_condition_free (condition->value.conditions[0]);
      72        cldr_plural_condition_free (condition->value.conditions[1]);
      73      }
      74    else if (condition->type == CLDR_PLURAL_CONDITION_RELATION)
      75      cldr_plural_relation_free (condition->value.relation);
      76    free (condition);
      77  }
      78  
      79  void
      80  cldr_plural_relation_free (struct cldr_plural_relation_ty *relation)
      81  {
      82    free (relation->expression);
      83    cldr_plural_range_list_free (relation->ranges);
      84    free (relation);
      85  }
      86  
      87  static void
      88  cldr_plural_rule_free (struct cldr_plural_rule_ty *rule)
      89  {
      90    free (rule->name);
      91    cldr_plural_condition_free (rule->condition);
      92    free (rule);
      93  }
      94  
      95  void
      96  cldr_plural_rule_list_free (struct cldr_plural_rule_list_ty *rules)
      97  {
      98    while (rules->nitems-- > 0)
      99      cldr_plural_rule_free (rules->items[rules->nitems]);
     100    free (rules->items);
     101    free (rules);
     102  }
     103  
     104  struct cldr_plural_rule_list_ty *
     105  cldr_plural_parse (const char *input)
     106  {
     107    struct cldr_plural_parse_args arg;
     108  
     109    memset (&arg, 0, sizeof (struct cldr_plural_parse_args));
     110    arg.cp = input;
     111    arg.cp_end = input + strlen (input);
     112    arg.result = XMALLOC (struct cldr_plural_rule_list_ty);
     113    memset (arg.result, 0, sizeof (struct cldr_plural_rule_list_ty));
     114  
     115    if (yyparse (&arg) != 0)
     116      return NULL;
     117  
     118    return arg.result;
     119  }
     120  
     121  #define OPERAND_ZERO_P(o)                               \
     122    (((o)->type == CLDR_PLURAL_OPERAND_INTEGER            \
     123      && (o)->value.ival == 0)                            \
     124     || ((o)->type == CLDR_PLURAL_OPERAND_DECIMAL         \
     125         && (o)->value.dval.d == 0))
     126  
     127  static enum cldr_plural_condition
     128  eval_relation (struct cldr_plural_relation_ty *relation)
     129  {
     130    switch (relation->expression->operand)
     131      {
     132      case 'n': case 'i':
     133        {
     134          /* Coerce decimal values in ranges into integers.  */
     135          size_t i;
     136          for (i = 0; i < relation->ranges->nitems; i++)
     137            {
     138              struct cldr_plural_range_ty *range = relation->ranges->items[i];
     139              if (range->start->type == CLDR_PLURAL_OPERAND_DECIMAL)
     140                {
     141                  int truncated = (int) range->start->value.dval.d;
     142                  range->start->type = CLDR_PLURAL_OPERAND_INTEGER;
     143                  range->start->value.ival =
     144                    (range->start->value.dval.d == truncated
     145                     ? truncated
     146                     : truncated + 1);
     147                }
     148              if (range->end->type == CLDR_PLURAL_OPERAND_DECIMAL)
     149                {
     150                  range->end->type = CLDR_PLURAL_OPERAND_INTEGER;
     151                  range->end->value.ival = (int) range->end->value.dval.d;
     152                }
     153            }
     154          relation->expression->operand = 'i';
     155        }
     156        break;
     157      case 'f': case 't':
     158      case 'v': case 'w':
     159        {
     160          /* Since plural expression in gettext only supports unsigned
     161             integer, turn relations whose operand is either 'f', 't',
     162             'v', or 'w' into a constant truth value.  */
     163          /* FIXME: check mod?  */
     164          size_t i;
     165          for (i = 0; i < relation->ranges->nitems; i++)
     166            {
     167              struct cldr_plural_range_ty *range = relation->ranges->items[i];
     168              if ((relation->type == CLDR_PLURAL_RELATION_EQUAL
     169                   && (!OPERAND_ZERO_P (range->start)
     170                       || !OPERAND_ZERO_P (range->end)))
     171                  || (relation->type == CLDR_PLURAL_RELATION_NOT_EQUAL
     172                      && (OPERAND_ZERO_P (range->start)
     173                          || OPERAND_ZERO_P (range->end))))
     174                return CLDR_PLURAL_CONDITION_FALSE;
     175            }
     176          return CLDR_PLURAL_CONDITION_TRUE;
     177        }
     178        break;
     179      }
     180    return CLDR_PLURAL_CONDITION_RELATION;
     181  }
     182  
     183  static void
     184  eval_condition (struct cldr_plural_condition_ty *condition)
     185  {
     186    if (condition->type == CLDR_PLURAL_CONDITION_AND)
     187      {
     188        eval_condition (condition->value.conditions[0]);
     189        eval_condition (condition->value.conditions[1]);
     190  
     191        if ((condition->value.conditions[0]->type
     192             == CLDR_PLURAL_CONDITION_FALSE)
     193            || (condition->value.conditions[1]->type
     194                == CLDR_PLURAL_CONDITION_FALSE))
     195          {
     196            cldr_plural_condition_free (condition->value.conditions[0]);
     197            cldr_plural_condition_free (condition->value.conditions[1]);
     198            condition->type = CLDR_PLURAL_CONDITION_FALSE;
     199          }
     200        else if ((condition->value.conditions[0]->type
     201                  == CLDR_PLURAL_CONDITION_TRUE)
     202                 && (condition->value.conditions[1]->type
     203                     == CLDR_PLURAL_CONDITION_TRUE))
     204          {
     205            cldr_plural_condition_free (condition->value.conditions[0]);
     206            cldr_plural_condition_free (condition->value.conditions[1]);
     207            condition->type = CLDR_PLURAL_CONDITION_TRUE;
     208          }
     209        else if (condition->value.conditions[0]->type
     210                 == CLDR_PLURAL_CONDITION_TRUE)
     211          {
     212            struct cldr_plural_condition_ty *original =
     213              condition->value.conditions[1];
     214            cldr_plural_condition_free (condition->value.conditions[0]);
     215            condition->type = condition->value.conditions[1]->type;
     216            condition->value = condition->value.conditions[1]->value;
     217            free (original);
     218          }
     219        else if (condition->value.conditions[1]->type
     220                 == CLDR_PLURAL_CONDITION_TRUE)
     221          {
     222            struct cldr_plural_condition_ty *original =
     223              condition->value.conditions[0];
     224            cldr_plural_condition_free (condition->value.conditions[1]);
     225            condition->type = condition->value.conditions[0]->type;
     226            condition->value = condition->value.conditions[0]->value;
     227            free (original);
     228          }
     229      }
     230    else if (condition->type == CLDR_PLURAL_CONDITION_OR)
     231      {
     232        eval_condition (condition->value.conditions[0]);
     233        eval_condition (condition->value.conditions[1]);
     234  
     235        if ((condition->value.conditions[0]->type
     236             == CLDR_PLURAL_CONDITION_TRUE)
     237            || (condition->value.conditions[1]->type
     238                == CLDR_PLURAL_CONDITION_TRUE))
     239          {
     240            cldr_plural_condition_free (condition->value.conditions[0]);
     241            cldr_plural_condition_free (condition->value.conditions[1]);
     242            condition->type = CLDR_PLURAL_CONDITION_TRUE;
     243          }
     244        else if ((condition->value.conditions[0]->type
     245                  == CLDR_PLURAL_CONDITION_FALSE)
     246                 && (condition->value.conditions[1]->type
     247                     == CLDR_PLURAL_CONDITION_FALSE))
     248          {
     249            cldr_plural_condition_free (condition->value.conditions[0]);
     250            cldr_plural_condition_free (condition->value.conditions[1]);
     251            condition->type = CLDR_PLURAL_CONDITION_FALSE;
     252          }
     253        else if (condition->value.conditions[0]->type
     254                 == CLDR_PLURAL_CONDITION_FALSE)
     255          {
     256            struct cldr_plural_condition_ty *original =
     257              condition->value.conditions[1];
     258            cldr_plural_condition_free (condition->value.conditions[0]);
     259            condition->type = condition->value.conditions[1]->type;
     260            condition->value = condition->value.conditions[1]->value;
     261            free (original);
     262          }
     263        else if (condition->value.conditions[1]->type
     264                 == CLDR_PLURAL_CONDITION_FALSE)
     265          {
     266            struct cldr_plural_condition_ty *original =
     267              condition->value.conditions[0];
     268            cldr_plural_condition_free (condition->value.conditions[1]);
     269            condition->type = condition->value.conditions[0]->type;
     270            condition->value = condition->value.conditions[0]->value;
     271            free (original);
     272          }
     273      }
     274    else
     275      {
     276        enum cldr_plural_condition value =
     277          eval_relation (condition->value.relation);
     278        if (value == CLDR_PLURAL_CONDITION_TRUE
     279            || value == CLDR_PLURAL_CONDITION_FALSE)
     280          {
     281            cldr_plural_relation_free (condition->value.relation);
     282            condition->type = value;
     283          }
     284      }
     285  }
     286  
     287  #define MAX(a,b) ((a) > (b) ? (a) : (b))
     288  
     289  static int
     290  find_largest_modulus (struct cldr_plural_condition_ty *condition)
     291  {
     292    if (condition->type == CLDR_PLURAL_CONDITION_AND
     293        || condition->type == CLDR_PLURAL_CONDITION_OR)
     294      {
     295        int modulus0 =
     296          find_largest_modulus (condition->value.conditions[0]);
     297        int modulus1 =
     298          find_largest_modulus (condition->value.conditions[1]);
     299        return MAX (modulus0, modulus1);
     300      }
     301    else if (condition->type == CLDR_PLURAL_CONDITION_RELATION)
     302      return condition->value.relation->expression->mod;
     303    else
     304      return 0;
     305  }
     306  
     307  static int
     308  find_largest_number (struct cldr_plural_condition_ty *condition)
     309  {
     310    if (condition->type == CLDR_PLURAL_CONDITION_AND
     311        || condition->type == CLDR_PLURAL_CONDITION_OR)
     312      {
     313        int number0 =
     314          find_largest_number (condition->value.conditions[0]);
     315        int number1 =
     316          find_largest_number (condition->value.conditions[1]);
     317        return MAX (number0, number1);
     318      }
     319    else if (condition->type == CLDR_PLURAL_CONDITION_RELATION)
     320      {
     321        int number = 0;
     322        size_t i;
     323        for (i = 0; i < condition->value.relation->ranges->nitems; i++)
     324          {
     325            struct cldr_plural_operand_ty *operand;
     326  
     327            operand = condition->value.relation->ranges->items[i]->end;
     328            if (operand->type == CLDR_PLURAL_OPERAND_INTEGER
     329                && operand->value.ival > number)
     330              number = operand->value.ival;
     331            else if (operand->type == CLDR_PLURAL_OPERAND_DECIMAL
     332                     && operand->value.dval.d > number)
     333              number = (int) operand->value.dval.d;
     334          }
     335        return number;
     336      }
     337    else
     338      return 0;
     339  }
     340  
     341  static bool
     342  apply_condition (struct cldr_plural_condition_ty *condition, int value)
     343  {
     344    if (condition->type == CLDR_PLURAL_CONDITION_AND)
     345      return apply_condition (condition->value.conditions[0], value)
     346             && apply_condition (condition->value.conditions[1], value);
     347    else if (condition->type == CLDR_PLURAL_CONDITION_OR)
     348      return apply_condition (condition->value.conditions[0], value)
     349             || apply_condition (condition->value.conditions[1], value);
     350    else if (condition->type == CLDR_PLURAL_CONDITION_RELATION)
     351      {
     352        struct cldr_plural_relation_ty *relation = condition->value.relation;
     353        int number = value;
     354        size_t i;
     355  
     356        if (relation->expression->mod > 0)
     357          number %= relation->expression->mod;
     358        for (i = 0; i < relation->ranges->nitems; i++)
     359          {
     360            struct cldr_plural_range_ty *range = relation->ranges->items[i];
     361            if (range->start->value.ival <= number
     362                && number <= range->end->value.ival)
     363              return relation->type == CLDR_PLURAL_RELATION_EQUAL;
     364          }
     365        return relation->type != CLDR_PLURAL_RELATION_EQUAL;
     366      }
     367    return false;
     368  }
     369  
     370  static void
     371  print_expression (struct cldr_plural_expression_ty *expression, bool space,
     372                    FILE *fp)
     373  {
     374    if (expression->mod == 0)
     375      fprintf (fp, "n");
     376    else
     377      fprintf (fp, space ? "n %% %d" : "n%%%d", expression->mod);
     378  }
     379  
     380  static void
     381  print_relation (struct cldr_plural_relation_ty *relation,
     382                  enum cldr_plural_condition parent, bool space,
     383                  FILE *fp)
     384  {
     385    if (relation->type == CLDR_PLURAL_RELATION_EQUAL)
     386      {
     387        size_t i;
     388        if (parent == CLDR_PLURAL_CONDITION_AND
     389            && relation->ranges->nitems > 1)
     390          fputc ('(', fp);
     391        for (i = 0; i < relation->ranges->nitems; i++)
     392          {
     393            struct cldr_plural_range_ty *range = relation->ranges->items[i];
     394            if (i > 0)
     395              fprintf (fp, " || ");
     396            if (range->start->value.ival == range->end->value.ival)
     397              {
     398                print_expression (relation->expression, space, fp);
     399                fprintf (fp,
     400                         (space && relation->ranges->nitems == 1
     401                          ? " == %d" : "==%d"),
     402                         range->start->value.ival);
     403              }
     404            else if (range->start->value.ival == 0)
     405              {
     406                print_expression (relation->expression, false, fp);
     407                fprintf (fp, "<=%d", range->end->value.ival);
     408              }
     409            else
     410              {
     411                if (parent == CLDR_PLURAL_CONDITION_OR
     412                    || relation->ranges->nitems > 1)
     413                  fputc ('(', fp);
     414                print_expression (relation->expression, false, fp);
     415                fprintf (fp, ">=%d", range->start->value.ival);
     416                fprintf (fp, " && ");
     417                print_expression (relation->expression, false, fp);
     418                fprintf (fp, "<=%d", range->end->value.ival);
     419                if (parent == CLDR_PLURAL_CONDITION_OR
     420                    || relation->ranges->nitems > 1)
     421                  fputc (')', fp);
     422              }
     423          }
     424        if (parent == CLDR_PLURAL_CONDITION_AND
     425            && relation->ranges->nitems > 1)
     426          fputc (')', fp);
     427      }
     428    else
     429      {
     430        size_t i;
     431        if (parent == CLDR_PLURAL_CONDITION_OR
     432            && relation->ranges->nitems > 1)
     433          fputc ('(', fp);
     434        for (i = 0; i < relation->ranges->nitems; i++)
     435          {
     436            struct cldr_plural_range_ty *range = relation->ranges->items[i];
     437            if (i > 0)
     438              fprintf (fp," && ");
     439            if (range->start->value.ival == range->end->value.ival)
     440              {
     441                print_expression (relation->expression, space, fp);
     442                fprintf (fp, space && relation->ranges->nitems == 1
     443                         ? " != %d" : "!=%d", range->start->value.ival);
     444              }
     445            else if (range->start->value.ival == 0)
     446              {
     447                print_expression (relation->expression, false, fp);
     448                fprintf (fp, ">%d", range->end->value.ival);
     449              }
     450            else
     451              {
     452                if (parent == CLDR_PLURAL_CONDITION_AND
     453                    || relation->ranges->nitems > 1)
     454                  fputc ('(', fp);
     455                print_expression (relation->expression, false, fp);
     456                fprintf (fp, "<%d", range->start->value.ival);
     457                fprintf (fp, " || ");
     458                print_expression (relation->expression, false, fp);
     459                fprintf (fp, ">%d", range->end->value.ival);
     460                if (parent == CLDR_PLURAL_CONDITION_AND
     461                    || relation->ranges->nitems > 1)
     462                  fputc (')', fp);
     463              }
     464          }
     465        if (parent == CLDR_PLURAL_CONDITION_OR
     466            && relation->ranges->nitems > 1)
     467          fputc (')', fp);
     468      }
     469  }
     470  
     471  static bool
     472  print_condition (struct cldr_plural_condition_ty *condition,
     473                   enum cldr_plural_condition parent, bool space,
     474                   FILE *fp)
     475  {
     476    if (condition->type == CLDR_PLURAL_CONDITION_AND)
     477      {
     478        if (parent == CLDR_PLURAL_CONDITION_OR)
     479          fputc ('(', fp);
     480        print_condition (condition->value.conditions[0],
     481                         CLDR_PLURAL_CONDITION_AND, false,
     482                         fp);
     483        fprintf (fp, " && ");
     484        print_condition (condition->value.conditions[1],
     485                         CLDR_PLURAL_CONDITION_AND, false,
     486                         fp);
     487        if (parent == CLDR_PLURAL_CONDITION_OR)
     488          fputc (')', fp);
     489        return true;
     490      }
     491    else if (condition->type == CLDR_PLURAL_CONDITION_OR)
     492      {
     493        if (parent == CLDR_PLURAL_CONDITION_AND)
     494          fputc ('(', fp);
     495        print_condition (condition->value.conditions[0],
     496                         CLDR_PLURAL_CONDITION_OR, false,
     497                         fp);
     498        fprintf (fp, " || ");
     499        print_condition (condition->value.conditions[1],
     500                         CLDR_PLURAL_CONDITION_OR, false,
     501                         fp);
     502        if (parent == CLDR_PLURAL_CONDITION_AND)
     503          fputc (')', fp);
     504        return true;
     505      }
     506    else if (condition->type == CLDR_PLURAL_CONDITION_RELATION)
     507      {
     508        print_relation (condition->value.relation, parent, space, fp);
     509        return true;
     510      }
     511    return false;
     512  }
     513  
     514  #define RULE_PRINTABLE_P(r)                                     \
     515    ((r)->condition->type != CLDR_PLURAL_CONDITION_TRUE           \
     516     && (r)->condition->type != CLDR_PLURAL_CONDITION_FALSE)
     517  
     518  /* Convert n == N into n != N.  */
     519  static bool
     520  print_condition_negation (struct cldr_plural_condition_ty *condition, FILE *fp)
     521  {
     522    if (condition->type == CLDR_PLURAL_CONDITION_RELATION
     523        && condition->value.relation->type == CLDR_PLURAL_RELATION_EQUAL
     524        && condition->value.relation->ranges->nitems == 1
     525        && condition->value.relation->ranges->items[0]->start
     526        == condition->value.relation->ranges->items[0]->end)
     527      {
     528        fprintf (fp, "nplurals=2; plural=(n != %d);\n",
     529                 condition->value.relation->ranges->items[0]->start->value.ival);
     530        return true;
     531      }
     532    return false;
     533  }
     534  
     535  /* Convert n == 0,...,N into n > N.  */
     536  static bool
     537  print_condition_greater (struct cldr_plural_condition_ty *condition, FILE *fp)
     538  {
     539    if (condition->type == CLDR_PLURAL_CONDITION_RELATION
     540        && condition->value.relation->type == CLDR_PLURAL_RELATION_EQUAL)
     541      {
     542        int last = -1;
     543        size_t i;
     544        for (i = 0; i < condition->value.relation->ranges->nitems; i++)
     545          {
     546            struct cldr_plural_range_ty *range =
     547              condition->value.relation->ranges->items[i];
     548            if (range->start->type != CLDR_PLURAL_OPERAND_INTEGER
     549                || range->end->type != CLDR_PLURAL_OPERAND_INTEGER
     550                || range->start->value.ival != last + 1)
     551              break;
     552            last = range->end->value.ival;
     553          }
     554        if (i == condition->value.relation->ranges->nitems)
     555          {
     556            struct cldr_plural_range_ty *range =
     557              condition->value.relation->ranges->items[i - 1];
     558            fprintf (fp, "nplurals=2; plural=(n > %d);\n",
     559                     range->end->value.ival);
     560            return true;
     561          }
     562      }
     563    return false;
     564  }
     565  
     566  typedef bool (*print_condition_function_ty) (struct cldr_plural_condition_ty *,
     567                                               FILE *);
     568  static print_condition_function_ty print_condition_functions[] =
     569    {
     570      print_condition_negation,
     571      print_condition_greater
     572    };
     573  
     574  #define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
     575  
     576  void
     577  cldr_plural_rule_list_print (struct cldr_plural_rule_list_ty *rules, FILE *fp)
     578  {
     579    size_t i;
     580    size_t count;
     581    size_t nplurals;
     582    int modulus_max = 0;
     583  
     584    /* Prune trivial conditions.  */
     585    for (i = 0; i < rules->nitems; i++)
     586      {
     587        struct cldr_plural_rule_ty *rule = rules->items[i];
     588        eval_condition (rule->condition);
     589      }
     590  
     591    /* Omit trivial rules (e.g., the last rule for "ru") with the
     592       following algorithm:
     593       1. From all rules, find the largest modulus M
     594       2. Prepare a bit vector with M elements and initialize it with zeros
     595       3. Loop over the rules, until all bits are set:
     596          For each value in the range [1, M], apply a rule, and flip the
     597          corresponding bit if it evaluates true  */
     598  
     599    /* Find the largest modulus.  */
     600    for (i = 0; i < rules->nitems; i++)
     601      {
     602        struct cldr_plural_rule_ty *rule = rules->items[i];
     603        int modulus = find_largest_modulus (rule->condition);
     604        int number = find_largest_number (rule->condition);
     605        /* If the rule contains a range whose end is larger than
     606           MODULUS, we can't use MODULUS as the upper bound.  Skip
     607           it.  */
     608        if (modulus >= number && modulus > modulus_max)
     609          modulus_max = modulus;
     610      }
     611  
     612    if (modulus_max > 0)
     613      {
     614        bool *values = XNMALLOC (modulus_max, bool);
     615  
     616        memset (values, 0, sizeof (bool) * modulus_max);
     617        for (i = 0; i < rules->nitems; i++)
     618          {
     619            struct cldr_plural_rule_ty *rule = rules->items[i];
     620            int j;
     621  
     622            for (j = 0; j < modulus_max; j++)
     623              {
     624                bool result = apply_condition (rule->condition, j + 1);
     625                if (result)
     626                  values[j] = true;
     627              }
     628  
     629            /* Check if all bits are set.  Then we can omit one more rule.  */
     630            for (j = 0; j < modulus_max; j++)
     631              if (values[j] == false)
     632                break;
     633            if (j == modulus_max)
     634              break;
     635          }
     636  
     637        free (values);
     638  
     639        while (i < rules->nitems)
     640          cldr_plural_rule_free (rules->items[--rules->nitems]);
     641      }
     642  
     643    for (i = 0, nplurals = 1; i < rules->nitems; i++)
     644      if (RULE_PRINTABLE_P (rules->items[i]))
     645        nplurals++;
     646  
     647    /* Special case when rules is empty.  */
     648    if (nplurals == 1)
     649      {
     650        fprintf (fp, "nplurals=1; plural=0;\n");
     651        return;
     652      }
     653  
     654    /* If we have only one printable rule, apply some heuristics.  */
     655    if (nplurals == 2)
     656      {
     657        struct cldr_plural_condition_ty *condition;
     658        size_t j;
     659  
     660        for (j = 0; j < rules->nitems; j++)
     661          if (RULE_PRINTABLE_P (rules->items[j]))
     662            break;
     663  
     664        condition = rules->items[j]->condition;
     665        for (j = 0; j < SIZEOF (print_condition_functions); j++)
     666          if (print_condition_functions[j] (condition, fp))
     667            return;
     668      }
     669  
     670    /* If there are more printable rules, build a ternary operator.  */
     671    fprintf (fp, "nplurals=%lu; plural=(", (unsigned long) nplurals);
     672    for (i = 0, count = 0; i < rules->nitems; i++)
     673      {
     674        struct cldr_plural_rule_ty *rule = rules->items[i];
     675        if (print_condition (rule->condition,
     676                             CLDR_PLURAL_CONDITION_FALSE,
     677                             nplurals == 2,
     678                             fp)
     679            && rules->nitems > 1)
     680          {
     681            bool printable_left = false;
     682            size_t j;
     683  
     684            for (j = i + 1; j < rules->nitems; j++)
     685              if (RULE_PRINTABLE_P (rules->items[j]))
     686                printable_left = true;
     687  
     688            if (i < rules->nitems - 1 && printable_left)
     689              fprintf (fp, " ? %lu : ", (unsigned long) count++);
     690          }
     691      }
     692    if (rules->nitems > 1)
     693      fprintf (fp, " ? %lu : %lu",
     694               (unsigned long) count, (unsigned long) (count + 1));
     695    fprintf (fp, ");\n");
     696  }