netdev-dpdk: fix mbuf leaks
[cascardo/ovs.git] / lib / smap.c
1 /* Copyright (c) 2012, 2014, 2015 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 "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 \f
31 /* Public Functions. */
32
33 void
34 smap_init(struct smap *smap)
35 {
36     hmap_init(&smap->map);
37 }
38
39 void
40 smap_destroy(struct smap *smap)
41 {
42     if (smap) {
43         smap_clear(smap);
44         hmap_destroy(&smap->map);
45     }
46 }
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 smap_add(struct smap *smap, const char *key, const char *value)
52 {
53     size_t key_len = strlen(key);
54     return smap_add__(smap, xmemdup0(key, key_len), xstrdup(value),
55                       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 smap_add_nocopy(struct smap *smap, char *key, char *value)
63 {
64     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 smap_add_once(struct smap *smap, const char *key, const char *value)
72 {
73     if (!smap_get(smap, key)) {
74         smap_add(smap, key, value);
75         return true;
76     } else {
77         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 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     va_start(args, format);
91     value = xvasprintf(format, args);
92     va_end(args);
93
94     key_len = strlen(key);
95     smap_add__(smap, xmemdup0(key, key_len), value,
96                hash_bytes(key, key_len, 0));
97 }
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 smap_add_ipv6(struct smap *smap, const char *key, struct in6_addr *addr)
103 {
104     char buf[INET6_ADDRSTRLEN];
105     ipv6_string_mapped(buf, addr);
106     smap_add(smap, key, buf);
107 }
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 smap_replace(struct smap *smap, const char *key, const char *value)
113 {
114     size_t  key_len = strlen(key);
115     size_t hash = hash_bytes(key, key_len, 0);
116
117     struct smap_node *node;
118
119     node = smap_find__(smap, key, key_len, hash);
120     if (node) {
121         free(node->value);
122         node->value = xstrdup(value);
123     } else {
124         smap_add__(smap, xmemdup0(key, key_len), xstrdup(value), hash);
125     }
126 }
127
128 /* If 'key' is in 'smap', removes it.  Otherwise does nothing. */
129 void
130 smap_remove(struct smap *smap, const char *key)
131 {
132     struct smap_node *node = smap_get_node(smap, key);
133
134     if (node) {
135         smap_remove_node(smap, node);
136     }
137 }
138
139 /* Removes 'node' from 'smap'. */
140 void
141 smap_remove_node(struct smap *smap, struct smap_node *node)
142 {
143     hmap_remove(&smap->map, &node->node);
144     free(node->key);
145     free(node->value);
146     free(node);
147 }
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 smap_steal(struct smap *smap, struct smap_node *node,
156            char **keyp, char **valuep)
157 {
158     if (keyp) {
159         *keyp = node->key;
160     } else {
161         free(node->key);
162     }
163
164     if (valuep) {
165         *valuep = node->value;
166     } else {
167         free(node->value);
168     }
169
170     hmap_remove(&smap->map, &node->node);
171     free(node);
172 }
173
174 /* Removes all key-value pairs from 'smap'. */
175 void
176 smap_clear(struct smap *smap)
177 {
178     struct smap_node *node, *next;
179
180     SMAP_FOR_EACH_SAFE (node, next, smap) {
181         smap_remove_node(smap, node);
182     }
183 }
184
185 /* Returns the value associated with 'key' in 'smap', or NULL. */
186 const char *
187 smap_get(const struct smap *smap, const char *key)
188 {
189     struct smap_node *node = smap_get_node(smap, key);
190     return node ? node->value : NULL;
191 }
192
193 /* Returns the node associated with 'key' in 'smap', or NULL. */
194 struct smap_node *
195 smap_get_node(const struct smap *smap, const char *key)
196 {
197     size_t key_len = strlen(key);
198     return smap_find__(smap, key, key_len, hash_bytes(key, key_len, 0));
199 }
200
201 /* Gets the value associated with 'key' in 'smap' and converts it to a boolean.
202  * If 'key' is not in 'smap', or its value is neither "true" nor "false",
203  * returns 'def'. */
204 bool
205 smap_get_bool(const struct smap *smap, const char *key, bool def)
206 {
207     const char *value = smap_get(smap, key);
208
209     if (!value) {
210         return def;
211     }
212
213     if (def) {
214         return strcasecmp("false", value) != 0;
215     } else {
216         return !strcasecmp("true", value);
217     }
218 }
219
220 /* Gets the value associated with 'key' in 'smap' and converts it to an int
221  * using atoi().  If 'key' is not in 'smap', returns 'def'. */
222 int
223 smap_get_int(const struct smap *smap, const char *key, int def)
224 {
225     const char *value = smap_get(smap, key);
226
227     return value ? atoi(value) : def;
228 }
229
230 /* Gets the value associated with 'key' in 'smap' and converts it to a UUID
231  * using uuid_from_string().  Returns true if successful, false if 'key' is not
232  * in 'smap' or if 'key' does not have the correct syntax for a UUID. */
233 bool
234 smap_get_uuid(const struct smap *smap, const char *key, struct uuid *uuid)
235 {
236     const char *value = smap_get(smap, key);
237     return value && uuid_from_string(uuid, value);
238 }
239
240 /* Returns true of there are no elements in 'smap'. */
241 bool
242 smap_is_empty(const struct smap *smap)
243 {
244     return hmap_is_empty(&smap->map);
245 }
246
247 /* Returns the number of elements in 'smap'. */
248 size_t
249 smap_count(const struct smap *smap)
250 {
251     return hmap_count(&smap->map);
252 }
253
254 /* Initializes 'dst' as a clone of 'src. */
255 void
256 smap_clone(struct smap *dst, const struct smap *src)
257 {
258     const struct smap_node *node;
259
260     smap_init(dst);
261     SMAP_FOR_EACH (node, src) {
262         smap_add__(dst, xstrdup(node->key), xstrdup(node->value),
263                    node->node.hash);
264     }
265 }
266
267 /* Returns an array of nodes sorted on key or NULL if 'smap' is empty.  The
268  * caller is responsible for freeing this array. */
269 const struct smap_node **
270 smap_sort(const struct smap *smap)
271 {
272     if (smap_is_empty(smap)) {
273         return NULL;
274     } else {
275         const struct smap_node **nodes;
276         struct smap_node *node;
277         size_t i, n;
278
279         n = smap_count(smap);
280         nodes = xmalloc(n * sizeof *nodes);
281         i = 0;
282         SMAP_FOR_EACH (node, smap) {
283             nodes[i++] = node;
284         }
285         ovs_assert(i == n);
286
287         qsort(nodes, n, sizeof *nodes, compare_nodes_by_key);
288
289         return nodes;
290     }
291 }
292
293 /* Adds each of the key-value pairs from 'json' (which must be a JSON object
294  * whose values are strings) to 'smap'.
295  *
296  * The caller must have initialized 'smap'.
297  *
298  * The caller retains ownership of 'json' and everything in it. */
299 void
300 smap_from_json(struct smap *smap, const struct json *json)
301 {
302     const struct shash_node *node;
303
304     SHASH_FOR_EACH (node, json_object(json)) {
305         const struct json *value = node->data;
306         smap_add(smap, node->name, json_string(value));
307     }
308 }
309
310 /* Returns a JSON object that maps from the keys in 'smap' to their values.
311  *
312  * The caller owns the returned value and must eventually json_destroy() it.
313  *
314  * The caller retains ownership of 'smap' and everything in it. */
315 struct json *
316 smap_to_json(const struct smap *smap)
317 {
318     const struct smap_node *node;
319     struct json *json;
320
321     json = json_object_create();
322     SMAP_FOR_EACH (node, smap) {
323         json_object_put_string(json, node->key, node->value);
324     }
325     return json;
326 }
327
328 /* Returns true if the two maps are equal, meaning that they have the same set
329  * of key-value pairs.
330  */
331 bool
332 smap_equal(const struct smap *smap1, const struct smap *smap2)
333 {
334     if (smap_count(smap1) != smap_count(smap2)) {
335         return false;
336     }
337
338     const struct smap_node *node;
339     SMAP_FOR_EACH (node, smap1) {
340         const char *value2 = smap_get(smap2, node->key);
341         if (!value2 || strcmp(node->value, value2)) {
342             return false;
343         }
344     }
345     return true;
346 }
347 \f
348 /* Private Helpers. */
349
350 static struct smap_node *
351 smap_add__(struct smap *smap, char *key, void *value, size_t hash)
352 {
353     struct smap_node *node = xmalloc(sizeof *node);
354     node->key = key;
355     node->value = value;
356     hmap_insert(&smap->map, &node->node, hash);
357     return node;
358 }
359
360 static struct smap_node *
361 smap_find__(const struct smap *smap, const char *key, size_t key_len,
362             size_t hash)
363 {
364     struct smap_node *node;
365
366     HMAP_FOR_EACH_WITH_HASH (node, node, hash, &smap->map) {
367         if (!strncmp(node->key, key, key_len) && !node->key[key_len]) {
368             return node;
369         }
370     }
371
372     return NULL;
373 }
374
375 static int
376 compare_nodes_by_key(const void *a_, const void *b_)
377 {
378     const struct smap_node *const *a = a_;
379     const struct smap_node *const *b = b_;
380     return strcmp((*a)->key, (*b)->key);
381 }