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