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