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