1 /*-------------------------------------------------------------------------*/
6 @version $Revision: 1.27 $
7 @brief Implements a dictionary for string variables.
9 This module implements a simple dictionary object, i.e. a list
10 of string/string associations. This object is useful to store e.g.
11 informations retrieved from a configuration file (ini files).
13 /*--------------------------------------------------------------------------*/
16 $Id: dictionary.c,v 1.27 2007-11-23 21:39:18 ndevilla Exp $
19 /*---------------------------------------------------------------------------
21 ---------------------------------------------------------------------------*/
22 #include <atalk/dictionary.h>
23 #include <atalk/compat.h>
30 /** Maximum value size for integers and doubles. */
33 /** Minimal allocated number of entries in a dictionary */
36 /** Invalid key token */
37 #define DICT_INVALID_KEY ((char*)-1)
39 /*---------------------------------------------------------------------------
41 ---------------------------------------------------------------------------*/
43 #define MAXKEYSIZE 1024
44 static char *makekey(const char *section, const char *entry)
46 static char buf[MAXKEYSIZE];
48 strlcpy(buf, section, MAXKEYSIZE);
50 strlcat(buf, ":", MAXKEYSIZE);
51 strlcat(buf, entry, MAXKEYSIZE);
57 /* Doubles the allocated size associated to a pointer */
58 /* 'size' is the current allocated size. */
59 static void * mem_double(void * ptr, int size)
63 newptr = calloc(2*size, 1);
67 memcpy(newptr, ptr, size);
72 /*-------------------------------------------------------------------------*/
74 @brief Duplicate a string
75 @param s String to duplicate
76 @return Pointer to a newly allocated string, to be freed with free()
78 This is a replacement for strdup(). This implementation is provided
79 for systems that do not have it.
81 /*--------------------------------------------------------------------------*/
82 static char * xstrdup(char * s)
87 t = malloc(strlen(s)+1) ;
94 /*---------------------------------------------------------------------------
96 ---------------------------------------------------------------------------*/
97 /*-------------------------------------------------------------------------*/
99 @brief Compute the hash key for a string.
100 @param key Character string to use for key.
101 @return 1 unsigned int on at least 32 bits.
103 This hash function has been taken from an Article in Dr Dobbs Journal.
104 This is normally a collision-free function, distributing keys evenly.
105 The key is stored anyway in the struct so that collision can be avoided
106 by comparing the key itself in last resort.
108 /*--------------------------------------------------------------------------*/
109 unsigned dictionary_hash(char * key)
116 for (hash=0, i=0 ; i<len ; i++) {
117 hash += (unsigned)key[i] ;
127 /*-------------------------------------------------------------------------*/
129 @brief Create a new dictionary object.
130 @param size Optional initial size of the dictionary.
131 @return 1 newly allocated dictionary objet.
133 This function allocates a new dictionary object of given size and returns
134 it. If you do not know in advance (roughly) the number of entries in the
135 dictionary, give size=0.
137 /*--------------------------------------------------------------------------*/
138 dictionary * dictionary_new(int size)
142 /* If no size was specified, allocate space for DICTMINSZ */
143 if (size<DICTMINSZ) size=DICTMINSZ ;
145 if (!(d = (dictionary *)calloc(1, sizeof(dictionary)))) {
149 d->val = (char **)calloc(size, sizeof(char*));
150 d->key = (char **)calloc(size, sizeof(char*));
151 d->hash = (unsigned int *)calloc(size, sizeof(unsigned));
155 /*-------------------------------------------------------------------------*/
157 @brief Delete a dictionary object
158 @param d dictionary object to deallocate.
161 Deallocate a dictionary object and all memory associated to it.
163 /*--------------------------------------------------------------------------*/
164 void dictionary_del(dictionary * d)
168 if (d==NULL) return ;
169 for (i=0 ; i<d->size ; i++) {
182 /*-------------------------------------------------------------------------*/
184 @brief Get a value from a dictionary.
185 @param d dictionary object to search.
186 @param key Key to look for in the dictionary.
187 @param def Default value to return if key not found.
188 @return 1 pointer to internally allocated character string.
190 This function locates a key in a dictionary and returns a pointer to its
191 value, or the passed 'def' pointer if no such key can be found in
192 dictionary. The returned character pointer points to data internal to the
193 dictionary object, you should not try to free it or modify it.
195 /*--------------------------------------------------------------------------*/
196 char * dictionary_get(dictionary * d, char *section, char * key, char * def)
201 hash = dictionary_hash(makekey(section, key));
202 for (i=0 ; i<d->size ; i++) {
206 if (hash==d->hash[i]) {
207 /* Compare string, to avoid hash collisions */
208 if (!strcmp(makekey(section, key), d->key[i])) {
216 /*-------------------------------------------------------------------------*/
218 @brief Set a value in a dictionary.
219 @param d dictionary object to modify.
220 @param key Key to modify or add.
221 @param val Value to add.
222 @return int 0 if Ok, anything else otherwise
224 If the given key is found in the dictionary, the associated value is
225 replaced by the provided one. If the key cannot be found in the
226 dictionary, it is added to it.
228 It is Ok to provide a NULL value for val, but NULL values for the dictionary
229 or the key are considered as errors: the function will return immediately
232 Notice that if you dictionary_set a variable to NULL, a call to
233 dictionary_get will return a NULL value: the variable will be found, and
234 its value (NULL) is returned. In other words, setting the variable
235 content to NULL is equivalent to deleting the variable from the
236 dictionary. It is not possible (in this implementation) to have a key in
237 the dictionary without value.
239 This function returns non-zero in case of failure.
241 /*--------------------------------------------------------------------------*/
242 int dictionary_set(dictionary * d, char *section, char * key, char * val)
247 if (d==NULL || key==NULL) return -1 ;
249 /* Compute hash for this key */
250 hash = dictionary_hash(makekey(section, key));
251 /* Find if value is already in dictionary */
253 for (i=0 ; i<d->size ; i++) {
256 if (hash==d->hash[i]) { /* Same hash value */
257 if (!strcmp(makekey(section, key), d->key[i])) { /* Same key */
258 /* Found a value: modify and return */
261 d->val[i] = val ? xstrdup(val) : NULL ;
262 /* Value has been modified: return */
268 /* Add a new value */
269 /* See if dictionary needs to grow */
272 /* Reached maximum size: reallocate dictionary */
273 d->val = (char **)mem_double(d->val, d->size * sizeof(char*)) ;
274 d->key = (char **)mem_double(d->key, d->size * sizeof(char*)) ;
275 d->hash = (unsigned int *)mem_double(d->hash, d->size * sizeof(unsigned)) ;
276 if ((d->val==NULL) || (d->key==NULL) || (d->hash==NULL)) {
277 /* Cannot grow dictionary */
284 /* Insert key in the first empty slot */
285 for (i=0 ; i<d->size ; i++) {
286 if (d->key[i]==NULL) {
292 d->key[i] = xstrdup(makekey(section, key));
293 d->val[i] = val ? xstrdup(val) : NULL ;
299 /*-------------------------------------------------------------------------*/
301 @brief Delete a key in a dictionary
302 @param d dictionary object to modify.
303 @param key Key to remove.
306 This function deletes a key in a dictionary. Nothing is done if the
309 /*--------------------------------------------------------------------------*/
310 void dictionary_unset(dictionary * d, char *section, char * key)
319 hash = dictionary_hash(makekey(section, key));
320 for (i=0 ; i<d->size ; i++) {
324 if (hash==d->hash[i]) {
325 /* Compare string, to avoid hash collisions */
326 if (!strcmp(makekey(section, key), d->key[i])) {
338 if (d->val[i]!=NULL) {
347 /*-------------------------------------------------------------------------*/
349 @brief Dump a dictionary to an opened file pointer.
350 @param d Dictionary to dump
351 @param f Opened file pointer.
354 Dumps a dictionary onto an opened file pointer. Key pairs are printed out
355 as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as
356 output file pointers.
358 /*--------------------------------------------------------------------------*/
359 void dictionary_dump(dictionary * d, FILE * out)
363 if (d==NULL || out==NULL) return ;
365 fprintf(out, "empty dictionary\n");
368 for (i=0 ; i<d->size ; i++) {
370 fprintf(out, "%20s\t[%s]\n",
372 d->val[i] ? d->val[i] : "UNDEF");