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 }