• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
split_keywordspec(const char * spec,const char ** endp,struct callshape * shapep)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
insert_keyword_callshape(hash_table * table,const char * keyword,size_t keyword_len,const struct callshape * shape)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 }
240