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