1 /***********************************************************************************************************************************
2 String List Handler
3 ***********************************************************************************************************************************/
4 #include "build.auto.h"
5
6 #include <stdarg.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10
11 #include "common/debug.h"
12 #include "common/memContext.h"
13 #include "common/type/stringList.h"
14
15 /***********************************************************************************************************************************
16 Internal add -- the string must have been created in the list's mem context before being passed
17 ***********************************************************************************************************************************/
18 __attribute__((always_inline)) static inline String *
strLstAddInternal(StringList * const this,String * const string)19 strLstAddInternal(StringList *const this, String *const string)
20 {
21 return *(String **)lstAdd((List *)this, &string);
22 }
23
24 /***********************************************************************************************************************************
25 Internal insert -- the string must have been created in the list's mem context before being passed
26 ***********************************************************************************************************************************/
27 __attribute__((always_inline)) static inline String *
strLstInsertInternal(StringList * const this,const unsigned int listIdx,String * const string)28 strLstInsertInternal(StringList *const this, const unsigned int listIdx, String *const string)
29 {
30 return *(String **)lstInsert((List *)this, listIdx, &string);
31 }
32
33 /**********************************************************************************************************************************/
34 StringList *
strLstNewSplitZ(const String * string,const char * delimiter)35 strLstNewSplitZ(const String *string, const char *delimiter)
36 {
37 FUNCTION_TEST_BEGIN();
38 FUNCTION_TEST_PARAM(STRING, string);
39 FUNCTION_TEST_PARAM(STRINGZ, delimiter);
40 FUNCTION_TEST_END();
41
42 ASSERT(string != NULL);
43 ASSERT(delimiter != NULL);
44
45 // Create the list
46 StringList *this = strLstNew();
47
48 // Base points to the beginning of the string that is being searched
49 const char *stringBase = strZ(string);
50
51 // Match points to the next delimiter match that has been found
52 const char *stringMatch = NULL;
53
54 MEM_CONTEXT_BEGIN(lstMemContext((List *)this))
55 {
56 do
57 {
58 // Find a delimiter match
59 stringMatch = strstr(stringBase, delimiter);
60
61 // If a match was found then add the string
62 if (stringMatch != NULL)
63 {
64 strLstAddInternal(this, strNewN(stringBase, (size_t)(stringMatch - stringBase)));
65 stringBase = stringMatch + strlen(delimiter);
66 }
67 // Else make whatever is left the last string
68 else
69 strLstAddInternal(this, strNewZ(stringBase));
70 }
71 while (stringMatch != NULL);
72 }
73 MEM_CONTEXT_END();
74
75 FUNCTION_TEST_RETURN(this);
76 }
77
78 /**********************************************************************************************************************************/
79 StringList *
strLstNewVarLst(const VariantList * sourceList)80 strLstNewVarLst(const VariantList *sourceList)
81 {
82 FUNCTION_TEST_BEGIN();
83 FUNCTION_TEST_PARAM(VARIANT_LIST, sourceList);
84 FUNCTION_TEST_END();
85
86 // Create the list
87 StringList *this = NULL;
88
89 if (sourceList != NULL)
90 {
91 this = strLstNew();
92
93 // Copy variants
94 MEM_CONTEXT_BEGIN(lstMemContext((List *)this))
95 {
96 for (unsigned int listIdx = 0; listIdx < varLstSize(sourceList); listIdx++)
97 strLstAddInternal(this, strDup(varStr(varLstGet(sourceList, listIdx))));
98 }
99 MEM_CONTEXT_END();
100 }
101
102 FUNCTION_TEST_RETURN(this);
103 }
104
105 /**********************************************************************************************************************************/
106 StringList *
strLstDup(const StringList * sourceList)107 strLstDup(const StringList *sourceList)
108 {
109 FUNCTION_TEST_BEGIN();
110 FUNCTION_TEST_PARAM(STRING_LIST, sourceList);
111 FUNCTION_TEST_END();
112
113 StringList *this = NULL;
114
115 if (sourceList != NULL)
116 {
117 // Create the list
118 this = strLstNew();
119
120 // Copy strings
121 MEM_CONTEXT_BEGIN(lstMemContext((List *)this))
122 {
123 for (unsigned int listIdx = 0; listIdx < strLstSize(sourceList); listIdx++)
124 strLstAddInternal(this, strDup(strLstGet(sourceList, listIdx)));
125 }
126 MEM_CONTEXT_END();
127 }
128
129 FUNCTION_TEST_RETURN(this);
130 }
131
132 /**********************************************************************************************************************************/
133 String *
strLstAdd(StringList * this,const String * string)134 strLstAdd(StringList *this, const String *string)
135 {
136 FUNCTION_TEST_BEGIN();
137 FUNCTION_TEST_PARAM(STRING_LIST, this);
138 FUNCTION_TEST_PARAM(STRING, string);
139 FUNCTION_TEST_END();
140
141 ASSERT(this != NULL);
142
143 String *result = NULL;
144
145 MEM_CONTEXT_BEGIN(lstMemContext((List *)this))
146 {
147 result = strLstAddInternal(this, strDup(string));
148 }
149 MEM_CONTEXT_END();
150
151 FUNCTION_TEST_RETURN(result);
152 }
153
154 String *
strLstAddIfMissing(StringList * this,const String * string)155 strLstAddIfMissing(StringList *this, const String *string)
156 {
157 FUNCTION_TEST_BEGIN();
158 FUNCTION_TEST_PARAM(STRING_LIST, this);
159 FUNCTION_TEST_PARAM(STRING, string);
160 FUNCTION_TEST_END();
161
162 ASSERT(this != NULL);
163
164 String **result = lstFind((List *)this, &string);
165
166 if (result == NULL)
167 FUNCTION_TEST_RETURN(strLstAdd(this, string));
168
169 FUNCTION_TEST_RETURN(*result);
170 }
171
172 String *
strLstAddZ(StringList * this,const char * string)173 strLstAddZ(StringList *this, const char *string)
174 {
175 FUNCTION_TEST_BEGIN();
176 FUNCTION_TEST_PARAM(STRING_LIST, this);
177 FUNCTION_TEST_PARAM(STRINGZ, string);
178 FUNCTION_TEST_END();
179
180 ASSERT(this != NULL);
181
182 String *result = NULL;
183
184 MEM_CONTEXT_BEGIN(lstMemContext((List *)this))
185 {
186 result = strLstAddInternal(this, strNewZ(string));
187 }
188 MEM_CONTEXT_END();
189
190 FUNCTION_TEST_RETURN(result);
191 }
192
193 /**********************************************************************************************************************************/
194 String *
strLstInsert(StringList * this,unsigned int listIdx,const String * string)195 strLstInsert(StringList *this, unsigned int listIdx, const String *string)
196 {
197 FUNCTION_TEST_BEGIN();
198 FUNCTION_TEST_PARAM(STRING_LIST, this);
199 FUNCTION_TEST_PARAM(UINT, listIdx);
200 FUNCTION_TEST_PARAM(STRING, string);
201 FUNCTION_TEST_END();
202
203 ASSERT(this != NULL);
204
205 String *result = NULL;
206
207 MEM_CONTEXT_BEGIN(lstMemContext((List *)this))
208 {
209 result = strLstInsertInternal(this, listIdx, strDup(string));
210 }
211 MEM_CONTEXT_END();
212
213 FUNCTION_TEST_RETURN(result);
214 }
215
216 /**********************************************************************************************************************************/
217 String *
strLstJoinQuote(const StringList * this,const char * separator,const char * quote)218 strLstJoinQuote(const StringList *this, const char *separator, const char *quote)
219 {
220 FUNCTION_TEST_BEGIN();
221 FUNCTION_TEST_PARAM(STRING_LIST, this);
222 FUNCTION_TEST_PARAM(STRINGZ, separator);
223 FUNCTION_TEST_PARAM(STRINGZ, quote);
224 FUNCTION_TEST_END();
225
226 ASSERT(this != NULL);
227 ASSERT(separator != NULL);
228 ASSERT(quote != NULL);
229
230 String *join = strNew();
231
232 for (unsigned int listIdx = 0; listIdx < strLstSize(this); listIdx++)
233 {
234 if (listIdx != 0)
235 strCatZ(join, separator);
236
237 if (strLstGet(this, listIdx) == NULL)
238 strCatZ(join, "[NULL]");
239 else
240 strCatFmt(join, "%s%s%s", quote, strZ(strLstGet(this, listIdx)), quote);
241 }
242
243 FUNCTION_TEST_RETURN(join);
244 }
245
246 /**********************************************************************************************************************************/
247 StringList *
strLstMergeAnti(const StringList * this,const StringList * anti)248 strLstMergeAnti(const StringList *this, const StringList *anti)
249 {
250 FUNCTION_TEST_BEGIN();
251 FUNCTION_TEST_PARAM(STRING_LIST, this);
252 FUNCTION_TEST_PARAM(STRING_LIST, anti);
253 FUNCTION_TEST_END();
254
255 ASSERT(this != NULL);
256 ASSERT(anti != NULL);
257
258 StringList *result = NULL;
259
260 MEM_CONTEXT_TEMP_BEGIN()
261 {
262 result = strLstNew();
263 unsigned int antiIdx = 0;
264
265 // Check every item in this
266 for (unsigned int thisIdx = 0; thisIdx < strLstSize(this); thisIdx++)
267 {
268 bool add = true;
269 const String *listItem = strLstGet(this, thisIdx);
270 ASSERT(listItem != NULL);
271
272 // If anything left in anti look for matches
273 while (antiIdx < strLstSize(anti))
274 {
275 ASSERT(strLstGet(anti, antiIdx) != NULL);
276 int compare = strCmp(listItem, strLstGet(anti, antiIdx));
277
278 // If the current item in this is less than the current item in anti then it will be added
279 if (compare < 0)
280 {
281 break;
282 }
283 // If they are equal it will not be added
284 else if (compare == 0)
285 {
286 add = false;
287 antiIdx++;
288 break;
289 }
290 // Otherwise keep searching anti for a match
291 else
292 antiIdx++;
293 }
294
295 // Add to the result list if no match found
296 if (add)
297 strLstAdd(result, listItem);
298 }
299
300 strLstMove(result, memContextPrior());
301 }
302 MEM_CONTEXT_TEMP_END();
303
304 FUNCTION_TEST_RETURN(result);
305 }
306
307 /**********************************************************************************************************************************/
308 const char **
strLstPtr(const StringList * this)309 strLstPtr(const StringList *this)
310 {
311 FUNCTION_TEST_BEGIN();
312 FUNCTION_TEST_PARAM(STRING_LIST, this);
313 FUNCTION_TEST_END();
314
315 ASSERT(this != NULL);
316
317 const char **list = memNew((strLstSize(this) + 1) * sizeof(char *));
318
319 for (unsigned int listIdx = 0; listIdx < strLstSize(this); listIdx++)
320 {
321 if (strLstGet(this, listIdx) == NULL)
322 list[listIdx] = NULL;
323 else
324 list[listIdx] = strZ(strLstGet(this, listIdx));
325 }
326
327 list[strLstSize(this)] = NULL;
328
329 FUNCTION_TEST_RETURN(list);
330 }
331
332 /**********************************************************************************************************************************/
333 String *
strLstToLog(const StringList * this)334 strLstToLog(const StringList *this)
335 {
336 return strNewFmt("{[%s]}", strZ(strLstJoinQuote(this, ", ", "\"")));
337 }
338