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