2fcbe186be081ec3b2b940b73673a72fcf828d88
[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         int num_elements = 0;
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         int num_elements = 0;
55         char **ret = NULL;
56
57         ret = talloc_array(mem_ctx, char *, 2);
58         if (ret == NULL) {
59                 return NULL;
60         }
61
62         ret[0] = talloc_strdup(ret, entry);
63         if (!ret[0]) {
64                 talloc_free(ret);
65                 return NULL;
66         }
67         ret[1] = NULL;
68
69         return ret;
70 }
71
72 /**
73   build a null terminated list of strings from a input string and a
74   separator list. The separator list must contain characters less than
75   or equal to 0x2f for this to work correctly on multi-byte strings
76 */
77 _PUBLIC_ char **str_list_make(TALLOC_CTX *mem_ctx, const char *string, const char *sep)
78 {
79         int num_elements = 0;
80         char **ret = NULL;
81
82         if (sep == NULL) {
83                 sep = LIST_SEP;
84         }
85
86         ret = talloc_array(mem_ctx, char *, 1);
87         if (ret == NULL) {
88                 return NULL;
89         }
90
91         while (string && *string) {
92                 size_t len = strcspn(string, sep);
93                 char **ret2;
94                 
95                 if (len == 0) {
96                         string += strspn(string, sep);
97                         continue;
98                 }
99
100                 ret2 = talloc_realloc(mem_ctx, ret, char *, 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 seperated by spaces and can be enclosed by quotes. 
125  * Does NOT support escaping
126  */
127 _PUBLIC_ const char **str_list_make_shell(TALLOC_CTX *mem_ctx, const char *string, const char *sep)
128 {
129         int num_elements = 0;
130         const char **ret = NULL;
131
132         ret = talloc_array(mem_ctx, const 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                 const 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, const 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 seperator)
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", seperator, list[i]);
198         }
199
200         return ret;
201 }
202
203 /** join a list back to one (shell-like) string; entries 
204  * seperated 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 **list1, const char **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_ char **str_list_append(const char **list1, const char * const *list2)
356 {
357         size_t len1 = str_list_length(list1);
358         size_t len2 = str_list_length(list2);
359         char **ret;
360         int i;
361
362         ret = talloc_realloc(NULL, list1, 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 }