Merge branch 'master' of git://git.samba.org/samba
[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 **list1, const char **list2)
268 {
269         int i;
270         
271         if (list1 == NULL || list2 == NULL) {
272                 return (list1 == list2); 
273         }
274         
275         for (i=0;list1[i] && list2[i];i++) {
276                 if (strcmp(list1[i], list2[i]) != 0) {
277                         return false;
278                 }
279         }
280         if (list1[i] || list2[i]) {
281                 return false;
282         }
283         return true;
284 }
285
286
287 /**
288   add an entry to a string list
289 */
290 _PUBLIC_ const char **str_list_add(const char **list, const char *s)
291 {
292         size_t len = str_list_length(list);
293         const char **ret;
294
295         ret = talloc_realloc(NULL, list, const char *, len+2);
296         if (ret == NULL) return NULL;
297
298         ret[len] = talloc_strdup(ret, s);
299         if (ret[len] == NULL) return NULL;
300
301         ret[len+1] = NULL;
302
303         return ret;
304 }
305
306 /**
307   remove an entry from a string list
308 */
309 _PUBLIC_ void str_list_remove(const char **list, const char *s)
310 {
311         int i;
312
313         for (i=0;list[i];i++) {
314                 if (strcmp(list[i], s) == 0) break;
315         }
316         if (!list[i]) return;
317
318         for (;list[i];i++) {
319                 list[i] = list[i+1];
320         }
321 }
322
323
324 /**
325   return true if a string is in a list
326 */
327 _PUBLIC_ bool str_list_check(const char **list, const char *s)
328 {
329         int i;
330
331         for (i=0;list[i];i++) {
332                 if (strcmp(list[i], s) == 0) return true;
333         }
334         return false;
335 }
336
337 /**
338   return true if a string is in a list, case insensitively
339 */
340 _PUBLIC_ bool str_list_check_ci(const char **list, const char *s)
341 {
342         int i;
343
344         for (i=0;list[i];i++) {
345                 if (strcasecmp(list[i], s) == 0) return true;
346         }
347         return false;
348 }
349
350
351 /**
352   append one list to another - expanding list1
353 */
354 _PUBLIC_ const char **str_list_append(const char **list1,
355         const char * const *list2)
356 {
357         size_t len1 = str_list_length(list1);
358         size_t len2 = str_list_length(list2);
359         const char **ret;
360         int i;
361
362         ret = talloc_realloc(NULL, list1, const char *, len1+len2+1);
363         if (ret == NULL) return NULL;
364
365         for (i=len1;i<len1+len2;i++) {
366                 ret[i] = talloc_strdup(ret, list2[i-len1]);
367                 if (ret[i] == NULL) {
368                         return NULL;
369                 }
370         }
371         ret[i] = NULL;
372
373         return ret;
374 }
375
376 static int list_cmp(const char **el1, const char **el2)
377 {
378         return strcmp(*el1, *el2);
379 }
380
381 /*
382   return a list that only contains the unique elements of a list,
383   removing any duplicates
384  */
385 _PUBLIC_ const char **str_list_unique(const char **list)
386 {
387         size_t len = str_list_length(list);
388         const char **list2;
389         int i, j;
390         if (len < 2) {
391                 return list;
392         }
393         list2 = (const char **)talloc_memdup(list, list,
394                                              sizeof(list[0])*(len+1));
395         qsort(list2, len, sizeof(list2[0]), QSORT_CAST list_cmp);
396         list[0] = list2[0];
397         for (i=j=1;i<len;i++) {
398                 if (strcmp(list2[i], list[j-1]) != 0) {
399                         list[j] = list2[i];
400                         j++;
401                 }
402         }
403         list[j] = NULL;
404         list = talloc_realloc(NULL, list, const char *, j);
405         talloc_free(list2);
406         return list;
407 }
408
409 /*
410   very useful when debugging complex list related code
411  */
412 _PUBLIC_ void str_list_show(const char **list)
413 {
414         int i;
415         DEBUG(0,("{ "));
416         for (i=0;list && list[i];i++) {
417                 DEBUG(0,("\"%s\", ", list[i]));
418         }
419         DEBUG(0,("}\n"));
420 }
421
422
423
424 /**
425   append one list to another - expanding list1
426   this assumes the elements of list2 are const pointers, so we can re-use them
427 */
428 _PUBLIC_ const char **str_list_append_const(const char **list1,
429                                             const char **list2)
430 {
431         size_t len1 = str_list_length(list1);
432         size_t len2 = str_list_length(list2);
433         const char **ret;
434         int i;
435
436         ret = talloc_realloc(NULL, list1, const char *, len1+len2+1);
437         if (ret == NULL) return NULL;
438
439         for (i=len1;i<len1+len2;i++) {
440                 ret[i] = list2[i-len1];
441         }
442         ret[i] = NULL;
443
444         return ret;
445 }
446
447 /**
448   add an entry to a string list
449   this assumes s will not change
450 */
451 _PUBLIC_ const char **str_list_add_const(const char **list, const char *s)
452 {
453         size_t len = str_list_length(list);
454         const char **ret;
455
456         ret = talloc_realloc(NULL, list, const char *, len+2);
457         if (ret == NULL) return NULL;
458
459         ret[len] = s;
460         ret[len+1] = NULL;
461
462         return ret;
463 }
464
465 /**
466   copy a string list
467   this assumes list will not change
468 */
469 _PUBLIC_ const char **str_list_copy_const(TALLOC_CTX *mem_ctx,
470                                           const char **list)
471 {
472         int i;
473         const char **ret;
474
475         if (list == NULL)
476                 return NULL;
477         
478         ret = talloc_array(mem_ctx, const char *, str_list_length(list)+1);
479         if (ret == NULL) 
480                 return NULL;
481
482         for (i=0;list && list[i];i++) {
483                 ret[i] = list[i];
484         }
485         ret[i] = NULL;
486         return ret;
487 }