]> git.proxmox.com Git - mirror_ovs.git/blob - lib/svec.c
ofp-actions: Fix userspace support for mpls_ttl.
[mirror_ovs.git] / lib / svec.c
1 /*
2 * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
3 *
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:
7 *
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.
15 */
16
17 #include <config.h>
18 #include "svec.h"
19 #include <ctype.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include "openvswitch/dynamic-string.h"
23 #include "random.h"
24 #include "util.h"
25 #include "openvswitch/vlog.h"
26
27 VLOG_DEFINE_THIS_MODULE(svec);
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 bool
63 svec_is_empty(const struct svec *svec)
64 {
65 return svec->n == 0;
66 }
67
68 void
69 svec_add(struct svec *svec, const char *name)
70 {
71 svec_add_nocopy(svec, xstrdup(name));
72 }
73
74 void
75 svec_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
88 static void
89 svec_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
97 void
98 svec_add_nocopy(struct svec *svec, char *name)
99 {
100 svec_expand(svec);
101 svec->names[svec->n++] = name;
102 }
103
104 void
105 svec_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
113 void
114 svec_terminate(struct svec *svec)
115 {
116 svec_expand(svec);
117 svec->names[svec->n] = NULL;
118 }
119
120 static int
121 compare_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
128 void
129 svec_sort(struct svec *svec)
130 {
131 if (svec->n) {
132 qsort(svec->names, svec->n, sizeof *svec->names, compare_strings);
133 }
134 }
135
136 void
137 svec_sort_unique(struct svec *svec)
138 {
139 svec_sort(svec);
140 svec_unique(svec);
141 }
142
143 void
144 svec_unique(struct svec *svec)
145 {
146 ovs_assert(svec_is_sorted(svec));
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
165 void
166 svec_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
178 static void
179 swap_strings(char **a, char **b)
180 {
181 char *tmp = *a;
182 *a = *b;
183 *b = tmp;
184 }
185
186 void
187 svec_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
195 void
196 svec_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
201 ovs_assert(svec_is_sorted(a));
202 ovs_assert(svec_is_sorted(b));
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
244 bool
245 svec_contains(const struct svec *svec, const char *name)
246 {
247 return svec_find(svec, name) != SIZE_MAX;
248 }
249
250 size_t
251 svec_find(const struct svec *svec, const char *name)
252 {
253 char **p;
254
255 ovs_assert(svec_is_sorted(svec));
256 p = bsearch(&name, svec->names, svec->n, sizeof *svec->names,
257 compare_strings);
258 return p ? p - svec->names : SIZE_MAX;
259 }
260
261 bool
262 svec_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
274 bool
275 svec_is_unique(const struct svec *svec)
276 {
277 return svec_get_duplicate(svec) == NULL;
278 }
279
280 const char *
281 svec_get_duplicate(const struct svec *svec)
282 {
283 ovs_assert(svec_is_sorted(svec));
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
295 void
296 svec_swap(struct svec *a, struct svec *b)
297 {
298 struct svec tmp = *a;
299 *a = *b;
300 *b = tmp;
301 }
302
303 void
304 svec_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'. */
316 void
317 svec_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
360 bool
361 svec_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
376 char *
377 svec_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
394 const char *
395 svec_back(const struct svec *svec)
396 {
397 ovs_assert(svec->n);
398 return svec->names[svec->n - 1];
399 }
400
401 void
402 svec_pop_back(struct svec *svec)
403 {
404 ovs_assert(svec->n);
405 free(svec->names[--svec->n]);
406 }