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