util/util_strlist - add a call "const_str_list" for making "unconst" lists "const"
[sfrench/samba-autobuild/.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 *,
99                         num_elements+2);
100                 if (ret2 == NULL) {
101                         talloc_free(ret);
102                         return NULL;
103                 }
104                 ret = ret2;
105
106                 ret[num_elements] = talloc_strndup(ret, string, len);
107                 if (ret[num_elements] == NULL) {
108                         talloc_free(ret);
109                         return NULL;
110                 }
111
112                 num_elements++;
113                 string += len;
114         }
115
116         ret[num_elements] = NULL;
117
118         return ret;
119 }
120
121 /**
122  * build a null terminated list of strings from an argv-like input string 
123  * Entries are seperated by spaces and can be enclosed by quotes. 
124  * Does NOT support escaping
125  */
126 _PUBLIC_ char **str_list_make_shell(TALLOC_CTX *mem_ctx, const char *string, const char *sep)
127 {
128         int num_elements = 0;
129         char **ret = NULL;
130
131         ret = talloc_array(mem_ctx, char *, 1);
132         if (ret == NULL) {
133                 return NULL;
134         }
135
136         if (sep == NULL)
137                 sep = " \t\n\r";
138
139         while (string && *string) {
140                 size_t len = strcspn(string, sep);
141                 char *element;
142                 char **ret2;
143                 
144                 if (len == 0) {
145                         string += strspn(string, sep);
146                         continue;
147                 }
148
149                 if (*string == '\"') {
150                         string++;
151                         len = strcspn(string, "\"");
152                         element = talloc_strndup(ret, string, len);
153                         string += len + 1;
154                 } else {
155                         element = talloc_strndup(ret, string, len);
156                         string += len;
157                 }
158
159                 if (element == NULL) {
160                         talloc_free(ret);
161                         return NULL;
162                 }
163
164                 ret2 = talloc_realloc(mem_ctx, ret, char *, num_elements+2);
165                 if (ret2 == NULL) {
166                         talloc_free(ret);
167                         return NULL;
168                 }
169                 ret = ret2;
170
171                 ret[num_elements] = element;    
172
173                 num_elements++;
174         }
175
176         ret[num_elements] = NULL;
177
178         return ret;
179
180 }
181
182 /**
183  * join a list back to one string 
184  */
185 _PUBLIC_ char *str_list_join(TALLOC_CTX *mem_ctx, const char **list, char seperator)
186 {
187         char *ret = NULL;
188         int i;
189         
190         if (list[0] == NULL)
191                 return talloc_strdup(mem_ctx, "");
192
193         ret = talloc_strdup(mem_ctx, list[0]);
194
195         for (i = 1; list[i]; i++) {
196                 ret = talloc_asprintf_append_buffer(ret, "%c%s", seperator, list[i]);
197         }
198
199         return ret;
200 }
201
202 /** join a list back to one (shell-like) string; entries 
203  * seperated by spaces, using quotes where necessary */
204 _PUBLIC_ char *str_list_join_shell(TALLOC_CTX *mem_ctx, const char **list, char sep)
205 {
206         char *ret = NULL;
207         int i;
208         
209         if (list[0] == NULL)
210                 return talloc_strdup(mem_ctx, "");
211
212         if (strchr(list[0], ' ') || strlen(list[0]) == 0) 
213                 ret = talloc_asprintf(mem_ctx, "\"%s\"", list[0]);
214         else 
215                 ret = talloc_strdup(mem_ctx, list[0]);
216
217         for (i = 1; list[i]; i++) {
218                 if (strchr(list[i], ' ') || strlen(list[i]) == 0) 
219                         ret = talloc_asprintf_append_buffer(ret, "%c\"%s\"", sep, list[i]);
220                 else 
221                         ret = talloc_asprintf_append_buffer(ret, "%c%s", sep, list[i]);
222         }
223
224         return ret;
225 }
226
227 /**
228   return the number of elements in a string list
229 */
230 _PUBLIC_ size_t str_list_length(const char * const *list)
231 {
232         size_t ret;
233         for (ret=0;list && list[ret];ret++) /* noop */ ;
234         return ret;
235 }
236
237
238 /**
239   copy a string list
240 */
241 _PUBLIC_ char **str_list_copy(TALLOC_CTX *mem_ctx, const char **list)
242 {
243         int i;
244         char **ret;
245
246         if (list == NULL)
247                 return NULL;
248         
249         ret = talloc_array(mem_ctx, char *, str_list_length(list)+1);
250         if (ret == NULL) 
251                 return NULL;
252
253         for (i=0;list && list[i];i++) {
254                 ret[i] = talloc_strdup(ret, list[i]);
255                 if (ret[i] == NULL) {
256                         talloc_free(ret);
257                         return NULL;
258                 }
259         }
260         ret[i] = NULL;
261         return ret;
262 }
263
264 /**
265    Return true if all the elements of the list match exactly.
266  */
267 _PUBLIC_ bool str_list_equal(const char * const *list1,
268                              const char * const *list2)
269 {
270         int i;
271         
272         if (list1 == NULL || list2 == NULL) {
273                 return (list1 == list2); 
274         }
275         
276         for (i=0;list1[i] && list2[i];i++) {
277                 if (strcmp(list1[i], list2[i]) != 0) {
278                         return false;
279                 }
280         }
281         if (list1[i] || list2[i]) {
282                 return false;
283         }
284         return true;
285 }
286
287
288 /**
289   add an entry to a string list
290 */
291 _PUBLIC_ const char **str_list_add(const char **list, const char *s)
292 {
293         size_t len = str_list_length(list);
294         const char **ret;
295
296         ret = talloc_realloc(NULL, list, const char *, len+2);
297         if (ret == NULL) return NULL;
298
299         ret[len] = talloc_strdup(ret, s);
300         if (ret[len] == NULL) return NULL;
301
302         ret[len+1] = NULL;
303
304         return ret;
305 }
306
307 /**
308   remove an entry from a string list
309 */
310 _PUBLIC_ void str_list_remove(const char **list, const char *s)
311 {
312         int i;
313
314         for (i=0;list[i];i++) {
315                 if (strcmp(list[i], s) == 0) break;
316         }
317         if (!list[i]) return;
318
319         for (;list[i];i++) {
320                 list[i] = list[i+1];
321         }
322 }
323
324
325 /**
326   return true if a string is in a list
327 */
328 _PUBLIC_ bool str_list_check(const char **list, const char *s)
329 {
330         int i;
331
332         for (i=0;list[i];i++) {
333                 if (strcmp(list[i], s) == 0) return true;
334         }
335         return false;
336 }
337
338 /**
339   return true if a string is in a list, case insensitively
340 */
341 _PUBLIC_ bool str_list_check_ci(const char **list, const char *s)
342 {
343         int i;
344
345         for (i=0;list[i];i++) {
346                 if (strcasecmp(list[i], s) == 0) return true;
347         }
348         return false;
349 }
350
351
352 /**
353   append one list to another - expanding list1
354 */
355 _PUBLIC_ const char **str_list_append(const char **list1,
356         const char * const *list2)
357 {
358         size_t len1 = str_list_length(list1);
359         size_t len2 = str_list_length(list2);
360         const char **ret;
361         int i;
362
363         ret = talloc_realloc(NULL, list1, const char *, len1+len2+1);
364         if (ret == NULL) return NULL;
365
366         for (i=len1;i<len1+len2;i++) {
367                 ret[i] = talloc_strdup(ret, list2[i-len1]);
368                 if (ret[i] == NULL) {
369                         return NULL;
370                 }
371         }
372         ret[i] = NULL;
373
374         return ret;
375 }
376
377 static int list_cmp(const char **el1, const char **el2)
378 {
379         return strcmp(*el1, *el2);
380 }
381
382 /*
383   return a list that only contains the unique elements of a list,
384   removing any duplicates
385  */
386 _PUBLIC_ const char **str_list_unique(const char **list)
387 {
388         size_t len = str_list_length(list);
389         const char **list2;
390         int i, j;
391         if (len < 2) {
392                 return list;
393         }
394         list2 = (const char **)talloc_memdup(list, list,
395                                              sizeof(list[0])*(len+1));
396         qsort(list2, len, sizeof(list2[0]), QSORT_CAST list_cmp);
397         list[0] = list2[0];
398         for (i=j=1;i<len;i++) {
399                 if (strcmp(list2[i], list[j-1]) != 0) {
400                         list[j] = list2[i];
401                         j++;
402                 }
403         }
404         list[j] = NULL;
405         list = talloc_realloc(NULL, list, const char *, j + 1);
406         talloc_free(list2);
407         return list;
408 }
409
410 /*
411   very useful when debugging complex list related code
412  */
413 _PUBLIC_ void str_list_show(const char **list)
414 {
415         int i;
416         DEBUG(0,("{ "));
417         for (i=0;list && list[i];i++) {
418                 DEBUG(0,("\"%s\", ", list[i]));
419         }
420         DEBUG(0,("}\n"));
421 }
422
423
424
425 /**
426   append one list to another - expanding list1
427   this assumes the elements of list2 are const pointers, so we can re-use them
428 */
429 _PUBLIC_ const char **str_list_append_const(const char **list1,
430                                             const char **list2)
431 {
432         size_t len1 = str_list_length(list1);
433         size_t len2 = str_list_length(list2);
434         const char **ret;
435         int i;
436
437         ret = talloc_realloc(NULL, list1, const char *, len1+len2+1);
438         if (ret == NULL) return NULL;
439
440         for (i=len1;i<len1+len2;i++) {
441                 ret[i] = list2[i-len1];
442         }
443         ret[i] = NULL;
444
445         return ret;
446 }
447
448 /**
449   add an entry to a string list
450   this assumes s will not change
451 */
452 _PUBLIC_ const char **str_list_add_const(const char **list, const char *s)
453 {
454         size_t len = str_list_length(list);
455         const char **ret;
456
457         ret = talloc_realloc(NULL, list, const char *, len+2);
458         if (ret == NULL) return NULL;
459
460         ret[len] = s;
461         ret[len+1] = NULL;
462
463         return ret;
464 }
465
466 /**
467   copy a string list
468   this assumes list will not change
469 */
470 _PUBLIC_ const char **str_list_copy_const(TALLOC_CTX *mem_ctx,
471                                           const char **list)
472 {
473         int i;
474         const char **ret;
475
476         if (list == NULL)
477                 return NULL;
478         
479         ret = talloc_array(mem_ctx, const char *, str_list_length(list)+1);
480         if (ret == NULL) 
481                 return NULL;
482
483         for (i=0;list && list[i];i++) {
484                 ret[i] = list[i];
485         }
486         ret[i] = NULL;
487         return ret;
488 }
489
490 /**
491  * Needed for making an "unconst" list "const"
492  */
493 _PUBLIC_ const char **const_str_list(char **list)
494 {
495         return (const char **)list;
496 }
497