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