(root)/
gettext-0.22.4/
gettext-tools/
src/
xg-arglist-context.c
       1  /* Keeping track of the flags that apply to a string extracted
       2     in a certain context.
       3     Copyright (C) 2001-2018, 2023 Free Software Foundation, Inc.
       4  
       5     This program is free software: you can redistribute it and/or modify
       6     it under the terms of the GNU General Public License as published by
       7     the Free Software Foundation; either version 3 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 General Public License for more details.
      14  
      15     You should have received a copy of the GNU 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  /* Specification.  */
      23  #include "xg-arglist-context.h"
      24  
      25  #include <stdlib.h>
      26  
      27  #include "xalloc.h"
      28  #include "xmalloca.h"
      29  #include "verify.h"
      30  
      31  
      32  /* Null context.  */
      33  flag_context_ty null_context =
      34    {
      35      undecided, false,
      36      undecided, false,
      37      undecided, false,
      38      undecided, false
      39    };
      40  
      41  /* Transparent context.  */
      42  flag_context_ty passthrough_context =
      43    {
      44      undecided, true,
      45      undecided, true,
      46      undecided, true,
      47      undecided, true
      48    };
      49  
      50  
      51  flag_context_ty
      52  inherited_context (flag_context_ty outer_context,
      53                     flag_context_ty modifier_context)
      54  {
      55    flag_context_ty result = modifier_context;
      56  
      57    if (result.pass_format1)
      58      {
      59        result.is_format1 = outer_context.is_format1;
      60        result.pass_format1 = false;
      61      }
      62    if (result.pass_format2)
      63      {
      64        result.is_format2 = outer_context.is_format2;
      65        result.pass_format2 = false;
      66      }
      67    if (result.pass_format3)
      68      {
      69        result.is_format3 = outer_context.is_format3;
      70        result.pass_format3 = false;
      71      }
      72    if (result.pass_format4)
      73      {
      74        result.is_format4 = outer_context.is_format4;
      75        result.pass_format4 = false;
      76      }
      77    return result;
      78  }
      79  
      80  
      81  /* Null context list iterator.  */
      82  flag_context_list_iterator_ty null_context_list_iterator = { 1, NULL };
      83  
      84  /* Transparent context list iterator.  */
      85  static flag_context_list_ty passthrough_context_circular_list =
      86    {
      87      1,
      88      { undecided, true, undecided, true, undecided, true, undecided, true },
      89      &passthrough_context_circular_list
      90    };
      91  flag_context_list_iterator_ty passthrough_context_list_iterator =
      92    {
      93      1,
      94      &passthrough_context_circular_list
      95    };
      96  
      97  
      98  flag_context_list_iterator_ty
      99  flag_context_list_iterator (flag_context_list_ty *list)
     100  {
     101    flag_context_list_iterator_ty result;
     102  
     103    result.argnum = 1;
     104    result.head = list;
     105    return result;
     106  }
     107  
     108  
     109  flag_context_ty
     110  flag_context_list_iterator_advance (flag_context_list_iterator_ty *iter)
     111  {
     112    if (iter->head == NULL)
     113      return null_context;
     114    if (iter->argnum == iter->head->argnum)
     115      {
     116        flag_context_ty result = iter->head->flags;
     117  
     118        /* Special casing of circular list.  */
     119        if (iter->head != iter->head->next)
     120          {
     121            iter->head = iter->head->next;
     122            iter->argnum++;
     123          }
     124  
     125        return result;
     126      }
     127    else
     128      {
     129        iter->argnum++;
     130        return null_context;
     131      }
     132  }
     133  
     134  
     135  flag_context_list_ty *
     136  flag_context_list_table_lookup (flag_context_list_table_ty *flag_table,
     137                                  const void *key, size_t keylen)
     138  {
     139    void *entry;
     140  
     141    if (flag_table->table != NULL
     142        && hash_find_entry (flag_table, key, keylen, &entry) == 0)
     143      return (flag_context_list_ty *) entry;
     144    else
     145      return NULL;
     146  }
     147  
     148  
     149  /* In the FLAGS, set the pair (is_formatX, pass_formatX) with X = INDEX+1
     150     to (VALUE, PASS).  */
     151  static void
     152  set_flags_for_formatstring_type (flag_context_ty *flags, unsigned int index,
     153                                   enum is_format value, bool pass)
     154  {
     155    switch (index)
     156      {
     157      case 0:
     158        flags->is_format1 = value;
     159        flags->pass_format1 = pass;
     160        break;
     161      case 1:
     162        flags->is_format2 = value;
     163        flags->pass_format2 = pass;
     164        break;
     165      case 2:
     166        flags->is_format3 = value;
     167        flags->pass_format3 = pass;
     168        break;
     169      case 3:
     170        flags->is_format4 = value;
     171        flags->pass_format4 = pass;
     172        break;
     173      default:
     174        abort ();
     175      }
     176  }
     177  
     178  
     179  void
     180  flag_context_list_table_add (flag_context_list_table_ty *table,
     181                               unsigned int index,
     182                               const char *name_start, const char *name_end,
     183                               int argnum, enum is_format value, bool pass)
     184  {
     185    if (table->table == NULL)
     186      hash_init (table, 100);
     187    {
     188      void *entry;
     189  
     190      if (hash_find_entry (table, name_start, name_end - name_start, &entry) != 0)
     191        {
     192          /* Create new hash table entry.  */
     193          flag_context_list_ty *list = XMALLOC (flag_context_list_ty);
     194          list->argnum = argnum;
     195          memset (&list->flags, '\0', sizeof (list->flags));
     196          set_flags_for_formatstring_type (&list->flags, index, value, pass);
     197          list->next = NULL;
     198          hash_insert_entry (table, name_start, name_end - name_start, list);
     199        }
     200      else
     201        {
     202          /* We don't put NULL entries into the table.  */
     203          assume (entry != NULL);
     204  
     205          flag_context_list_ty *list = (flag_context_list_ty *)entry;
     206          flag_context_list_ty **lastp = NULL;
     207          /* Invariant: list == (lastp != NULL ? *lastp : entry).  */
     208  
     209          while (list != NULL && list->argnum < argnum)
     210            {
     211              lastp = &list->next;
     212              list = *lastp;
     213            }
     214          if (list != NULL && list->argnum == argnum)
     215            {
     216              /* Add this flag to the current argument number.  */
     217              set_flags_for_formatstring_type (&list->flags, index, value, pass);
     218            }
     219          else if (lastp != NULL)
     220            {
     221              /* Add a new list entry for this argument number.  */
     222              list = XMALLOC (flag_context_list_ty);
     223              list->argnum = argnum;
     224              memset (&list->flags, '\0', sizeof (list->flags));
     225              set_flags_for_formatstring_type (&list->flags, index, value, pass);
     226              list->next = *lastp;
     227              *lastp = list;
     228            }
     229          else
     230            {
     231              /* Add a new list entry for this argument number, at the beginning
     232                 of the list.  Since we don't have an API for replacing the
     233                 value of a key in the hash table, we have to copy the first
     234                 list element.  */
     235              flag_context_list_ty *copy = XMALLOC (flag_context_list_ty);
     236              *copy = *list;
     237  
     238              list->argnum = argnum;
     239              memset (&list->flags, '\0', sizeof (list->flags));
     240              set_flags_for_formatstring_type (&list->flags, index, value, pass);
     241              list->next = copy;
     242            }
     243        }
     244    }
     245  }