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