Branch data Line data Source code
1 : : /* Copyright (c) 2012, 2014, 2015, 2016 Nicira, Inc.
2 : : *
3 : : * Licensed under the Apache License, Version 2.0 (the "License");
4 : : * you may not use this file except in compliance with the License.
5 : : * You may obtain a copy of the License at:
6 : : *
7 : : * http://www.apache.org/licenses/LICENSE-2.0
8 : : *
9 : : * Unless required by applicable law or agreed to in writing, software
10 : : * distributed under the License is distributed on an "AS IS" BASIS,
11 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : : * See the License for the specific language governing permissions and
13 : : * limitations under the License. */
14 : :
15 : : #include <config.h>
16 : : #include "smap.h"
17 : :
18 : : #include <strings.h>
19 : :
20 : : #include "hash.h"
21 : : #include "openvswitch/json.h"
22 : : #include "packets.h"
23 : : #include "uuid.h"
24 : :
25 : : static struct smap_node *smap_add__(struct smap *, char *, void *,
26 : : size_t hash);
27 : : static struct smap_node *smap_find__(const struct smap *, const char *key,
28 : : size_t key_len, size_t hash);
29 : : static int compare_nodes_by_key(const void *, const void *);
30 : :
31 : : /* Public Functions. */
32 : :
33 : : void
34 : 1735860 : smap_init(struct smap *smap)
35 : : {
36 : 1735860 : hmap_init(&smap->map);
37 : 1735860 : }
38 : :
39 : : void
40 : 953382 : smap_destroy(struct smap *smap)
41 : : {
42 [ + - ]: 953382 : if (smap) {
43 : 953382 : smap_clear(smap);
44 : 953382 : hmap_destroy(&smap->map);
45 : : }
46 : 953382 : }
47 : :
48 : : /* Adds 'key' paired with 'value' to 'smap'. It is the caller's responsibility
49 : : * to avoid duplicate keys if desirable. */
50 : : struct smap_node *
51 : 364495 : smap_add(struct smap *smap, const char *key, const char *value)
52 : : {
53 : 364495 : size_t key_len = strlen(key);
54 : 364495 : return smap_add__(smap, xmemdup0(key, key_len), xstrdup(value),
55 : 364495 : hash_bytes(key, key_len, 0));
56 : : }
57 : :
58 : : /* Adds 'key' paired with 'value' to 'smap'. Takes ownership of 'key' and
59 : : * 'value' (which will eventually be freed with free()). It is the caller's
60 : : * responsibility to avoid duplicate keys if desirable. */
61 : : struct smap_node *
62 : 0 : smap_add_nocopy(struct smap *smap, char *key, char *value)
63 : : {
64 : 0 : return smap_add__(smap, key, value, hash_bytes(key, strlen(key), 0));
65 : : }
66 : :
67 : : /* Attempts to add 'key' to 'smap' associated with 'value'. If 'key' already
68 : : * exists in 'smap', does nothing and returns false. Otherwise, performs the
69 : : * addition and returns true. */
70 : : bool
71 : 0 : smap_add_once(struct smap *smap, const char *key, const char *value)
72 : : {
73 [ # # ]: 0 : if (!smap_get(smap, key)) {
74 : 0 : smap_add(smap, key, value);
75 : 0 : return true;
76 : : } else {
77 : 0 : return false;
78 : : }
79 : : }
80 : :
81 : : /* Adds 'key' paired with a value derived from 'format' (similar to printf).
82 : : * It is the caller's responsibility to avoid duplicate keys if desirable. */
83 : : void
84 : 20631 : smap_add_format(struct smap *smap, const char *key, const char *format, ...)
85 : : {
86 : : size_t key_len;
87 : : va_list args;
88 : : char *value;
89 : :
90 : 20631 : va_start(args, format);
91 : 20631 : value = xvasprintf(format, args);
92 : 20631 : va_end(args);
93 : :
94 : 20631 : key_len = strlen(key);
95 : 20631 : smap_add__(smap, xmemdup0(key, key_len), value,
96 : 20631 : hash_bytes(key, key_len, 0));
97 : 20631 : }
98 : :
99 : : /* Adds 'key' paired with a string representation of 'addr'. It is the
100 : : * caller's responsibility to avoid duplicate keys if desirable. */
101 : : void
102 : 41 : smap_add_ipv6(struct smap *smap, const char *key, struct in6_addr *addr)
103 : : {
104 : : char buf[INET6_ADDRSTRLEN];
105 : 41 : ipv6_string_mapped(buf, addr);
106 : 41 : smap_add(smap, key, buf);
107 : 41 : }
108 : :
109 : : /* Searches for 'key' in 'smap'. If it does not already exists, adds it.
110 : : * Otherwise, changes its value to 'value'. */
111 : : void
112 : 53 : smap_replace(struct smap *smap, const char *key, const char *value)
113 : : {
114 : 53 : size_t key_len = strlen(key);
115 : 53 : size_t hash = hash_bytes(key, key_len, 0);
116 : :
117 : : struct smap_node *node;
118 : :
119 : 53 : node = smap_find__(smap, key, key_len, hash);
120 [ + + ]: 53 : if (node) {
121 : 28 : free(node->value);
122 : 28 : node->value = xstrdup(value);
123 : : } else {
124 : 25 : smap_add__(smap, xmemdup0(key, key_len), xstrdup(value), hash);
125 : : }
126 : 53 : }
127 : :
128 : : /* If 'key' is in 'smap', removes it. Otherwise does nothing. */
129 : : void
130 : 49 : smap_remove(struct smap *smap, const char *key)
131 : : {
132 : 49 : struct smap_node *node = smap_get_node(smap, key);
133 : :
134 [ + - ]: 49 : if (node) {
135 : 49 : smap_remove_node(smap, node);
136 : : }
137 : 49 : }
138 : :
139 : : /* Removes 'node' from 'smap'. */
140 : : void
141 : 385380 : smap_remove_node(struct smap *smap, struct smap_node *node)
142 : : {
143 : 385380 : hmap_remove(&smap->map, &node->node);
144 : 385380 : free(node->key);
145 : 385380 : free(node->value);
146 : 385380 : free(node);
147 : 385380 : }
148 : :
149 : : /* Deletes 'node' from 'smap'.
150 : : *
151 : : * If 'keyp' is nonnull, stores the node's key in '*keyp' and transfers
152 : : * ownership to the caller. Otherwise, frees the node's key. Similarly for
153 : : * 'valuep' and the node's value. */
154 : : void
155 : 0 : smap_steal(struct smap *smap, struct smap_node *node,
156 : : char **keyp, char **valuep)
157 : : {
158 [ # # ]: 0 : if (keyp) {
159 : 0 : *keyp = node->key;
160 : : } else {
161 : 0 : free(node->key);
162 : : }
163 : :
164 [ # # ]: 0 : if (valuep) {
165 : 0 : *valuep = node->value;
166 : : } else {
167 : 0 : free(node->value);
168 : : }
169 : :
170 : 0 : hmap_remove(&smap->map, &node->node);
171 : 0 : free(node);
172 : 0 : }
173 : :
174 : : /* Removes all key-value pairs from 'smap'. */
175 : : void
176 : 953535 : smap_clear(struct smap *smap)
177 : : {
178 : : struct smap_node *node, *next;
179 : :
180 [ + + ][ - + ]: 1338866 : SMAP_FOR_EACH_SAFE (node, next, smap) {
[ + + ]
181 : 385331 : smap_remove_node(smap, node);
182 : : }
183 : 953535 : }
184 : :
185 : : /* Returns the value associated with 'key' in 'smap'.
186 : : * If 'smap' does not contain 'key', returns NULL. */
187 : : const char *
188 : 2672544 : smap_get(const struct smap *smap, const char *key)
189 : : {
190 : 2672544 : return smap_get_def(smap, key, NULL);
191 : : }
192 : :
193 : : /* Returns the value associated with 'key' in 'smap'.
194 : : * If 'smap' does not contain 'key', returns 'def'. */
195 : : const char *
196 : 3442331 : smap_get_def(const struct smap *smap, const char *key, const char *def)
197 : : {
198 : 3442331 : struct smap_node *node = smap_get_node(smap, key);
199 [ + + ]: 3442331 : return node ? node->value : def;
200 : : }
201 : :
202 : : /* Returns the node associated with 'key' in 'smap', or NULL. */
203 : : struct smap_node *
204 : 3442380 : smap_get_node(const struct smap *smap, const char *key)
205 : : {
206 : 3442380 : size_t key_len = strlen(key);
207 : 3442380 : return smap_find__(smap, key, key_len, hash_bytes(key, key_len, 0));
208 : : }
209 : :
210 : : /* Gets the value associated with 'key' in 'smap' and converts it to a boolean.
211 : : * If 'key' is not in 'smap', or its value is neither "true" nor "false",
212 : : * returns 'def'. */
213 : : bool
214 : 195753 : smap_get_bool(const struct smap *smap, const char *key, bool def)
215 : : {
216 : 195753 : const char *value = smap_get_def(smap, key, "");
217 [ + + ]: 195753 : if (def) {
218 : 301 : return strcasecmp("false", value) != 0;
219 : : } else {
220 : 195452 : return !strcasecmp("true", value);
221 : : }
222 : : }
223 : :
224 : : /* Gets the value associated with 'key' in 'smap' and converts it to an int
225 : : * using atoi(). If 'key' is not in 'smap', returns 'def'. */
226 : : int
227 : 229819 : smap_get_int(const struct smap *smap, const char *key, int def)
228 : : {
229 : 229819 : const char *value = smap_get(smap, key);
230 : :
231 [ + + ]: 229819 : return value ? atoi(value) : def;
232 : : }
233 : :
234 : : /* Gets the value associated with 'key' in 'smap' and converts it to an int
235 : : * using strtoull(). If 'key' is not in 'smap', returns 'def'. */
236 : : unsigned long long int
237 : 121 : smap_get_ullong(const struct smap *smap, const char *key,
238 : : unsigned long long def)
239 : : {
240 : 121 : const char *value = smap_get(smap, key);
241 : :
242 [ - + ]: 121 : return value ? strtoull(value, NULL, 10) : def;
243 : : }
244 : :
245 : : /* Gets the value associated with 'key' in 'smap' and converts it to a UUID
246 : : * using uuid_from_string(). Returns true if successful, false if 'key' is not
247 : : * in 'smap' or if 'key' does not have the correct syntax for a UUID. */
248 : : bool
249 : 441859 : smap_get_uuid(const struct smap *smap, const char *key, struct uuid *uuid)
250 : : {
251 : 441859 : return uuid_from_string(uuid, smap_get_def(smap, key, ""));
252 : : }
253 : :
254 : : /* Returns true of there are no elements in 'smap'. */
255 : : bool
256 : 4317 : smap_is_empty(const struct smap *smap)
257 : : {
258 : 4317 : return hmap_is_empty(&smap->map);
259 : : }
260 : :
261 : : /* Returns the number of elements in 'smap'. */
262 : : size_t
263 : 101619 : smap_count(const struct smap *smap)
264 : : {
265 : 101619 : return hmap_count(&smap->map);
266 : : }
267 : :
268 : : /* Initializes 'dst' as a clone of 'src. */
269 : : void
270 : 84 : smap_clone(struct smap *dst, const struct smap *src)
271 : : {
272 : : const struct smap_node *node;
273 : :
274 : 84 : smap_init(dst);
275 [ + + ][ - + ]: 314 : SMAP_FOR_EACH (node, src) {
276 : 230 : smap_add__(dst, xstrdup(node->key), xstrdup(node->value),
277 : : node->node.hash);
278 : : }
279 : 84 : }
280 : :
281 : : /* Returns an array of nodes sorted on key or NULL if 'smap' is empty. The
282 : : * caller is responsible for freeing this array. */
283 : : const struct smap_node **
284 : 142 : smap_sort(const struct smap *smap)
285 : : {
286 [ + + ]: 142 : if (smap_is_empty(smap)) {
287 : 72 : return NULL;
288 : : } else {
289 : : const struct smap_node **nodes;
290 : : struct smap_node *node;
291 : : size_t i, n;
292 : :
293 : 70 : n = smap_count(smap);
294 : 70 : nodes = xmalloc(n * sizeof *nodes);
295 : 70 : i = 0;
296 [ + + ][ - + ]: 197 : SMAP_FOR_EACH (node, smap) {
297 : 127 : nodes[i++] = node;
298 : : }
299 [ - + ]: 70 : ovs_assert(i == n);
300 : :
301 : 70 : qsort(nodes, n, sizeof *nodes, compare_nodes_by_key);
302 : :
303 : 70 : return nodes;
304 : : }
305 : : }
306 : :
307 : : /* Adds each of the key-value pairs from 'json' (which must be a JSON object
308 : : * whose values are strings) to 'smap'.
309 : : *
310 : : * The caller must have initialized 'smap'.
311 : : *
312 : : * The caller retains ownership of 'json' and everything in it. */
313 : : void
314 : 0 : smap_from_json(struct smap *smap, const struct json *json)
315 : : {
316 : : const struct shash_node *node;
317 : :
318 [ # # ][ # # ]: 0 : SHASH_FOR_EACH (node, json_object(json)) {
319 : 0 : const struct json *value = node->data;
320 : 0 : smap_add(smap, node->name, json_string(value));
321 : : }
322 : 0 : }
323 : :
324 : : /* Returns a JSON object that maps from the keys in 'smap' to their values.
325 : : *
326 : : * The caller owns the returned value and must eventually json_destroy() it.
327 : : *
328 : : * The caller retains ownership of 'smap' and everything in it. */
329 : : struct json *
330 : 0 : smap_to_json(const struct smap *smap)
331 : : {
332 : : const struct smap_node *node;
333 : : struct json *json;
334 : :
335 : 0 : json = json_object_create();
336 [ # # ][ # # ]: 0 : SMAP_FOR_EACH (node, smap) {
337 : 0 : json_object_put_string(json, node->key, node->value);
338 : : }
339 : 0 : return json;
340 : : }
341 : :
342 : : /* Returns true if the two maps are equal, meaning that they have the same set
343 : : * of key-value pairs.
344 : : */
345 : : bool
346 : 3294 : smap_equal(const struct smap *smap1, const struct smap *smap2)
347 : : {
348 [ - + ]: 3294 : if (smap_count(smap1) != smap_count(smap2)) {
349 : 0 : return false;
350 : : }
351 : :
352 : : const struct smap_node *node;
353 [ + + ][ - + ]: 13152 : SMAP_FOR_EACH (node, smap1) {
354 : 9859 : const char *value2 = smap_get(smap2, node->key);
355 [ + - ][ + + ]: 9859 : if (!value2 || strcmp(node->value, value2)) {
356 : 1 : return false;
357 : : }
358 : : }
359 : 3293 : return true;
360 : : }
361 : :
362 : : /* Private Helpers. */
363 : :
364 : : static struct smap_node *
365 : 385381 : smap_add__(struct smap *smap, char *key, void *value, size_t hash)
366 : : {
367 : 385381 : struct smap_node *node = xmalloc(sizeof *node);
368 : 385381 : node->key = key;
369 : 385381 : node->value = value;
370 : 385381 : hmap_insert(&smap->map, &node->node, hash);
371 : 385381 : return node;
372 : : }
373 : :
374 : : static struct smap_node *
375 : 3442433 : smap_find__(const struct smap *smap, const char *key, size_t key_len,
376 : : size_t hash)
377 : : {
378 : : struct smap_node *node;
379 : :
380 [ + + ][ - + ]: 3442433 : HMAP_FOR_EACH_WITH_HASH (node, node, hash, &smap->map) {
381 [ + - ][ + - ]: 1593062 : if (!strncmp(node->key, key, key_len) && !node->key[key_len]) {
382 : 1593062 : return node;
383 : : }
384 : : }
385 : :
386 : 1849371 : return NULL;
387 : : }
388 : :
389 : : static int
390 : 75 : compare_nodes_by_key(const void *a_, const void *b_)
391 : : {
392 : 75 : const struct smap_node *const *a = a_;
393 : 75 : const struct smap_node *const *b = b_;
394 : 75 : return strcmp((*a)->key, (*b)->key);
395 : : }
|