]> git.proxmox.com Git - ovs.git/blame - lib/smap.c
json: Fix error message for corner case in json_string_unescape().
[ovs.git] / lib / smap.c
CommitLineData
ff929935 1/* Copyright (c) 2012, 2014 Nicira, Inc.
79f1cbe9
EJ
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
ff929935
BP
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. */
59struct smap_node *
60smap_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
79f1cbe9
EJ
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. */
68bool
69smap_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. */
81void
82smap_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'. */
99void
100smap_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. */
117void
118smap_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'. */
128void
129smap_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
57c8677b
BP
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. */
142void
143smap_steal(struct smap *smap, struct smap_node *node,
144 char **keyp, char **valuep)
51c82a49 145{
57c8677b
BP
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 }
51c82a49
BP
157
158 hmap_remove(&smap->map, &node->node);
159 free(node);
51c82a49
BP
160}
161
79f1cbe9
EJ
162/* Removes all key-value pairs from 'smap'. */
163void
164smap_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. */
174const char *
175smap_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. */
182struct smap_node *
183smap_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'. */
192bool
193smap_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'. */
210int
211smap_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'. */
219bool
220smap_is_empty(const struct smap *smap)
221{
222 return hmap_is_empty(&smap->map);
223}
224
225/* Returns the number of elements in 'smap'. */
226size_t
227smap_count(const struct smap *smap)
228{
229 return hmap_count(&smap->map);
230}
231
232/* Initializes 'dst' as a clone of 'src. */
233void
4512aaa7 234smap_clone(struct smap *dst, const struct smap *src)
79f1cbe9 235{
4512aaa7 236 const struct smap_node *node;
79f1cbe9
EJ
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. */
247const struct smap_node **
248smap_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 }
cb22974d 263 ovs_assert(i == n);
79f1cbe9
EJ
264
265 qsort(nodes, n, sizeof *nodes, compare_nodes_by_key);
266
267 return nodes;
268 }
269}
cccc1356
BP
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. */
277void
278smap_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. */
293struct json *
294smap_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}
79f1cbe9
EJ
305\f
306/* Private Helpers. */
307
308static struct smap_node *
309smap_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
318static struct smap_node *
319smap_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
333static int
334compare_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}