]> git.proxmox.com Git - mirror_ovs.git/blame - lib/smap.c
netdev-linux, netdev-bsd: Make access to AF_INET socket thread-safe.
[mirror_ovs.git] / lib / smap.c
CommitLineData
79f1cbe9
EJ
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
edefaa2e
YT
18#include <strings.h>
19
79f1cbe9 20#include "hash.h"
cccc1356 21#include "json.h"
79f1cbe9
EJ
22
23static struct smap_node *smap_add__(struct smap *, char *, void *,
24 size_t hash);
25static struct smap_node *smap_find__(const struct smap *, const char *key,
26 size_t key_len, size_t hash);
27static int compare_nodes_by_key(const void *, const void *);
28\f
29/* Public Functions. */
30
31void
32smap_init(struct smap *smap)
33{
34 hmap_init(&smap->map);
35}
36
37void
38smap_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. */
48struct smap_node *
49smap_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. */
59bool
60smap_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. */
72void
73smap_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'. */
90void
91smap_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. */
108void
109smap_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'. */
119void
120smap_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
57c8677b
BP
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. */
133void
134smap_steal(struct smap *smap, struct smap_node *node,
135 char **keyp, char **valuep)
51c82a49 136{
57c8677b
BP
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 }
51c82a49
BP
148
149 hmap_remove(&smap->map, &node->node);
150 free(node);
51c82a49
BP
151}
152
79f1cbe9
EJ
153/* Removes all key-value pairs from 'smap'. */
154void
155smap_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. */
165const char *
166smap_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. */
173struct smap_node *
174smap_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'. */
183bool
184smap_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'. */
201int
202smap_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'. */
210bool
211smap_is_empty(const struct smap *smap)
212{
213 return hmap_is_empty(&smap->map);
214}
215
216/* Returns the number of elements in 'smap'. */
217size_t
218smap_count(const struct smap *smap)
219{
220 return hmap_count(&smap->map);
221}
222
223/* Initializes 'dst' as a clone of 'src. */
224void
4512aaa7 225smap_clone(struct smap *dst, const struct smap *src)
79f1cbe9 226{
4512aaa7 227 const struct smap_node *node;
79f1cbe9
EJ
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. */
238const struct smap_node **
239smap_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 }
cb22974d 254 ovs_assert(i == n);
79f1cbe9
EJ
255
256 qsort(nodes, n, sizeof *nodes, compare_nodes_by_key);
257
258 return nodes;
259 }
260}
cccc1356
BP
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. */
268void
269smap_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. */
284struct json *
285smap_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}
79f1cbe9
EJ
296\f
297/* Private Helpers. */
298
299static struct smap_node *
300smap_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
309static struct smap_node *
310smap_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
324static int
325compare_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}