1 /* Copyright (c) 2000-2007 by Nicolas Devillard.
2 * Copyright (x) 2009 by Tim Post <tinkertim@gmail.com>
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
24 /** @addtogroup ciniparser
29 * @author N. Devillard
31 * @version $Revision: 1.27 $
32 * @brief Implements a dictionary for string variables.
34 * This module implements a simple dictionary object, i.e. a list
35 * of string/string associations. This object is useful to store e.g.
36 * information retrieved from a configuration file (ini files).
39 #include "dictionary.h"
46 /** Maximum value size for integers and doubles. */
49 /** Minimal allocated number of entries in a dictionary */
52 /** Invalid key token */
53 #define DICT_INVALID_KEY ((char*)-1)
56 * @brief Double the allocated size associated to a pointer
57 * @param size the current allocated size
58 * @return re-allocated pointer on success, NULL on failure
60 static void *mem_double(void *ptr, int size)
64 newptr = calloc(2 * size, 1);
68 memcpy(newptr, ptr, size);
73 /* The remaining exposed functions are documented in dictionary.h */
75 unsigned dictionary_hash(char *key)
82 for (hash = 0, i = 0; i < len; i++) {
83 hash += (unsigned) key[i];
93 dictionary *dictionary_new(int size)
97 /* If no size was specified, allocate space for DICTMINSZ */
98 if (size<DICTMINSZ) size=DICTMINSZ;
100 if (!(d = (dictionary *) calloc(1, sizeof(dictionary)))) {
104 d->val = (char **) calloc(size, sizeof(char *));
105 d->key = (char **) calloc(size, sizeof(char *));
106 d->hash = (unsigned int *) calloc(size, sizeof(unsigned));
110 void dictionary_del(dictionary *d)
116 for (i = 0; i < d->size; i++) {
117 if (d->key[i] != NULL)
119 if (d->val[i] != NULL)
129 char *dictionary_get(dictionary *d, char *key, char *def)
134 hash = dictionary_hash(key);
135 for (i=0; i < d->size; i++) {
136 if (d->key[i] == NULL)
139 if (hash == d->hash[i]) {
140 /* Compare string, to avoid hash collisions */
141 if (!strcmp(key, d->key[i])) {
149 int dictionary_set(dictionary *d, char *key, char *val)
154 if (d==NULL || key==NULL)
157 /* Compute hash for this key */
158 hash = dictionary_hash(key);
159 /* Find if value is already in dictionary */
161 for (i = 0; i < d->size; i++) {
162 if (d->key[i] == NULL)
164 /* Same hash value */
165 if (hash == d->hash[i]) {
167 if (!strcmp(key, d->key[i])) {
168 /* Found a value: modify and return */
169 if (d->val[i] != NULL)
171 d->val[i] = val ? strdup(val) : NULL;
172 /* Value has been modified: return */
180 * See if dictionary needs to grow */
181 if (d->n == d->size) {
182 /* Reached maximum size: reallocate dictionary */
183 d->val = (char **) mem_double(d->val, d->size * sizeof(char *));
184 d->key = (char **) mem_double(d->key, d->size * sizeof(char *));
185 d->hash = (unsigned int *)
186 mem_double(d->hash, d->size * sizeof(unsigned));
187 if ((d->val == NULL) || (d->key == NULL) || (d->hash == NULL))
188 /* Cannot grow dictionary */
194 /* Insert key in the first empty slot */
195 for (i = 0; i < d->size; i++) {
196 if (d->key[i] == NULL) {
202 d->key[i] = strdup(key);
203 d->val[i] = val ? strdup(val) : NULL;
209 void dictionary_unset(dictionary *d, char *key)
217 hash = dictionary_hash(key);
218 for (i = 0; i < d->size; i++) {
219 if (d->key[i] == NULL)
222 if (hash == d->hash[i]) {
223 /* Compare string, to avoid hash collisions */
224 if (!strcmp(key, d->key[i])) {
236 if (d->val[i]!=NULL) {
245 void dictionary_dump(dictionary *d, FILE *out)
249 if (d == NULL || out == NULL)
252 fprintf(out, "empty dictionary\n");
255 for (i = 0; i < d->size; i++) {
257 fprintf(out, "%20s\t[%s]\n",
259 d->val[i] ? d->val[i] : "UNDEF");