Import from old repository commit 61ef2b42a9c4ba8e1600f15bb0236765edc2ad45.
[cascardo/ovs.git] / lib / svec.c
1 /*
2  * Copyright (c) 2008, 2009 Nicira Networks.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include <config.h>
18 #include "svec.h"
19 #include <assert.h>
20 #include <ctype.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include "dynamic-string.h"
24 #include "util.h"
25
26 #define THIS_MODULE VLM_svec
27 #include "vlog.h"
28
29 void
30 svec_init(struct svec *svec)
31 {
32     svec->names = NULL;
33     svec->n = 0;
34     svec->allocated = 0;
35 }
36
37 void
38 svec_clone(struct svec *svec, const struct svec *other)
39 {
40     svec_init(svec);
41     svec_append(svec, other);
42 }
43
44 void
45 svec_destroy(struct svec *svec)
46 {
47     svec_clear(svec);
48     free(svec->names);
49 }
50
51 void
52 svec_clear(struct svec *svec) 
53 {
54     size_t i;
55
56     for (i = 0; i < svec->n; i++) {
57         free(svec->names[i]);
58     }
59     svec->n = 0;
60 }
61
62 void
63 svec_add(struct svec *svec, const char *name)
64 {
65     svec_add_nocopy(svec, xstrdup(name));
66 }
67
68 void
69 svec_del(struct svec *svec, const char *name)
70 {
71     size_t offset;
72
73     offset = svec_find(svec, name);
74     if (offset != SIZE_MAX) {
75         free(svec->names[offset]);
76         memmove(&svec->names[offset], &svec->names[offset + 1],
77                 sizeof *svec->names * (svec->n - offset - 1));
78         svec->n--;
79     }
80 }
81
82 static void
83 svec_expand(struct svec *svec)
84 {
85     if (svec->n >= svec->allocated) {
86         svec->names = x2nrealloc(svec->names, &svec->allocated,
87                                  sizeof *svec->names);
88     }
89 }
90
91 void
92 svec_add_nocopy(struct svec *svec, char *name)
93 {
94     svec_expand(svec);
95     svec->names[svec->n++] = name;
96 }
97
98 void
99 svec_append(struct svec *svec, const struct svec *other)
100 {
101     size_t i;
102     for (i = 0; i < other->n; i++) {
103         svec_add(svec, other->names[i]);
104     }
105 }
106
107 void
108 svec_terminate(struct svec *svec)
109 {
110     svec_expand(svec);
111     svec->names[svec->n] = NULL;
112 }
113
114 static int
115 compare_strings(const void *a_, const void *b_)
116 {
117     char *const *a = a_;
118     char *const *b = b_;
119     return strcmp(*a, *b);
120 }
121
122 void
123 svec_sort(struct svec *svec)
124 {
125     qsort(svec->names, svec->n, sizeof *svec->names, compare_strings);
126 }
127
128 void
129 svec_sort_unique(struct svec *svec)
130 {
131     svec_sort(svec);
132     svec_unique(svec);
133 }
134
135 void
136 svec_unique(struct svec *svec)
137 {
138     assert(svec_is_sorted(svec));
139     if (svec->n > 1) {
140         /* This algorithm is lazy and sub-optimal, but it's "obviously correct"
141          * and asymptotically optimal . */
142         struct svec tmp;
143         size_t i;
144
145         svec_init(&tmp);
146         svec_add(&tmp, svec->names[0]);
147         for (i = 1; i < svec->n; i++) {
148             if (strcmp(svec->names[i - 1], svec->names[i])) {
149                 svec_add(&tmp, svec->names[i]);
150             }
151         }
152         svec_swap(&tmp, svec);
153         svec_destroy(&tmp);
154     }
155 }
156
157 void
158 svec_compact(struct svec *svec)
159 {
160     size_t i, j;
161
162     for (i = j = 0; i < svec->n; i++) {
163         if (svec->names[i] != NULL) {
164             svec->names[j++] = svec->names[i];
165         }
166     }
167     svec->n = j;
168 }
169
170 void
171 svec_diff(const struct svec *a, const struct svec *b,
172           struct svec *a_only, struct svec *both, struct svec *b_only)
173 {
174     size_t i, j;
175
176     assert(svec_is_sorted(a));
177     assert(svec_is_sorted(b));
178     if (a_only) {
179         svec_init(a_only);
180     }
181     if (both) {
182         svec_init(both);
183     }
184     if (b_only) {
185         svec_init(b_only);
186     }
187     for (i = j = 0; i < a->n && j < b->n; ) {
188         int cmp = strcmp(a->names[i], b->names[j]);
189         if (cmp < 0) {
190             if (a_only) {
191                 svec_add(a_only, a->names[i]);
192             }
193             i++;
194         } else if (cmp > 0) {
195             if (b_only) {
196                 svec_add(b_only, b->names[j]);
197             }
198             j++;
199         } else {
200             if (both) {
201                 svec_add(both, a->names[i]);
202             }
203             i++;
204             j++;
205         }
206     }
207     if (a_only) {
208         for (; i < a->n; i++) {
209             svec_add(a_only, a->names[i]);
210         }
211     }
212     if (b_only) {
213         for (; j < b->n; j++) {
214             svec_add(b_only, b->names[j]);
215         }
216     }
217 }
218
219 bool
220 svec_contains(const struct svec *svec, const char *name)
221 {
222     return svec_find(svec, name) != SIZE_MAX;
223 }
224
225 size_t
226 svec_find(const struct svec *svec, const char *name)
227 {
228     char **p;
229
230     assert(svec_is_sorted(svec));
231     p = bsearch(&name, svec->names, svec->n, sizeof *svec->names,
232                 compare_strings);
233     return p ? p - svec->names : SIZE_MAX;
234 }
235
236 bool
237 svec_is_sorted(const struct svec *svec)
238 {
239     size_t i;
240
241     for (i = 1; i < svec->n; i++) {
242         if (strcmp(svec->names[i - 1], svec->names[i]) > 0) {
243             return false;
244         }
245     }
246     return true;
247 }
248
249 bool
250 svec_is_unique(const struct svec *svec)
251 {
252     return svec_get_duplicate(svec) == NULL;
253 }
254
255 const char *
256 svec_get_duplicate(const struct svec *svec)
257 {
258     assert(svec_is_sorted(svec));
259     if (svec->n > 1) {
260         size_t i;
261         for (i = 1; i < svec->n; i++) {
262             if (!strcmp(svec->names[i - 1], svec->names[i])) {
263                 return svec->names[i];
264             }
265         }
266     }
267     return NULL;
268 }
269
270 void
271 svec_swap(struct svec *a, struct svec *b)
272 {
273     struct svec tmp = *a;
274     *a = *b;
275     *b = tmp;
276 }
277
278 void
279 svec_print(const struct svec *svec, const char *title)
280 {
281     size_t i;
282
283     printf("%s:\n", title);
284     for (i = 0; i < svec->n; i++) {
285         printf("\"%s\"\n", svec->names[i]);
286     }
287 }
288
289 /* Breaks 'words' into words at white space, respecting shell-like quoting
290  * conventions, and appends the words to 'svec'. */
291 void
292 svec_parse_words(struct svec *svec, const char *words)
293 {
294     struct ds word = DS_EMPTY_INITIALIZER;
295     const char *p, *q;
296
297     for (p = words; *p != '\0'; p = q) {
298         int quote = 0;
299
300         while (isspace((unsigned char) *p)) {
301             p++;
302         }
303         if (*p == '\0') {
304             break;
305         }
306
307         ds_clear(&word);
308         for (q = p; *q != '\0'; q++) {
309             if (*q == quote) {
310                 quote = 0;
311             } else if (*q == '\'' || *q == '"') {
312                 quote = *q;
313             } else if (*q == '\\' && (!quote || quote == '"')) {
314                 q++;
315                 if (*q == '\0') {
316                     VLOG_WARN("%s: ends in trailing backslash", words);
317                     break;
318                 }
319                 ds_put_char(&word, *q);
320             } else if (isspace((unsigned char) *q) && !quote) {
321                 q++;
322                 break;
323             } else {
324                 ds_put_char(&word, *q);
325             }
326         }
327         svec_add(svec, ds_cstr(&word));
328         if (quote) {
329             VLOG_WARN("%s: word ends inside quoted string", words);
330         }
331     }
332     ds_destroy(&word);
333 }
334
335 bool
336 svec_equal(const struct svec *a, const struct svec *b)
337 {
338     size_t i;
339
340     if (a->n != b->n) {
341         return false;
342     }
343     for (i = 0; i < a->n; i++) {
344         if (strcmp(a->names[i], b->names[i])) {
345             return false;
346         }
347     }
348     return true;
349 }
350
351 char *
352 svec_join(const struct svec *svec,
353           const char *delimiter, const char *terminator)
354 {
355     struct ds ds;
356     size_t i;
357
358     ds_init(&ds);
359     for (i = 0; i < svec->n; i++) {
360         if (i) {
361             ds_put_cstr(&ds, delimiter);
362         }
363         ds_put_cstr(&ds, svec->names[i]);
364     }
365     ds_put_cstr(&ds, terminator);
366     return ds_cstr(&ds);
367 }
368
369 const char *
370 svec_back(const struct svec *svec)
371 {
372     assert(svec->n);
373     return svec->names[svec->n - 1];
374 }
375
376 void
377 svec_pop_back(struct svec *svec)
378 {
379     assert(svec->n);
380     free(svec->names[--svec->n]);
381 }