844e8f25dca1e878822266a81656c6e01e1321f2
[ira/wip.git] / lib / util / util_strlist.c
1 /* 
2    Unix SMB/CIFS implementation.
3    
4    Copyright (C) Andrew Tridgell 2005
5    Copyright (C) Jelmer Vernooij 2005
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "system/locale.h"
23
24 #undef strcasecmp
25
26 /**
27  * @file
28  * @brief String list manipulation
29  */
30
31 /**
32   build an empty (only NULL terminated) list of strings (for expansion with str_list_add() etc)
33 */
34 _PUBLIC_ char **str_list_make_empty(TALLOC_CTX *mem_ctx)
35 {
36         char **ret = NULL;
37
38         ret = talloc_array(mem_ctx, char *, 1);
39         if (ret == NULL) {
40                 return NULL;
41         }
42
43         ret[0] = NULL;
44
45         return ret;
46 }
47
48 /**
49   place the only element 'entry' into a new, NULL terminated string list
50 */
51 _PUBLIC_ char **str_list_make_single(TALLOC_CTX *mem_ctx, const char *entry)
52 {
53         char **ret = NULL;
54
55         ret = talloc_array(mem_ctx, char *, 2);
56         if (ret == NULL) {
57                 return NULL;
58         }
59
60         ret[0] = talloc_strdup(ret, entry);
61         if (!ret[0]) {
62                 talloc_free(ret);
63                 return NULL;
64         }
65         ret[1] = NULL;
66
67         return ret;
68 }
69
70 /**
71   build a null terminated list of strings from a input string and a
72   separator list. The separator list must contain characters less than
73   or equal to 0x2f for this to work correctly on multi-byte strings
74 */
75 _PUBLIC_ char **str_list_make(TALLOC_CTX *mem_ctx, const char *string, const char *sep)
76 {
77         int num_elements = 0;
78         char **ret = NULL;
79
80         if (sep == NULL) {
81                 sep = LIST_SEP;
82         }
83
84         ret = talloc_array(mem_ctx, char *, 1);
85         if (ret == NULL) {
86                 return NULL;
87         }
88
89         while (string && *string) {
90                 size_t len = strcspn(string, sep);
91                 char **ret2;
92                 
93                 if (len == 0) {
94                         string += strspn(string, sep);
95                         continue;
96                 }
97
98                 ret2 = talloc_realloc(mem_ctx, ret, char *, num_elements+2);
99                 if (ret2 == NULL) {
100                         talloc_free(ret);
101                         return NULL;
102                 }
103                 ret = ret2;
104
105                 ret[num_elements] = talloc_strndup(ret, string, len);
106                 if (ret[num_elements] == NULL) {
107                         talloc_free(ret);
108                         return NULL;
109                 }
110
111                 num_elements++;
112                 string += len;
113         }
114
115         ret[num_elements] = NULL;
116
117         return ret;
118 }
119
120 /**
121  * build a null terminated list of strings from an argv-like input string 
122  * Entries are seperated by spaces and can be enclosed by quotes. 
123  * Does NOT support escaping
124  */
125 _PUBLIC_ const char **str_list_make_shell(TALLOC_CTX *mem_ctx, const char *string, const char *sep)
126 {
127         int num_elements = 0;
128         const char **ret = NULL;
129
130         ret = talloc_array(mem_ctx, const char *, 1);
131         if (ret == NULL) {
132                 return NULL;
133         }
134
135         if (sep == NULL)
136                 sep = " \t\n\r";
137
138         while (string && *string) {
139                 size_t len = strcspn(string, sep);
140                 char *element;
141                 const char **ret2;
142                 
143                 if (len == 0) {
144                         string += strspn(string, sep);
145                         continue;
146                 }
147
148                 if (*string == '\"') {
149                         string++;
150                         len = strcspn(string, "\"");
151                         element = talloc_strndup(ret, string, len);
152                         string += len + 1;
153                 } else {
154                         element = talloc_strndup(ret, string, len);
155                         string += len;
156                 }
157
158                 if (element == NULL) {
159                         talloc_free(ret);
160                         return NULL;
161                 }
162
163                 ret2 = talloc_realloc(mem_ctx, ret, const char *, num_elements+2);
164                 if (ret2 == NULL) {
165                         talloc_free(ret);
166                         return NULL;
167                 }
168                 ret = ret2;
169
170                 ret[num_elements] = element;    
171
172                 num_elements++;
173         }
174
175         ret[num_elements] = NULL;
176
177         return ret;
178
179 }
180
181 /**
182  * join a list back to one string 
183  */
184 _PUBLIC_ char *str_list_join(TALLOC_CTX *mem_ctx, const char **list, char seperator)
185 {
186         char *ret = NULL;
187         int i;
188         
189         if (list[0] == NULL)
190                 return talloc_strdup(mem_ctx, "");
191
192         ret = talloc_strdup(mem_ctx, list[0]);
193
194         for (i = 1; list[i]; i++) {
195                 ret = talloc_asprintf_append_buffer(ret, "%c%s", seperator, list[i]);
196         }
197
198         return ret;
199 }
200
201 /** join a list back to one (shell-like) string; entries 
202  * seperated by spaces, using quotes where necessary */
203 _PUBLIC_ char *str_list_join_shell(TALLOC_CTX *mem_ctx, const char **list, char sep)
204 {
205         char *ret = NULL;
206         int i;
207         
208         if (list[0] == NULL)
209                 return talloc_strdup(mem_ctx, "");
210
211         if (strchr(list[0], ' ') || strlen(list[0]) == 0) 
212                 ret = talloc_asprintf(mem_ctx, "\"%s\"", list[0]);
213         else 
214                 ret = talloc_strdup(mem_ctx, list[0]);
215
216         for (i = 1; list[i]; i++) {
217                 if (strchr(list[i], ' ') || strlen(list[i]) == 0) 
218                         ret = talloc_asprintf_append_buffer(ret, "%c\"%s\"", sep, list[i]);
219                 else 
220                         ret = talloc_asprintf_append_buffer(ret, "%c%s", sep, list[i]);
221         }
222
223         return ret;
224 }
225
226 /**
227   return the number of elements in a string list
228 */
229 _PUBLIC_ size_t str_list_length(const char * const *list)
230 {
231         size_t ret;
232         for (ret=0;list && list[ret];ret++) /* noop */ ;
233         return ret;
234 }
235
236
237 /**
238   copy a string list
239 */
240 _PUBLIC_ char **str_list_copy(TALLOC_CTX *mem_ctx, const char **list)
241 {
242         int i;
243         char **ret;
244
245         if (list == NULL)
246                 return NULL;
247         
248         ret = talloc_array(mem_ctx, char *, str_list_length(list)+1);
249         if (ret == NULL) 
250                 return NULL;
251
252         for (i=0;list && list[i];i++) {
253                 ret[i] = talloc_strdup(ret, list[i]);
254                 if (ret[i] == NULL) {
255                         talloc_free(ret);
256                         return NULL;
257                 }
258         }
259         ret[i] = NULL;
260         return ret;
261 }
262
263 /**
264    Return true if all the elements of the list match exactly.
265  */
266 _PUBLIC_ bool str_list_equal(const char **list1, const char **list2)
267 {
268         int i;
269         
270         if (list1 == NULL || list2 == NULL) {
271                 return (list1 == list2); 
272         }
273         
274         for (i=0;list1[i] && list2[i];i++) {
275                 if (strcmp(list1[i], list2[i]) != 0) {
276                         return false;
277                 }
278         }
279         if (list1[i] || list2[i]) {
280                 return false;
281         }
282         return true;
283 }
284
285
286 /**
287   add an entry to a string list
288 */
289 _PUBLIC_ const char **str_list_add(const char **list, const char *s)
290 {
291         size_t len = str_list_length(list);
292         const char **ret;
293
294         ret = talloc_realloc(NULL, list, const char *, len+2);
295         if (ret == NULL) return NULL;
296
297         ret[len] = talloc_strdup(ret, s);
298         if (ret[len] == NULL) return NULL;
299
300         ret[len+1] = NULL;
301
302         return ret;
303 }
304
305 /**
306   remove an entry from a string list
307 */
308 _PUBLIC_ void str_list_remove(const char **list, const char *s)
309 {
310         int i;
311
312         for (i=0;list[i];i++) {
313                 if (strcmp(list[i], s) == 0) break;
314         }
315         if (!list[i]) return;
316
317         for (;list[i];i++) {
318                 list[i] = list[i+1];
319         }
320 }
321
322
323 /**
324   return true if a string is in a list
325 */
326 _PUBLIC_ bool str_list_check(const char **list, const char *s)
327 {
328         int i;
329
330         for (i=0;list[i];i++) {
331                 if (strcmp(list[i], s) == 0) return true;
332         }
333         return false;
334 }
335
336 /**
337   return true if a string is in a list, case insensitively
338 */
339 _PUBLIC_ bool str_list_check_ci(const char **list, const char *s)
340 {
341         int i;
342
343         for (i=0;list[i];i++) {
344                 if (strcasecmp(list[i], s) == 0) return true;
345         }
346         return false;
347 }
348
349
350 /**
351   append one list to another - expanding list1
352 */
353 _PUBLIC_ char **str_list_append(const char **list1, const char * const *list2)
354 {
355         size_t len1 = str_list_length(list1);
356         size_t len2 = str_list_length(list2);
357         char **ret;
358         int i;
359
360         ret = talloc_realloc(NULL, list1, char *, len1+len2+1);
361         if (ret == NULL) return NULL;
362
363         for (i=len1;i<len1+len2;i++) {
364                 ret[i] = talloc_strdup(ret, list2[i-len1]);
365                 if (ret[i] == NULL) {
366                         return NULL;
367                 }
368         }
369         ret[i] = NULL;
370
371         return ret;
372 }
373
374 static int list_cmp(const char **el1, const char **el2)
375 {
376         return strcmp(*el1, *el2);
377 }
378
379 /*
380   return a list that only contains the unique elements of a list,
381   removing any duplicates
382  */
383 _PUBLIC_ const char **str_list_unique(const char **list)
384 {
385         size_t len = str_list_length(list);
386         const char **list2;
387         int i, j;
388         if (len < 2) {
389                 return list;
390         }
391         list2 = (const char **)talloc_memdup(list, list,
392                                              sizeof(list[0])*(len+1));
393         qsort(list2, len, sizeof(list2[0]), QSORT_CAST list_cmp);
394         list[0] = list2[0];
395         for (i=j=1;i<len;i++) {
396                 if (strcmp(list2[i], list[j-1]) != 0) {
397                         list[j] = list2[i];
398                         j++;
399                 }
400         }
401         list[j] = NULL;
402         list = talloc_realloc(NULL, list, const char *, j);
403         talloc_free(list2);
404         return list;
405 }
406
407 /*
408   very useful when debugging complex list related code
409  */
410 _PUBLIC_ void str_list_show(const char **list)
411 {
412         int i;
413         DEBUG(0,("{ "));
414         for (i=0;list && list[i];i++) {
415                 DEBUG(0,("\"%s\", ", list[i]));
416         }
417         DEBUG(0,("}\n"));
418 }
419
420
421
422 /**
423   append one list to another - expanding list1
424   this assumes the elements of list2 are const pointers, so we can re-use them
425 */
426 _PUBLIC_ const char **str_list_append_const(const char **list1,
427                                             const char **list2)
428 {
429         size_t len1 = str_list_length(list1);
430         size_t len2 = str_list_length(list2);
431         const char **ret;
432         int i;
433
434         ret = talloc_realloc(NULL, list1, const char *, len1+len2+1);
435         if (ret == NULL) return NULL;
436
437         for (i=len1;i<len1+len2;i++) {
438                 ret[i] = list2[i-len1];
439         }
440         ret[i] = NULL;
441
442         return ret;
443 }
444
445 /**
446   add an entry to a string list
447   this assumes s will not change
448 */
449 _PUBLIC_ const char **str_list_add_const(const char **list, const char *s)
450 {
451         size_t len = str_list_length(list);
452         const char **ret;
453
454         ret = talloc_realloc(NULL, list, const char *, len+2);
455         if (ret == NULL) return NULL;
456
457         ret[len] = s;
458         ret[len+1] = NULL;
459
460         return ret;
461 }
462
463 /**
464   copy a string list
465   this assumes list will not change
466 */
467 _PUBLIC_ const char **str_list_copy_const(TALLOC_CTX *mem_ctx,
468                                           const char **list)
469 {
470         int i;
471         const char **ret;
472
473         if (list == NULL)
474                 return NULL;
475         
476         ret = talloc_array(mem_ctx, const char *, str_list_length(list)+1);
477         if (ret == NULL) 
478                 return NULL;
479
480         for (i=0;list && list[i];i++) {
481                 ret[i] = list[i];
482         }
483         ret[i] = NULL;
484         return ret;
485 }