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