0e9fcd9db9eba4d73681431d2d26f1434534ffdb
[samba.git] / source4 / 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 2 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, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23 #include "pstring.h"
24 #include "system/locale.h"
25
26 /**
27  * @file
28  * @brief String list manipulation
29  */
30
31 /**
32   build a null terminated list of strings from a input string and a
33   separator list. The separator list must contain characters less than
34   or equal to 0x2f for this to work correctly on multi-byte strings
35 */
36 _PUBLIC_ const char **str_list_make(TALLOC_CTX *mem_ctx, const char *string, const char *sep)
37 {
38         int num_elements = 0;
39         const char **ret = NULL;
40
41         if (sep == NULL) {
42                 sep = LIST_SEP;
43         }
44
45         ret = talloc_array(mem_ctx, const char *, 1);
46         if (ret == NULL) {
47                 return NULL;
48         }
49
50         while (string && *string) {
51                 size_t len = strcspn(string, sep);
52                 const char **ret2;
53                 
54                 if (len == 0) {
55                         string += strspn(string, sep);
56                         continue;
57                 }
58
59                 ret2 = talloc_realloc(mem_ctx, ret, const char *, num_elements+2);
60                 if (ret2 == NULL) {
61                         talloc_free(ret);
62                         return NULL;
63                 }
64                 ret = ret2;
65
66                 ret[num_elements] = talloc_strndup(ret, string, len);
67                 if (ret[num_elements] == NULL) {
68                         talloc_free(ret);
69                         return NULL;
70                 }
71
72                 num_elements++;
73                 string += len;
74         }
75
76         ret[num_elements] = NULL;
77
78         return ret;
79 }
80
81 /**
82  * build a null terminated list of strings from an argv-like input string 
83  * Entries are seperated by spaces and can be enclosed by quotes. 
84  * Does NOT support escaping
85  */
86 _PUBLIC_ const char **str_list_make_shell(TALLOC_CTX *mem_ctx, const char *string, const char *sep)
87 {
88         int num_elements = 0;
89         const char **ret = NULL;
90
91         ret = talloc_array(mem_ctx, const char *, 1);
92         if (ret == NULL) {
93                 return NULL;
94         }
95
96         if (sep == NULL)
97                 sep = " \t\n\r";
98
99         while (string && *string) {
100                 size_t len = strcspn(string, sep);
101                 char *element;
102                 const char **ret2;
103                 
104                 if (len == 0) {
105                         string += strspn(string, sep);
106                         continue;
107                 }
108
109                 if (*string == '\"') {
110                         string++;
111                         len = strcspn(string, "\"");
112                         element = talloc_strndup(ret, string, len);
113                         string += len + 1;
114                 } else {
115                         element = talloc_strndup(ret, string, len);
116                         string += len;
117                 }
118
119                 if (element == NULL) {
120                         talloc_free(ret);
121                         return NULL;
122                 }
123
124                 ret2 = talloc_realloc(mem_ctx, ret, const char *, num_elements+2);
125                 if (ret2 == NULL) {
126                         talloc_free(ret);
127                         return NULL;
128                 }
129                 ret = ret2;
130
131                 ret[num_elements] = element;    
132
133                 num_elements++;
134         }
135
136         ret[num_elements] = NULL;
137
138         return ret;
139
140 }
141
142 /**
143  * join a list back to one string 
144  */
145 _PUBLIC_ char *str_list_join(TALLOC_CTX *mem_ctx, const char **list, char seperator)
146 {
147         char *ret = NULL;
148         int i;
149         
150         if (list[0] == NULL)
151                 return talloc_strdup(mem_ctx, "");
152
153         ret = talloc_strdup(mem_ctx, list[0]);
154
155         for (i = 1; list[i]; i++) {
156                 ret = talloc_asprintf_append(ret, "%c%s", seperator, list[i]);
157         }
158
159         return ret;
160 }
161
162 /** join a list back to one (shell-like) string; entries 
163  * seperated by spaces, using quotes where necessary */
164 _PUBLIC_ char *str_list_join_shell(TALLOC_CTX *mem_ctx, const char **list, char sep)
165 {
166         char *ret = NULL;
167         int i;
168         
169         if (list[0] == NULL)
170                 return talloc_strdup(mem_ctx, "");
171
172         if (strchr(list[0], ' ') || strlen(list[0]) == 0) 
173                 ret = talloc_asprintf(mem_ctx, "\"%s\"", list[0]);
174         else 
175                 ret = talloc_strdup(mem_ctx, list[0]);
176
177         for (i = 1; list[i]; i++) {
178                 if (strchr(list[i], ' ') || strlen(list[i]) == 0) 
179                         ret = talloc_asprintf_append(ret, "%c\"%s\"", sep, list[i]);
180                 else 
181                         ret = talloc_asprintf_append(ret, "%c%s", sep, list[i]);
182         }
183
184         return ret;
185 }
186
187 /**
188   return the number of elements in a string list
189 */
190 _PUBLIC_ size_t str_list_length(const char **list)
191 {
192         size_t ret;
193         for (ret=0;list && list[ret];ret++) /* noop */ ;
194         return ret;
195 }
196
197
198 /**
199   copy a string list
200 */
201 _PUBLIC_ const char **str_list_copy(TALLOC_CTX *mem_ctx, const char **list)
202 {
203         int i;
204         const char **ret = talloc_array(mem_ctx, const char *, str_list_length(list)+1);
205         if (ret == NULL) return NULL;
206
207         for (i=0;list && list[i];i++) {
208                 ret[i] = talloc_strdup(ret, list[i]);
209                 if (ret[i] == NULL) {
210                         talloc_free(ret);
211                         return NULL;
212                 }
213         }
214         ret[i] = NULL;
215         return ret;
216 }
217
218 /**
219    Return true if all the elements of the list match exactly.
220  */
221 _PUBLIC_ BOOL str_list_equal(const char **list1, const char **list2)
222 {
223         int i;
224         
225         if (list1 == NULL || list2 == NULL) {
226                 return (list1 == list2); 
227         }
228         
229         for (i=0;list1[i] && list2[i];i++) {
230                 if (strcmp(list1[i], list2[i]) != 0) {
231                         return False;
232                 }
233         }
234         if (list1[i] || list2[i]) {
235                 return False;
236         }
237         return True;
238 }
239
240
241 /**
242   add an entry to a string list
243 */
244 _PUBLIC_ const char **str_list_add(const char **list, const char *s)
245 {
246         size_t len = str_list_length(list);
247         const char **ret;
248
249         ret = talloc_realloc(NULL, list, const char *, len+2);
250         if (ret == NULL) return NULL;
251
252         ret[len] = talloc_strdup(ret, s);
253         if (ret[len] == NULL) return NULL;
254
255         ret[len+1] = NULL;
256
257         return ret;
258 }
259
260 /**
261   remove an entry from a string list
262 */
263 _PUBLIC_ void str_list_remove(const char **list, const char *s)
264 {
265         int i;
266
267         for (i=0;list[i];i++) {
268                 if (strcmp(list[i], s) == 0) break;
269         }
270         if (!list[i]) return;
271
272         for (;list[i];i++) {
273                 list[i] = list[i+1];
274         }
275 }
276
277
278 /**
279   return True if a string is in a list
280 */
281 _PUBLIC_ BOOL str_list_check(const char **list, const char *s)
282 {
283         int i;
284
285         for (i=0;list[i];i++) {
286                 if (strcmp(list[i], s) == 0) return True;
287         }
288         return False;
289 }
290
291 /**
292   return True if a string is in a list, case insensitively
293 */
294 _PUBLIC_ BOOL str_list_check_ci(const char **list, const char *s)
295 {
296         int i;
297
298         for (i=0;list[i];i++) {
299                 if (strcasecmp(list[i], s) == 0) return True;
300         }
301         return False;
302 }
303
304 /**
305  Check if a string is part of a list.
306 **/
307 _PUBLIC_ BOOL in_list(const char *s, const char *list, BOOL casesensitive)
308 {
309         pstring tok;
310         const char *p=list;
311
312         if (!list)
313                 return(False);
314
315         while (next_token(&p,tok,LIST_SEP,sizeof(tok))) {
316                 if (casesensitive) {
317                         if (strcmp(tok,s) == 0)
318                                 return(True);
319                 } else {
320                         if (strcasecmp_m(tok,s) == 0)
321                                 return(True);
322                 }
323         }
324         return(False);
325 }