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