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