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 ---------------------------------------------------------------------------*/
24 #endif /* HAVE_CONFIG_H */
26 #include <atalk/dictionary.h>
27 #include <atalk/compat.h>
34 /** Maximum value size for integers and doubles. */
37 /** Minimal allocated number of entries in a dictionary */
40 /** Invalid key token */
41 #define DICT_INVALID_KEY ((char*)-1)
43 /*---------------------------------------------------------------------------
45 ---------------------------------------------------------------------------*/
47 #define MAXKEYSIZE 1024
48 static char *makekey(const char *section, const char *entry)
50 static char buf[MAXKEYSIZE];
52 strlcpy(buf, section, MAXKEYSIZE);
54 strlcat(buf, ":", MAXKEYSIZE);
55 strlcat(buf, entry, MAXKEYSIZE);
61 /* Doubles the allocated size associated to a pointer */
62 /* 'size' is the current allocated size. */
63 static void * mem_double(void * ptr, int size)
67 newptr = calloc(2*size, 1);
71 memcpy(newptr, ptr, size);
76 /*-------------------------------------------------------------------------*/
78 @brief Duplicate a string
79 @param s String to duplicate
80 @return Pointer to a newly allocated string, to be freed with free()
82 This is a replacement for strdup(). This implementation is provided
83 for systems that do not have it.
85 /*--------------------------------------------------------------------------*/
86 static char * xstrdup(char * s)
91 t = malloc(strlen(s)+1) ;
98 /*---------------------------------------------------------------------------
100 ---------------------------------------------------------------------------*/
101 /*-------------------------------------------------------------------------*/
103 @brief Compute the hash key for a string.
104 @param key Character string to use for key.
105 @return 1 unsigned int on at least 32 bits.
107 This hash function has been taken from an Article in Dr Dobbs Journal.
108 This is normally a collision-free function, distributing keys evenly.
109 The key is stored anyway in the struct so that collision can be avoided
110 by comparing the key itself in last resort.
112 /*--------------------------------------------------------------------------*/
113 unsigned dictionary_hash(char * key)
120 for (hash=0, i=0 ; i<len ; i++) {
121 hash += (unsigned)key[i] ;
131 /*-------------------------------------------------------------------------*/
133 @brief Create a new dictionary object.
134 @param size Optional initial size of the dictionary.
135 @return 1 newly allocated dictionary objet.
137 This function allocates a new dictionary object of given size and returns
138 it. If you do not know in advance (roughly) the number of entries in the
139 dictionary, give size=0.
141 /*--------------------------------------------------------------------------*/
142 dictionary * dictionary_new(int size)
146 /* If no size was specified, allocate space for DICTMINSZ */
147 if (size<DICTMINSZ) size=DICTMINSZ ;
149 if (!(d = (dictionary *)calloc(1, sizeof(dictionary)))) {
153 d->val = (char **)calloc(size, sizeof(char*));
154 d->key = (char **)calloc(size, sizeof(char*));
155 d->hash = (unsigned int *)calloc(size, sizeof(unsigned));
159 /*-------------------------------------------------------------------------*/
161 @brief Delete a dictionary object
162 @param d dictionary object to deallocate.
165 Deallocate a dictionary object and all memory associated to it.
167 /*--------------------------------------------------------------------------*/
168 void dictionary_del(dictionary * d)
172 if (d==NULL) return ;
173 for (i=0 ; i<d->size ; i++) {
186 /*-------------------------------------------------------------------------*/
188 @brief Get a value from a dictionary.
189 @param d dictionary object to search.
190 @param key Key to look for in the dictionary.
191 @param def Default value to return if key not found.
192 @return 1 pointer to internally allocated character string.
194 This function locates a key in a dictionary and returns a pointer to its
195 value, or the passed 'def' pointer if no such key can be found in
196 dictionary. The returned character pointer points to data internal to the
197 dictionary object, you should not try to free it or modify it.
199 /*--------------------------------------------------------------------------*/
200 const char * dictionary_get(const dictionary * d, const char *section, const char * key, const char * def)
205 hash = dictionary_hash(makekey(section, key));
206 for (i=0 ; i<d->size ; i++) {
210 if (hash==d->hash[i]) {
211 /* Compare string, to avoid hash collisions */
212 if (!strcmp(makekey(section, key), d->key[i])) {
220 /*-------------------------------------------------------------------------*/
222 @brief Set a value in a dictionary.
223 @param d dictionary object to modify.
224 @param key Key to modify or add.
225 @param val Value to add.
226 @return int 0 if Ok, anything else otherwise
228 If the given key is found in the dictionary, the associated value is
229 replaced by the provided one. If the key cannot be found in the
230 dictionary, it is added to it.
232 It is Ok to provide a NULL value for val, but NULL values for the dictionary
233 or the key are considered as errors: the function will return immediately
236 Notice that if you dictionary_set a variable to NULL, a call to
237 dictionary_get will return a NULL value: the variable will be found, and
238 its value (NULL) is returned. In other words, setting the variable
239 content to NULL is equivalent to deleting the variable from the
240 dictionary. It is not possible (in this implementation) to have a key in
241 the dictionary without value.
243 This function returns non-zero in case of failure.
245 /*--------------------------------------------------------------------------*/
246 int dictionary_set(dictionary * d, char *section, char * key, char * val)
251 if (d==NULL || section==NULL) return -1 ;
253 /* Compute hash for this key */
254 hash = dictionary_hash(makekey(section, key));
255 /* Find if value is already in dictionary */
257 for (i=0 ; i<d->size ; i++) {
260 if (hash==d->hash[i]) { /* Same hash value */
261 if (!strcmp(makekey(section, key), d->key[i])) { /* Same key */
262 /* Found a value: modify and return */
265 d->val[i] = val ? xstrdup(val) : NULL ;
266 /* Value has been modified: return */
272 /* Add a new value */
273 /* See if dictionary needs to grow */
276 /* Reached maximum size: reallocate dictionary */
277 d->val = (char **)mem_double(d->val, d->size * sizeof(char*)) ;
278 d->key = (char **)mem_double(d->key, d->size * sizeof(char*)) ;
279 d->hash = (unsigned int *)mem_double(d->hash, d->size * sizeof(unsigned)) ;
280 if ((d->val==NULL) || (d->key==NULL) || (d->hash==NULL)) {
281 /* Cannot grow dictionary */
288 /* Insert key in the first empty slot */
289 for (i=0 ; i<d->size ; i++) {
290 if (d->key[i]==NULL) {
296 d->key[i] = xstrdup(makekey(section, key));
297 d->val[i] = val ? xstrdup(val) : NULL ;
303 /*-------------------------------------------------------------------------*/
305 @brief Delete a key in a dictionary
306 @param d dictionary object to modify.
307 @param key Key to remove.
310 This function deletes a key in a dictionary. Nothing is done if the
313 /*--------------------------------------------------------------------------*/
314 void dictionary_unset(dictionary * d, char *section, char * key)
323 hash = dictionary_hash(makekey(section, key));
324 for (i=0 ; i<d->size ; i++) {
328 if (hash==d->hash[i]) {
329 /* Compare string, to avoid hash collisions */
330 if (!strcmp(makekey(section, key), d->key[i])) {
342 if (d->val[i]!=NULL) {
351 /*-------------------------------------------------------------------------*/
353 @brief Dump a dictionary to an opened file pointer.
354 @param d Dictionary to dump
355 @param f Opened file pointer.
358 Dumps a dictionary onto an opened file pointer. Key pairs are printed out
359 as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as
360 output file pointers.
362 /*--------------------------------------------------------------------------*/
363 void dictionary_dump(dictionary * d, FILE * out)
367 if (d==NULL || out==NULL) return ;
369 fprintf(out, "empty dictionary\n");
372 for (i=0 ; i<d->size ; i++) {
374 fprintf(out, "%20s\t[%s]\n",
376 d->val[i] ? d->val[i] : "UNDEF");