]> git.proxmox.com Git - mirror_ovs.git/blame - lib/svec.c
cirrus: Use FreeBSD 12.2.
[mirror_ovs.git] / lib / svec.c
CommitLineData
064af421 1/*
cb22974d 2 * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
064af421 3 *
a14bc59f
BP
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
064af421 7 *
a14bc59f
BP
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
064af421
BP
15 */
16
17#include <config.h>
18#include "svec.h"
064af421
BP
19#include <ctype.h>
20#include <stdlib.h>
21#include <string.h>
3e8a2ad1 22#include "openvswitch/dynamic-string.h"
8cf6bbb1 23#include "random.h"
064af421 24#include "util.h"
e6211adc 25#include "openvswitch/vlog.h"
064af421 26
d98e6007 27VLOG_DEFINE_THIS_MODULE(svec);
5136ce49 28
064af421
BP
29void
30svec_init(struct svec *svec)
31{
32 svec->names = NULL;
33 svec->n = 0;
34 svec->allocated = 0;
35}
36
37void
38svec_clone(struct svec *svec, const struct svec *other)
39{
40 svec_init(svec);
41 svec_append(svec, other);
42}
43
44void
45svec_destroy(struct svec *svec)
46{
47 svec_clear(svec);
48 free(svec->names);
49}
50
51void
d295e8e9 52svec_clear(struct svec *svec)
064af421
BP
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
8ecd5308
BP
62bool
63svec_is_empty(const struct svec *svec)
64{
65 return svec->n == 0;
66}
67
064af421
BP
68void
69svec_add(struct svec *svec, const char *name)
70{
71 svec_add_nocopy(svec, xstrdup(name));
72}
73
74void
75svec_del(struct svec *svec, const char *name)
76{
77 size_t offset;
78
79 offset = svec_find(svec, name);
80 if (offset != SIZE_MAX) {
81 free(svec->names[offset]);
82 memmove(&svec->names[offset], &svec->names[offset + 1],
83 sizeof *svec->names * (svec->n - offset - 1));
84 svec->n--;
85 }
86}
87
88static void
89svec_expand(struct svec *svec)
90{
91 if (svec->n >= svec->allocated) {
92 svec->names = x2nrealloc(svec->names, &svec->allocated,
93 sizeof *svec->names);
94 }
95}
96
97void
98svec_add_nocopy(struct svec *svec, char *name)
99{
100 svec_expand(svec);
101 svec->names[svec->n++] = name;
102}
103
104void
105svec_append(struct svec *svec, const struct svec *other)
106{
107 size_t i;
108 for (i = 0; i < other->n; i++) {
109 svec_add(svec, other->names[i]);
110 }
111}
112
113void
114svec_terminate(struct svec *svec)
115{
116 svec_expand(svec);
117 svec->names[svec->n] = NULL;
118}
119
120static int
121compare_strings(const void *a_, const void *b_)
122{
123 char *const *a = a_;
124 char *const *b = b_;
125 return strcmp(*a, *b);
126}
127
128void
129svec_sort(struct svec *svec)
130{
316d0932
LR
131 if (svec->n) {
132 qsort(svec->names, svec->n, sizeof *svec->names, compare_strings);
133 }
064af421
BP
134}
135
136void
137svec_sort_unique(struct svec *svec)
138{
139 svec_sort(svec);
140 svec_unique(svec);
141}
142
143void
144svec_unique(struct svec *svec)
145{
cb22974d 146 ovs_assert(svec_is_sorted(svec));
064af421
BP
147 if (svec->n > 1) {
148 /* This algorithm is lazy and sub-optimal, but it's "obviously correct"
149 * and asymptotically optimal . */
150 struct svec tmp;
151 size_t i;
152
153 svec_init(&tmp);
154 svec_add(&tmp, svec->names[0]);
155 for (i = 1; i < svec->n; i++) {
156 if (strcmp(svec->names[i - 1], svec->names[i])) {
157 svec_add(&tmp, svec->names[i]);
158 }
159 }
160 svec_swap(&tmp, svec);
161 svec_destroy(&tmp);
162 }
163}
164
165void
166svec_compact(struct svec *svec)
167{
168 size_t i, j;
169
170 for (i = j = 0; i < svec->n; i++) {
171 if (svec->names[i] != NULL) {
172 svec->names[j++] = svec->names[i];
173 }
174 }
175 svec->n = j;
176}
177
8cf6bbb1
BP
178static void
179swap_strings(char **a, char **b)
180{
181 char *tmp = *a;
182 *a = *b;
183 *b = tmp;
184}
185
186void
187svec_shuffle(struct svec *svec)
188{
189 for (size_t i = 0; i < svec->n; i++) {
190 size_t j = i + random_range(svec->n - i);
191 swap_strings(&svec->names[i], &svec->names[j]);
192 }
193}
194
064af421
BP
195void
196svec_diff(const struct svec *a, const struct svec *b,
197 struct svec *a_only, struct svec *both, struct svec *b_only)
198{
199 size_t i, j;
200
cb22974d
BP
201 ovs_assert(svec_is_sorted(a));
202 ovs_assert(svec_is_sorted(b));
064af421
BP
203 if (a_only) {
204 svec_init(a_only);
205 }
206 if (both) {
207 svec_init(both);
208 }
209 if (b_only) {
210 svec_init(b_only);
211 }
212 for (i = j = 0; i < a->n && j < b->n; ) {
213 int cmp = strcmp(a->names[i], b->names[j]);
214 if (cmp < 0) {
215 if (a_only) {
216 svec_add(a_only, a->names[i]);
217 }
218 i++;
219 } else if (cmp > 0) {
220 if (b_only) {
221 svec_add(b_only, b->names[j]);
222 }
223 j++;
224 } else {
225 if (both) {
226 svec_add(both, a->names[i]);
227 }
228 i++;
229 j++;
230 }
231 }
232 if (a_only) {
233 for (; i < a->n; i++) {
234 svec_add(a_only, a->names[i]);
235 }
236 }
237 if (b_only) {
238 for (; j < b->n; j++) {
239 svec_add(b_only, b->names[j]);
240 }
241 }
242}
243
244bool
245svec_contains(const struct svec *svec, const char *name)
246{
247 return svec_find(svec, name) != SIZE_MAX;
248}
249
250size_t
251svec_find(const struct svec *svec, const char *name)
252{
253 char **p;
254
cb22974d 255 ovs_assert(svec_is_sorted(svec));
064af421
BP
256 p = bsearch(&name, svec->names, svec->n, sizeof *svec->names,
257 compare_strings);
258 return p ? p - svec->names : SIZE_MAX;
259}
260
261bool
262svec_is_sorted(const struct svec *svec)
263{
264 size_t i;
265
266 for (i = 1; i < svec->n; i++) {
267 if (strcmp(svec->names[i - 1], svec->names[i]) > 0) {
268 return false;
269 }
270 }
271 return true;
272}
273
274bool
275svec_is_unique(const struct svec *svec)
276{
277 return svec_get_duplicate(svec) == NULL;
278}
279
280const char *
281svec_get_duplicate(const struct svec *svec)
282{
cb22974d 283 ovs_assert(svec_is_sorted(svec));
064af421
BP
284 if (svec->n > 1) {
285 size_t i;
286 for (i = 1; i < svec->n; i++) {
287 if (!strcmp(svec->names[i - 1], svec->names[i])) {
288 return svec->names[i];
289 }
290 }
291 }
292 return NULL;
293}
294
295void
296svec_swap(struct svec *a, struct svec *b)
297{
298 struct svec tmp = *a;
299 *a = *b;
300 *b = tmp;
301}
302
303void
304svec_print(const struct svec *svec, const char *title)
305{
306 size_t i;
307
308 printf("%s:\n", title);
309 for (i = 0; i < svec->n; i++) {
310 printf("\"%s\"\n", svec->names[i]);
311 }
312}
313
314/* Breaks 'words' into words at white space, respecting shell-like quoting
315 * conventions, and appends the words to 'svec'. */
316void
317svec_parse_words(struct svec *svec, const char *words)
318{
319 struct ds word = DS_EMPTY_INITIALIZER;
320 const char *p, *q;
321
322 for (p = words; *p != '\0'; p = q) {
323 int quote = 0;
324
325 while (isspace((unsigned char) *p)) {
326 p++;
327 }
328 if (*p == '\0') {
329 break;
330 }
331
332 ds_clear(&word);
333 for (q = p; *q != '\0'; q++) {
334 if (*q == quote) {
335 quote = 0;
336 } else if (*q == '\'' || *q == '"') {
337 quote = *q;
338 } else if (*q == '\\' && (!quote || quote == '"')) {
339 q++;
340 if (*q == '\0') {
341 VLOG_WARN("%s: ends in trailing backslash", words);
342 break;
343 }
344 ds_put_char(&word, *q);
345 } else if (isspace((unsigned char) *q) && !quote) {
346 q++;
347 break;
348 } else {
349 ds_put_char(&word, *q);
350 }
351 }
352 svec_add(svec, ds_cstr(&word));
353 if (quote) {
354 VLOG_WARN("%s: word ends inside quoted string", words);
355 }
356 }
357 ds_destroy(&word);
358}
359
360bool
361svec_equal(const struct svec *a, const struct svec *b)
362{
363 size_t i;
364
365 if (a->n != b->n) {
366 return false;
367 }
368 for (i = 0; i < a->n; i++) {
369 if (strcmp(a->names[i], b->names[i])) {
370 return false;
371 }
372 }
373 return true;
374}
375
376char *
377svec_join(const struct svec *svec,
378 const char *delimiter, const char *terminator)
379{
380 struct ds ds;
381 size_t i;
382
383 ds_init(&ds);
384 for (i = 0; i < svec->n; i++) {
385 if (i) {
386 ds_put_cstr(&ds, delimiter);
387 }
388 ds_put_cstr(&ds, svec->names[i]);
389 }
390 ds_put_cstr(&ds, terminator);
391 return ds_cstr(&ds);
392}
393
394const char *
395svec_back(const struct svec *svec)
396{
cb22974d 397 ovs_assert(svec->n);
064af421
BP
398 return svec->names[svec->n - 1];
399}
400
401void
402svec_pop_back(struct svec *svec)
403{
cb22974d 404 ovs_assert(svec->n);
064af421
BP
405 free(svec->names[--svec->n]);
406}