(root)/
gettext-0.22.4/
gettext-tools/
src/
xg-arglist-callshape.c
       1  /* Resolving ambiguity of argument lists: Information given through
       2     command-line options.
       3     Copyright (C) 2001-2018 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-callshape.h"
      24  
      25  #include <ctype.h>
      26  #include <stdlib.h>
      27  #include <string.h>
      28  
      29  #include "xalloc.h"
      30  #include "xsize.h"
      31  
      32  
      33  void
      34  split_keywordspec (const char *spec,
      35                     const char **endp, struct callshape *shapep)
      36  {
      37    const char *p;
      38    int argnum1 = 0;
      39    int argnum2 = 0;
      40    int argnumc = 0;
      41    bool argnum1_glib_context = false;
      42    bool argnum2_glib_context = false;
      43    int argtotal = 0;
      44    string_list_ty xcomments;
      45  
      46    string_list_init (&xcomments);
      47  
      48    /* Start parsing from the end.  */
      49    p = spec + strlen (spec);
      50    while (p > spec)
      51      {
      52        if (isdigit ((unsigned char) p[-1])
      53            || ((p[-1] == 'c' || p[-1] == 'g' || p[-1] == 't')
      54                && p - 1 > spec && isdigit ((unsigned char) p[-2])))
      55          {
      56            bool contextp = (p[-1] == 'c');
      57            bool glibp = (p[-1] == 'g');
      58            bool totalp = (p[-1] == 't');
      59  
      60            do
      61              p--;
      62            while (p > spec && isdigit ((unsigned char) p[-1]));
      63  
      64            if (p > spec && (p[-1] == ',' || p[-1] == ':'))
      65              {
      66                char *dummy;
      67                int arg = strtol (p, &dummy, 10);
      68  
      69                if (contextp)
      70                  {
      71                    if (argnumc != 0)
      72                      /* Only one context argument can be given.  */
      73                      break;
      74                    argnumc = arg;
      75                  }
      76                else if (totalp)
      77                  {
      78                    if (argtotal != 0)
      79                      /* Only one total number of arguments can be given.  */
      80                      break;
      81                    argtotal = arg;
      82                  }
      83                else
      84                  {
      85                    if (argnum2 != 0)
      86                      /* At most two normal arguments can be given.  */
      87                      break;
      88                    argnum2 = argnum1;
      89                    argnum2_glib_context = argnum1_glib_context;
      90                    argnum1 = arg;
      91                    argnum1_glib_context = glibp;
      92                  }
      93              }
      94            else
      95              break;
      96          }
      97        else if (p[-1] == '"')
      98          {
      99            const char *xcomment_end;
     100  
     101            p--;
     102            xcomment_end = p;
     103  
     104            while (p > spec && p[-1] != '"')
     105              p--;
     106  
     107            if (p > spec /* && p[-1] == '"' */)
     108              {
     109                const char *xcomment_start;
     110  
     111                xcomment_start = p;
     112                p--;
     113                if (p > spec && (p[-1] == ',' || p[-1] == ':'))
     114                  {
     115                    size_t xcomment_len = xcomment_end - xcomment_start;
     116                    char *xcomment = XNMALLOC (xcomment_len + 1, char);
     117  
     118                    memcpy (xcomment, xcomment_start, xcomment_len);
     119                    xcomment[xcomment_len] = '\0';
     120                    string_list_append (&xcomments, xcomment);
     121                  }
     122                else
     123                  break;
     124              }
     125            else
     126              break;
     127          }
     128        else
     129          break;
     130  
     131        /* Here an element of the comma-separated list has been parsed.  */
     132        if (!(p > spec && (p[-1] == ',' || p[-1] == ':')))
     133          abort ();
     134        p--;
     135        if (*p == ':')
     136          {
     137            size_t i;
     138  
     139            if (argnum1 == 0 && argnum2 == 0)
     140              /* At least one non-context argument must be given.  */
     141              break;
     142            if (argnumc != 0
     143                && (argnum1_glib_context || argnum2_glib_context))
     144              /* Incompatible ways to specify the context.  */
     145              break;
     146            *endp = p;
     147            shapep->argnum1 = (argnum1 > 0 ? argnum1 : 1);
     148            shapep->argnum2 = argnum2;
     149            shapep->argnumc = argnumc;
     150            shapep->argnum1_glib_context = argnum1_glib_context;
     151            shapep->argnum2_glib_context = argnum2_glib_context;
     152            shapep->argtotal = argtotal;
     153            /* Reverse the order of the xcomments.  */
     154            string_list_init (&shapep->xcomments);
     155            for (i = xcomments.nitems; i > 0; )
     156              string_list_append (&shapep->xcomments, xcomments.item[--i]);
     157            string_list_destroy (&xcomments);
     158            return;
     159          }
     160      }
     161  
     162    /* Couldn't parse the desired syntax.  */
     163    *endp = spec + strlen (spec);
     164    shapep->argnum1 = 1;
     165    shapep->argnum2 = 0;
     166    shapep->argnumc = 0;
     167    shapep->argnum1_glib_context = false;
     168    shapep->argnum2_glib_context = false;
     169    shapep->argtotal = 0;
     170    string_list_init (&shapep->xcomments);
     171    string_list_destroy (&xcomments);
     172  }
     173  
     174  
     175  void
     176  insert_keyword_callshape (hash_table *table,
     177                            const char *keyword, size_t keyword_len,
     178                            const struct callshape *shape)
     179  {
     180    void *old_value;
     181  
     182    if (hash_find_entry (table, keyword, keyword_len, &old_value))
     183      {
     184        /* Create a one-element 'struct callshapes'.  */
     185        struct callshapes *shapes = XMALLOC (struct callshapes);
     186        shapes->nshapes = 1;
     187        shapes->shapes[0] = *shape;
     188        keyword =
     189          (const char *) hash_insert_entry (table, keyword, keyword_len, shapes);
     190        if (keyword == NULL)
     191          abort ();
     192        shapes->keyword = keyword;
     193        shapes->keyword_len = keyword_len;
     194      }
     195    else
     196      {
     197        /* Found a 'struct callshapes'.  See whether it already contains the
     198           desired shape.  */
     199        struct callshapes *old_shapes = (struct callshapes *) old_value;
     200        bool found;
     201        size_t i;
     202  
     203        found = false;
     204        for (i = 0; i < old_shapes->nshapes; i++)
     205          if (old_shapes->shapes[i].argnum1 == shape->argnum1
     206              && old_shapes->shapes[i].argnum2 == shape->argnum2
     207              && old_shapes->shapes[i].argnumc == shape->argnumc
     208              && old_shapes->shapes[i].argnum1_glib_context
     209                 == shape->argnum1_glib_context
     210              && old_shapes->shapes[i].argnum2_glib_context
     211                 == shape->argnum2_glib_context
     212              && old_shapes->shapes[i].argtotal == shape->argtotal)
     213            {
     214              old_shapes->shapes[i].xcomments = shape->xcomments;
     215              found = true;
     216              break;
     217            }
     218  
     219        if (!found)
     220          {
     221            /* Replace the existing 'struct callshapes' with a new one.  */
     222            struct callshapes *shapes =
     223              (struct callshapes *)
     224              xmalloc (xsum (sizeof (struct callshapes),
     225                             xtimes (old_shapes->nshapes,
     226                                     sizeof (struct callshape))));
     227  
     228            shapes->keyword = old_shapes->keyword;
     229            shapes->keyword_len = old_shapes->keyword_len;
     230            shapes->nshapes = old_shapes->nshapes + 1;
     231            for (i = 0; i < old_shapes->nshapes; i++)
     232              shapes->shapes[i] = old_shapes->shapes[i];
     233            shapes->shapes[i] = *shape;
     234            if (hash_set_value (table, keyword, keyword_len, shapes))
     235              abort ();
     236            free (old_shapes);
     237          }
     238      }
     239  }