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