http://ndevilla.free.fr/iniparser/ Welcome to iniParser -- version 3.1 released 08 Apr 2012 This modules offers parsing of ini files from the C level. See a complete documentation in HTML format, from this directory open the file html/index.html with any HTML-capable browser. Enjoy! N.Devillard Sun Apr 8 16:38:09 CEST 2012
dictionary.c@0:1a9f9f36242e, 2012-09-17 (annotated)
- Committer:
- tobyspark
- Date:
- Mon Sep 17 00:33:09 2012 +0000
- Revision:
- 0:1a9f9f36242e
//#include <unistd.h> // Not required for MBED
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
tobyspark | 0:1a9f9f36242e | 1 | /*-------------------------------------------------------------------------*/ |
tobyspark | 0:1a9f9f36242e | 2 | /** |
tobyspark | 0:1a9f9f36242e | 3 | @file dictionary.c |
tobyspark | 0:1a9f9f36242e | 4 | @author N. Devillard |
tobyspark | 0:1a9f9f36242e | 5 | @brief Implements a dictionary for string variables. |
tobyspark | 0:1a9f9f36242e | 6 | |
tobyspark | 0:1a9f9f36242e | 7 | This module implements a simple dictionary object, i.e. a list |
tobyspark | 0:1a9f9f36242e | 8 | of string/string associations. This object is useful to store e.g. |
tobyspark | 0:1a9f9f36242e | 9 | informations retrieved from a configuration file (ini files). |
tobyspark | 0:1a9f9f36242e | 10 | */ |
tobyspark | 0:1a9f9f36242e | 11 | /*--------------------------------------------------------------------------*/ |
tobyspark | 0:1a9f9f36242e | 12 | |
tobyspark | 0:1a9f9f36242e | 13 | /*--------------------------------------------------------------------------- |
tobyspark | 0:1a9f9f36242e | 14 | Includes |
tobyspark | 0:1a9f9f36242e | 15 | ---------------------------------------------------------------------------*/ |
tobyspark | 0:1a9f9f36242e | 16 | #include "dictionary.h" |
tobyspark | 0:1a9f9f36242e | 17 | |
tobyspark | 0:1a9f9f36242e | 18 | #include <stdio.h> |
tobyspark | 0:1a9f9f36242e | 19 | #include <stdlib.h> |
tobyspark | 0:1a9f9f36242e | 20 | #include <string.h> |
tobyspark | 0:1a9f9f36242e | 21 | //#include <unistd.h> // Not required for MBED |
tobyspark | 0:1a9f9f36242e | 22 | |
tobyspark | 0:1a9f9f36242e | 23 | /** Maximum value size for integers and doubles. */ |
tobyspark | 0:1a9f9f36242e | 24 | #define MAXVALSZ 1024 |
tobyspark | 0:1a9f9f36242e | 25 | |
tobyspark | 0:1a9f9f36242e | 26 | /** Minimal allocated number of entries in a dictionary */ |
tobyspark | 0:1a9f9f36242e | 27 | #define DICTMINSZ 128 |
tobyspark | 0:1a9f9f36242e | 28 | |
tobyspark | 0:1a9f9f36242e | 29 | /** Invalid key token */ |
tobyspark | 0:1a9f9f36242e | 30 | #define DICT_INVALID_KEY ((char*)-1) |
tobyspark | 0:1a9f9f36242e | 31 | |
tobyspark | 0:1a9f9f36242e | 32 | /*--------------------------------------------------------------------------- |
tobyspark | 0:1a9f9f36242e | 33 | Private functions |
tobyspark | 0:1a9f9f36242e | 34 | ---------------------------------------------------------------------------*/ |
tobyspark | 0:1a9f9f36242e | 35 | |
tobyspark | 0:1a9f9f36242e | 36 | /* Doubles the allocated size associated to a pointer */ |
tobyspark | 0:1a9f9f36242e | 37 | /* 'size' is the current allocated size. */ |
tobyspark | 0:1a9f9f36242e | 38 | static void * mem_double(void * ptr, int size) |
tobyspark | 0:1a9f9f36242e | 39 | { |
tobyspark | 0:1a9f9f36242e | 40 | void * newptr ; |
tobyspark | 0:1a9f9f36242e | 41 | |
tobyspark | 0:1a9f9f36242e | 42 | newptr = calloc(2*size, 1); |
tobyspark | 0:1a9f9f36242e | 43 | if (newptr==NULL) { |
tobyspark | 0:1a9f9f36242e | 44 | return NULL ; |
tobyspark | 0:1a9f9f36242e | 45 | } |
tobyspark | 0:1a9f9f36242e | 46 | memcpy(newptr, ptr, size); |
tobyspark | 0:1a9f9f36242e | 47 | free(ptr); |
tobyspark | 0:1a9f9f36242e | 48 | return newptr ; |
tobyspark | 0:1a9f9f36242e | 49 | } |
tobyspark | 0:1a9f9f36242e | 50 | |
tobyspark | 0:1a9f9f36242e | 51 | /*-------------------------------------------------------------------------*/ |
tobyspark | 0:1a9f9f36242e | 52 | /** |
tobyspark | 0:1a9f9f36242e | 53 | @brief Duplicate a string |
tobyspark | 0:1a9f9f36242e | 54 | @param s String to duplicate |
tobyspark | 0:1a9f9f36242e | 55 | @return Pointer to a newly allocated string, to be freed with free() |
tobyspark | 0:1a9f9f36242e | 56 | |
tobyspark | 0:1a9f9f36242e | 57 | This is a replacement for strdup(). This implementation is provided |
tobyspark | 0:1a9f9f36242e | 58 | for systems that do not have it. |
tobyspark | 0:1a9f9f36242e | 59 | */ |
tobyspark | 0:1a9f9f36242e | 60 | /*--------------------------------------------------------------------------*/ |
tobyspark | 0:1a9f9f36242e | 61 | static char * xstrdup(const char * s) |
tobyspark | 0:1a9f9f36242e | 62 | { |
tobyspark | 0:1a9f9f36242e | 63 | char * t ; |
tobyspark | 0:1a9f9f36242e | 64 | if (!s) |
tobyspark | 0:1a9f9f36242e | 65 | return NULL ; |
tobyspark | 0:1a9f9f36242e | 66 | t = (char*)malloc(strlen(s)+1) ; |
tobyspark | 0:1a9f9f36242e | 67 | if (t) { |
tobyspark | 0:1a9f9f36242e | 68 | strcpy(t,s); |
tobyspark | 0:1a9f9f36242e | 69 | } |
tobyspark | 0:1a9f9f36242e | 70 | return t ; |
tobyspark | 0:1a9f9f36242e | 71 | } |
tobyspark | 0:1a9f9f36242e | 72 | |
tobyspark | 0:1a9f9f36242e | 73 | /*--------------------------------------------------------------------------- |
tobyspark | 0:1a9f9f36242e | 74 | Function codes |
tobyspark | 0:1a9f9f36242e | 75 | ---------------------------------------------------------------------------*/ |
tobyspark | 0:1a9f9f36242e | 76 | /*-------------------------------------------------------------------------*/ |
tobyspark | 0:1a9f9f36242e | 77 | /** |
tobyspark | 0:1a9f9f36242e | 78 | @brief Compute the hash key for a string. |
tobyspark | 0:1a9f9f36242e | 79 | @param key Character string to use for key. |
tobyspark | 0:1a9f9f36242e | 80 | @return 1 unsigned int on at least 32 bits. |
tobyspark | 0:1a9f9f36242e | 81 | |
tobyspark | 0:1a9f9f36242e | 82 | This hash function has been taken from an Article in Dr Dobbs Journal. |
tobyspark | 0:1a9f9f36242e | 83 | This is normally a collision-free function, distributing keys evenly. |
tobyspark | 0:1a9f9f36242e | 84 | The key is stored anyway in the struct so that collision can be avoided |
tobyspark | 0:1a9f9f36242e | 85 | by comparing the key itself in last resort. |
tobyspark | 0:1a9f9f36242e | 86 | */ |
tobyspark | 0:1a9f9f36242e | 87 | /*--------------------------------------------------------------------------*/ |
tobyspark | 0:1a9f9f36242e | 88 | unsigned dictionary_hash(const char * key) |
tobyspark | 0:1a9f9f36242e | 89 | { |
tobyspark | 0:1a9f9f36242e | 90 | int len ; |
tobyspark | 0:1a9f9f36242e | 91 | unsigned hash ; |
tobyspark | 0:1a9f9f36242e | 92 | int i ; |
tobyspark | 0:1a9f9f36242e | 93 | |
tobyspark | 0:1a9f9f36242e | 94 | len = strlen(key); |
tobyspark | 0:1a9f9f36242e | 95 | for (hash=0, i=0 ; i<len ; i++) { |
tobyspark | 0:1a9f9f36242e | 96 | hash += (unsigned)key[i] ; |
tobyspark | 0:1a9f9f36242e | 97 | hash += (hash<<10); |
tobyspark | 0:1a9f9f36242e | 98 | hash ^= (hash>>6) ; |
tobyspark | 0:1a9f9f36242e | 99 | } |
tobyspark | 0:1a9f9f36242e | 100 | hash += (hash <<3); |
tobyspark | 0:1a9f9f36242e | 101 | hash ^= (hash >>11); |
tobyspark | 0:1a9f9f36242e | 102 | hash += (hash <<15); |
tobyspark | 0:1a9f9f36242e | 103 | return hash ; |
tobyspark | 0:1a9f9f36242e | 104 | } |
tobyspark | 0:1a9f9f36242e | 105 | |
tobyspark | 0:1a9f9f36242e | 106 | /*-------------------------------------------------------------------------*/ |
tobyspark | 0:1a9f9f36242e | 107 | /** |
tobyspark | 0:1a9f9f36242e | 108 | @brief Create a new dictionary object. |
tobyspark | 0:1a9f9f36242e | 109 | @param size Optional initial size of the dictionary. |
tobyspark | 0:1a9f9f36242e | 110 | @return 1 newly allocated dictionary objet. |
tobyspark | 0:1a9f9f36242e | 111 | |
tobyspark | 0:1a9f9f36242e | 112 | This function allocates a new dictionary object of given size and returns |
tobyspark | 0:1a9f9f36242e | 113 | it. If you do not know in advance (roughly) the number of entries in the |
tobyspark | 0:1a9f9f36242e | 114 | dictionary, give size=0. |
tobyspark | 0:1a9f9f36242e | 115 | */ |
tobyspark | 0:1a9f9f36242e | 116 | /*--------------------------------------------------------------------------*/ |
tobyspark | 0:1a9f9f36242e | 117 | dictionary * dictionary_new(int size) |
tobyspark | 0:1a9f9f36242e | 118 | { |
tobyspark | 0:1a9f9f36242e | 119 | dictionary * d ; |
tobyspark | 0:1a9f9f36242e | 120 | |
tobyspark | 0:1a9f9f36242e | 121 | /* If no size was specified, allocate space for DICTMINSZ */ |
tobyspark | 0:1a9f9f36242e | 122 | if (size<DICTMINSZ) size=DICTMINSZ ; |
tobyspark | 0:1a9f9f36242e | 123 | |
tobyspark | 0:1a9f9f36242e | 124 | if (!(d = (dictionary *)calloc(1, sizeof(dictionary)))) { |
tobyspark | 0:1a9f9f36242e | 125 | return NULL; |
tobyspark | 0:1a9f9f36242e | 126 | } |
tobyspark | 0:1a9f9f36242e | 127 | d->size = size ; |
tobyspark | 0:1a9f9f36242e | 128 | d->val = (char **)calloc(size, sizeof(char*)); |
tobyspark | 0:1a9f9f36242e | 129 | d->key = (char **)calloc(size, sizeof(char*)); |
tobyspark | 0:1a9f9f36242e | 130 | d->hash = (unsigned int *)calloc(size, sizeof(unsigned)); |
tobyspark | 0:1a9f9f36242e | 131 | return d ; |
tobyspark | 0:1a9f9f36242e | 132 | } |
tobyspark | 0:1a9f9f36242e | 133 | |
tobyspark | 0:1a9f9f36242e | 134 | /*-------------------------------------------------------------------------*/ |
tobyspark | 0:1a9f9f36242e | 135 | /** |
tobyspark | 0:1a9f9f36242e | 136 | @brief Delete a dictionary object |
tobyspark | 0:1a9f9f36242e | 137 | @param d dictionary object to deallocate. |
tobyspark | 0:1a9f9f36242e | 138 | @return void |
tobyspark | 0:1a9f9f36242e | 139 | |
tobyspark | 0:1a9f9f36242e | 140 | Deallocate a dictionary object and all memory associated to it. |
tobyspark | 0:1a9f9f36242e | 141 | */ |
tobyspark | 0:1a9f9f36242e | 142 | /*--------------------------------------------------------------------------*/ |
tobyspark | 0:1a9f9f36242e | 143 | void dictionary_del(dictionary * d) |
tobyspark | 0:1a9f9f36242e | 144 | { |
tobyspark | 0:1a9f9f36242e | 145 | int i ; |
tobyspark | 0:1a9f9f36242e | 146 | |
tobyspark | 0:1a9f9f36242e | 147 | if (d==NULL) return ; |
tobyspark | 0:1a9f9f36242e | 148 | for (i=0 ; i<d->size ; i++) { |
tobyspark | 0:1a9f9f36242e | 149 | if (d->key[i]!=NULL) |
tobyspark | 0:1a9f9f36242e | 150 | free(d->key[i]); |
tobyspark | 0:1a9f9f36242e | 151 | if (d->val[i]!=NULL) |
tobyspark | 0:1a9f9f36242e | 152 | free(d->val[i]); |
tobyspark | 0:1a9f9f36242e | 153 | } |
tobyspark | 0:1a9f9f36242e | 154 | free(d->val); |
tobyspark | 0:1a9f9f36242e | 155 | free(d->key); |
tobyspark | 0:1a9f9f36242e | 156 | free(d->hash); |
tobyspark | 0:1a9f9f36242e | 157 | free(d); |
tobyspark | 0:1a9f9f36242e | 158 | return ; |
tobyspark | 0:1a9f9f36242e | 159 | } |
tobyspark | 0:1a9f9f36242e | 160 | |
tobyspark | 0:1a9f9f36242e | 161 | /*-------------------------------------------------------------------------*/ |
tobyspark | 0:1a9f9f36242e | 162 | /** |
tobyspark | 0:1a9f9f36242e | 163 | @brief Get a value from a dictionary. |
tobyspark | 0:1a9f9f36242e | 164 | @param d dictionary object to search. |
tobyspark | 0:1a9f9f36242e | 165 | @param key Key to look for in the dictionary. |
tobyspark | 0:1a9f9f36242e | 166 | @param def Default value to return if key not found. |
tobyspark | 0:1a9f9f36242e | 167 | @return 1 pointer to internally allocated character string. |
tobyspark | 0:1a9f9f36242e | 168 | |
tobyspark | 0:1a9f9f36242e | 169 | This function locates a key in a dictionary and returns a pointer to its |
tobyspark | 0:1a9f9f36242e | 170 | value, or the passed 'def' pointer if no such key can be found in |
tobyspark | 0:1a9f9f36242e | 171 | dictionary. The returned character pointer points to data internal to the |
tobyspark | 0:1a9f9f36242e | 172 | dictionary object, you should not try to free it or modify it. |
tobyspark | 0:1a9f9f36242e | 173 | */ |
tobyspark | 0:1a9f9f36242e | 174 | /*--------------------------------------------------------------------------*/ |
tobyspark | 0:1a9f9f36242e | 175 | char * dictionary_get(dictionary * d, const char * key, char * def) |
tobyspark | 0:1a9f9f36242e | 176 | { |
tobyspark | 0:1a9f9f36242e | 177 | unsigned hash ; |
tobyspark | 0:1a9f9f36242e | 178 | int i ; |
tobyspark | 0:1a9f9f36242e | 179 | |
tobyspark | 0:1a9f9f36242e | 180 | hash = dictionary_hash(key); |
tobyspark | 0:1a9f9f36242e | 181 | for (i=0 ; i<d->size ; i++) { |
tobyspark | 0:1a9f9f36242e | 182 | if (d->key[i]==NULL) |
tobyspark | 0:1a9f9f36242e | 183 | continue ; |
tobyspark | 0:1a9f9f36242e | 184 | /* Compare hash */ |
tobyspark | 0:1a9f9f36242e | 185 | if (hash==d->hash[i]) { |
tobyspark | 0:1a9f9f36242e | 186 | /* Compare string, to avoid hash collisions */ |
tobyspark | 0:1a9f9f36242e | 187 | if (!strcmp(key, d->key[i])) { |
tobyspark | 0:1a9f9f36242e | 188 | return d->val[i] ; |
tobyspark | 0:1a9f9f36242e | 189 | } |
tobyspark | 0:1a9f9f36242e | 190 | } |
tobyspark | 0:1a9f9f36242e | 191 | } |
tobyspark | 0:1a9f9f36242e | 192 | return def ; |
tobyspark | 0:1a9f9f36242e | 193 | } |
tobyspark | 0:1a9f9f36242e | 194 | |
tobyspark | 0:1a9f9f36242e | 195 | /*-------------------------------------------------------------------------*/ |
tobyspark | 0:1a9f9f36242e | 196 | /** |
tobyspark | 0:1a9f9f36242e | 197 | @brief Set a value in a dictionary. |
tobyspark | 0:1a9f9f36242e | 198 | @param d dictionary object to modify. |
tobyspark | 0:1a9f9f36242e | 199 | @param key Key to modify or add. |
tobyspark | 0:1a9f9f36242e | 200 | @param val Value to add. |
tobyspark | 0:1a9f9f36242e | 201 | @return int 0 if Ok, anything else otherwise |
tobyspark | 0:1a9f9f36242e | 202 | |
tobyspark | 0:1a9f9f36242e | 203 | If the given key is found in the dictionary, the associated value is |
tobyspark | 0:1a9f9f36242e | 204 | replaced by the provided one. If the key cannot be found in the |
tobyspark | 0:1a9f9f36242e | 205 | dictionary, it is added to it. |
tobyspark | 0:1a9f9f36242e | 206 | |
tobyspark | 0:1a9f9f36242e | 207 | It is Ok to provide a NULL value for val, but NULL values for the dictionary |
tobyspark | 0:1a9f9f36242e | 208 | or the key are considered as errors: the function will return immediately |
tobyspark | 0:1a9f9f36242e | 209 | in such a case. |
tobyspark | 0:1a9f9f36242e | 210 | |
tobyspark | 0:1a9f9f36242e | 211 | Notice that if you dictionary_set a variable to NULL, a call to |
tobyspark | 0:1a9f9f36242e | 212 | dictionary_get will return a NULL value: the variable will be found, and |
tobyspark | 0:1a9f9f36242e | 213 | its value (NULL) is returned. In other words, setting the variable |
tobyspark | 0:1a9f9f36242e | 214 | content to NULL is equivalent to deleting the variable from the |
tobyspark | 0:1a9f9f36242e | 215 | dictionary. It is not possible (in this implementation) to have a key in |
tobyspark | 0:1a9f9f36242e | 216 | the dictionary without value. |
tobyspark | 0:1a9f9f36242e | 217 | |
tobyspark | 0:1a9f9f36242e | 218 | This function returns non-zero in case of failure. |
tobyspark | 0:1a9f9f36242e | 219 | */ |
tobyspark | 0:1a9f9f36242e | 220 | /*--------------------------------------------------------------------------*/ |
tobyspark | 0:1a9f9f36242e | 221 | int dictionary_set(dictionary * d, const char * key, const char * val) |
tobyspark | 0:1a9f9f36242e | 222 | { |
tobyspark | 0:1a9f9f36242e | 223 | int i ; |
tobyspark | 0:1a9f9f36242e | 224 | unsigned hash ; |
tobyspark | 0:1a9f9f36242e | 225 | |
tobyspark | 0:1a9f9f36242e | 226 | if (d==NULL || key==NULL) return -1 ; |
tobyspark | 0:1a9f9f36242e | 227 | |
tobyspark | 0:1a9f9f36242e | 228 | /* Compute hash for this key */ |
tobyspark | 0:1a9f9f36242e | 229 | hash = dictionary_hash(key) ; |
tobyspark | 0:1a9f9f36242e | 230 | /* Find if value is already in dictionary */ |
tobyspark | 0:1a9f9f36242e | 231 | if (d->n>0) { |
tobyspark | 0:1a9f9f36242e | 232 | for (i=0 ; i<d->size ; i++) { |
tobyspark | 0:1a9f9f36242e | 233 | if (d->key[i]==NULL) |
tobyspark | 0:1a9f9f36242e | 234 | continue ; |
tobyspark | 0:1a9f9f36242e | 235 | if (hash==d->hash[i]) { /* Same hash value */ |
tobyspark | 0:1a9f9f36242e | 236 | if (!strcmp(key, d->key[i])) { /* Same key */ |
tobyspark | 0:1a9f9f36242e | 237 | /* Found a value: modify and return */ |
tobyspark | 0:1a9f9f36242e | 238 | if (d->val[i]!=NULL) |
tobyspark | 0:1a9f9f36242e | 239 | free(d->val[i]); |
tobyspark | 0:1a9f9f36242e | 240 | d->val[i] = val ? xstrdup(val) : NULL ; |
tobyspark | 0:1a9f9f36242e | 241 | /* Value has been modified: return */ |
tobyspark | 0:1a9f9f36242e | 242 | return 0 ; |
tobyspark | 0:1a9f9f36242e | 243 | } |
tobyspark | 0:1a9f9f36242e | 244 | } |
tobyspark | 0:1a9f9f36242e | 245 | } |
tobyspark | 0:1a9f9f36242e | 246 | } |
tobyspark | 0:1a9f9f36242e | 247 | /* Add a new value */ |
tobyspark | 0:1a9f9f36242e | 248 | /* See if dictionary needs to grow */ |
tobyspark | 0:1a9f9f36242e | 249 | if (d->n==d->size) { |
tobyspark | 0:1a9f9f36242e | 250 | |
tobyspark | 0:1a9f9f36242e | 251 | /* Reached maximum size: reallocate dictionary */ |
tobyspark | 0:1a9f9f36242e | 252 | d->val = (char **)mem_double(d->val, d->size * sizeof(char*)) ; |
tobyspark | 0:1a9f9f36242e | 253 | d->key = (char **)mem_double(d->key, d->size * sizeof(char*)) ; |
tobyspark | 0:1a9f9f36242e | 254 | d->hash = (unsigned int *)mem_double(d->hash, d->size * sizeof(unsigned)) ; |
tobyspark | 0:1a9f9f36242e | 255 | if ((d->val==NULL) || (d->key==NULL) || (d->hash==NULL)) { |
tobyspark | 0:1a9f9f36242e | 256 | /* Cannot grow dictionary */ |
tobyspark | 0:1a9f9f36242e | 257 | return -1 ; |
tobyspark | 0:1a9f9f36242e | 258 | } |
tobyspark | 0:1a9f9f36242e | 259 | /* Double size */ |
tobyspark | 0:1a9f9f36242e | 260 | d->size *= 2 ; |
tobyspark | 0:1a9f9f36242e | 261 | } |
tobyspark | 0:1a9f9f36242e | 262 | |
tobyspark | 0:1a9f9f36242e | 263 | /* Insert key in the first empty slot. Start at d->n and wrap at |
tobyspark | 0:1a9f9f36242e | 264 | d->size. Because d->n < d->size this will necessarily |
tobyspark | 0:1a9f9f36242e | 265 | terminate. */ |
tobyspark | 0:1a9f9f36242e | 266 | for (i=d->n ; d->key[i] ; ) { |
tobyspark | 0:1a9f9f36242e | 267 | if(++i == d->size) i = 0; |
tobyspark | 0:1a9f9f36242e | 268 | } |
tobyspark | 0:1a9f9f36242e | 269 | /* Copy key */ |
tobyspark | 0:1a9f9f36242e | 270 | d->key[i] = xstrdup(key); |
tobyspark | 0:1a9f9f36242e | 271 | d->val[i] = val ? xstrdup(val) : NULL ; |
tobyspark | 0:1a9f9f36242e | 272 | d->hash[i] = hash; |
tobyspark | 0:1a9f9f36242e | 273 | d->n ++ ; |
tobyspark | 0:1a9f9f36242e | 274 | return 0 ; |
tobyspark | 0:1a9f9f36242e | 275 | } |
tobyspark | 0:1a9f9f36242e | 276 | |
tobyspark | 0:1a9f9f36242e | 277 | /*-------------------------------------------------------------------------*/ |
tobyspark | 0:1a9f9f36242e | 278 | /** |
tobyspark | 0:1a9f9f36242e | 279 | @brief Delete a key in a dictionary |
tobyspark | 0:1a9f9f36242e | 280 | @param d dictionary object to modify. |
tobyspark | 0:1a9f9f36242e | 281 | @param key Key to remove. |
tobyspark | 0:1a9f9f36242e | 282 | @return void |
tobyspark | 0:1a9f9f36242e | 283 | |
tobyspark | 0:1a9f9f36242e | 284 | This function deletes a key in a dictionary. Nothing is done if the |
tobyspark | 0:1a9f9f36242e | 285 | key cannot be found. |
tobyspark | 0:1a9f9f36242e | 286 | */ |
tobyspark | 0:1a9f9f36242e | 287 | /*--------------------------------------------------------------------------*/ |
tobyspark | 0:1a9f9f36242e | 288 | void dictionary_unset(dictionary * d, const char * key) |
tobyspark | 0:1a9f9f36242e | 289 | { |
tobyspark | 0:1a9f9f36242e | 290 | unsigned hash ; |
tobyspark | 0:1a9f9f36242e | 291 | int i ; |
tobyspark | 0:1a9f9f36242e | 292 | |
tobyspark | 0:1a9f9f36242e | 293 | if (key == NULL) { |
tobyspark | 0:1a9f9f36242e | 294 | return; |
tobyspark | 0:1a9f9f36242e | 295 | } |
tobyspark | 0:1a9f9f36242e | 296 | |
tobyspark | 0:1a9f9f36242e | 297 | hash = dictionary_hash(key); |
tobyspark | 0:1a9f9f36242e | 298 | for (i=0 ; i<d->size ; i++) { |
tobyspark | 0:1a9f9f36242e | 299 | if (d->key[i]==NULL) |
tobyspark | 0:1a9f9f36242e | 300 | continue ; |
tobyspark | 0:1a9f9f36242e | 301 | /* Compare hash */ |
tobyspark | 0:1a9f9f36242e | 302 | if (hash==d->hash[i]) { |
tobyspark | 0:1a9f9f36242e | 303 | /* Compare string, to avoid hash collisions */ |
tobyspark | 0:1a9f9f36242e | 304 | if (!strcmp(key, d->key[i])) { |
tobyspark | 0:1a9f9f36242e | 305 | /* Found key */ |
tobyspark | 0:1a9f9f36242e | 306 | break ; |
tobyspark | 0:1a9f9f36242e | 307 | } |
tobyspark | 0:1a9f9f36242e | 308 | } |
tobyspark | 0:1a9f9f36242e | 309 | } |
tobyspark | 0:1a9f9f36242e | 310 | if (i>=d->size) |
tobyspark | 0:1a9f9f36242e | 311 | /* Key not found */ |
tobyspark | 0:1a9f9f36242e | 312 | return ; |
tobyspark | 0:1a9f9f36242e | 313 | |
tobyspark | 0:1a9f9f36242e | 314 | free(d->key[i]); |
tobyspark | 0:1a9f9f36242e | 315 | d->key[i] = NULL ; |
tobyspark | 0:1a9f9f36242e | 316 | if (d->val[i]!=NULL) { |
tobyspark | 0:1a9f9f36242e | 317 | free(d->val[i]); |
tobyspark | 0:1a9f9f36242e | 318 | d->val[i] = NULL ; |
tobyspark | 0:1a9f9f36242e | 319 | } |
tobyspark | 0:1a9f9f36242e | 320 | d->hash[i] = 0 ; |
tobyspark | 0:1a9f9f36242e | 321 | d->n -- ; |
tobyspark | 0:1a9f9f36242e | 322 | return ; |
tobyspark | 0:1a9f9f36242e | 323 | } |
tobyspark | 0:1a9f9f36242e | 324 | |
tobyspark | 0:1a9f9f36242e | 325 | /*-------------------------------------------------------------------------*/ |
tobyspark | 0:1a9f9f36242e | 326 | /** |
tobyspark | 0:1a9f9f36242e | 327 | @brief Dump a dictionary to an opened file pointer. |
tobyspark | 0:1a9f9f36242e | 328 | @param d Dictionary to dump |
tobyspark | 0:1a9f9f36242e | 329 | @param f Opened file pointer. |
tobyspark | 0:1a9f9f36242e | 330 | @return void |
tobyspark | 0:1a9f9f36242e | 331 | |
tobyspark | 0:1a9f9f36242e | 332 | Dumps a dictionary onto an opened file pointer. Key pairs are printed out |
tobyspark | 0:1a9f9f36242e | 333 | as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as |
tobyspark | 0:1a9f9f36242e | 334 | output file pointers. |
tobyspark | 0:1a9f9f36242e | 335 | */ |
tobyspark | 0:1a9f9f36242e | 336 | /*--------------------------------------------------------------------------*/ |
tobyspark | 0:1a9f9f36242e | 337 | void dictionary_dump(dictionary * d, FILE * out) |
tobyspark | 0:1a9f9f36242e | 338 | { |
tobyspark | 0:1a9f9f36242e | 339 | int i ; |
tobyspark | 0:1a9f9f36242e | 340 | |
tobyspark | 0:1a9f9f36242e | 341 | if (d==NULL || out==NULL) return ; |
tobyspark | 0:1a9f9f36242e | 342 | if (d->n<1) { |
tobyspark | 0:1a9f9f36242e | 343 | fprintf(out, "empty dictionary\n"); |
tobyspark | 0:1a9f9f36242e | 344 | return ; |
tobyspark | 0:1a9f9f36242e | 345 | } |
tobyspark | 0:1a9f9f36242e | 346 | for (i=0 ; i<d->size ; i++) { |
tobyspark | 0:1a9f9f36242e | 347 | if (d->key[i]) { |
tobyspark | 0:1a9f9f36242e | 348 | fprintf(out, "%20s\t[%s]\n", |
tobyspark | 0:1a9f9f36242e | 349 | d->key[i], |
tobyspark | 0:1a9f9f36242e | 350 | d->val[i] ? d->val[i] : "UNDEF"); |
tobyspark | 0:1a9f9f36242e | 351 | } |
tobyspark | 0:1a9f9f36242e | 352 | } |
tobyspark | 0:1a9f9f36242e | 353 | return ; |
tobyspark | 0:1a9f9f36242e | 354 | } |
tobyspark | 0:1a9f9f36242e | 355 | |
tobyspark | 0:1a9f9f36242e | 356 | |
tobyspark | 0:1a9f9f36242e | 357 | /* Test code */ |
tobyspark | 0:1a9f9f36242e | 358 | #ifdef TESTDIC |
tobyspark | 0:1a9f9f36242e | 359 | #define NVALS 20000 |
tobyspark | 0:1a9f9f36242e | 360 | int main(int argc, char *argv[]) |
tobyspark | 0:1a9f9f36242e | 361 | { |
tobyspark | 0:1a9f9f36242e | 362 | dictionary * d ; |
tobyspark | 0:1a9f9f36242e | 363 | char * val ; |
tobyspark | 0:1a9f9f36242e | 364 | int i ; |
tobyspark | 0:1a9f9f36242e | 365 | char cval[90] ; |
tobyspark | 0:1a9f9f36242e | 366 | |
tobyspark | 0:1a9f9f36242e | 367 | /* Allocate dictionary */ |
tobyspark | 0:1a9f9f36242e | 368 | printf("allocating...\n"); |
tobyspark | 0:1a9f9f36242e | 369 | d = dictionary_new(0); |
tobyspark | 0:1a9f9f36242e | 370 | |
tobyspark | 0:1a9f9f36242e | 371 | /* Set values in dictionary */ |
tobyspark | 0:1a9f9f36242e | 372 | printf("setting %d values...\n", NVALS); |
tobyspark | 0:1a9f9f36242e | 373 | for (i=0 ; i<NVALS ; i++) { |
tobyspark | 0:1a9f9f36242e | 374 | sprintf(cval, "%04d", i); |
tobyspark | 0:1a9f9f36242e | 375 | dictionary_set(d, cval, "salut"); |
tobyspark | 0:1a9f9f36242e | 376 | } |
tobyspark | 0:1a9f9f36242e | 377 | printf("getting %d values...\n", NVALS); |
tobyspark | 0:1a9f9f36242e | 378 | for (i=0 ; i<NVALS ; i++) { |
tobyspark | 0:1a9f9f36242e | 379 | sprintf(cval, "%04d", i); |
tobyspark | 0:1a9f9f36242e | 380 | val = dictionary_get(d, cval, DICT_INVALID_KEY); |
tobyspark | 0:1a9f9f36242e | 381 | if (val==DICT_INVALID_KEY) { |
tobyspark | 0:1a9f9f36242e | 382 | printf("cannot get value for key [%s]\n", cval); |
tobyspark | 0:1a9f9f36242e | 383 | } |
tobyspark | 0:1a9f9f36242e | 384 | } |
tobyspark | 0:1a9f9f36242e | 385 | printf("unsetting %d values...\n", NVALS); |
tobyspark | 0:1a9f9f36242e | 386 | for (i=0 ; i<NVALS ; i++) { |
tobyspark | 0:1a9f9f36242e | 387 | sprintf(cval, "%04d", i); |
tobyspark | 0:1a9f9f36242e | 388 | dictionary_unset(d, cval); |
tobyspark | 0:1a9f9f36242e | 389 | } |
tobyspark | 0:1a9f9f36242e | 390 | if (d->n != 0) { |
tobyspark | 0:1a9f9f36242e | 391 | printf("error deleting values\n"); |
tobyspark | 0:1a9f9f36242e | 392 | } |
tobyspark | 0:1a9f9f36242e | 393 | printf("deallocating...\n"); |
tobyspark | 0:1a9f9f36242e | 394 | dictionary_del(d); |
tobyspark | 0:1a9f9f36242e | 395 | return 0 ; |
tobyspark | 0:1a9f9f36242e | 396 | } |
tobyspark | 0:1a9f9f36242e | 397 | #endif |
tobyspark | 0:1a9f9f36242e | 398 | /* vim: set ts=4 et sw=4 tw=75 */ |