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