Subversion Repositories FlightCtrl

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
56 elmo 1
 
2
/*-------------------------------------------------------------------------*/
3
/**
4
   @file        dictionary.c
5
   @author      N. Devillard
6
   @date        Aug 2000
7
   @version     $Revision: 1.23 $
8
   @brief       Implements a dictionary for string variables.
9
 
10
   This module implements a simple dictionary object, i.e. a list
11
   of string/string associations. This object is useful to store e.g.
12
   informations retrieved from a configuration file (ini files).
13
*/
14
/*--------------------------------------------------------------------------*/
15
 
16
/*
17
        $Id: dictionary.c,v 1.23 2002/06/17 09:30:46 ndevilla Exp $
18
        $Author: ndevilla $
19
        $Date: 2002/06/17 09:30:46 $
20
        $Revision: 1.23 $
21
*/
22
 
23
/*---------------------------------------------------------------------------
24
                                                                Includes
25
 ---------------------------------------------------------------------------*/
26
 
27
#include "dictionary.h"
28
 
29
#include <stdio.h>
30
#include <stdlib.h>
31
#include <string.h>
32
#include <unistd.h>
33
 
34
 
35
/** Maximum value size for integers and doubles. */
36
#define MAXVALSZ        1024
37
 
38
/** Minimal allocated number of entries in a dictionary */
39
#define DICTMINSZ       128
40
 
41
/** Invalid key token */
42
#define DICT_INVALID_KEY    ((char*)-1)
43
 
44
 
45
/*---------------------------------------------------------------------------
46
                                                        Private functions
47
 ---------------------------------------------------------------------------*/
48
 
49
/* Doubles the allocated size associated to a pointer */
50
/* 'size' is the current allocated size. */
51
static void * mem_double(void * ptr, int size)
52
{
53
    void    *   newptr ;
54
 
55
    newptr = calloc(2*size, 1);
56
    memcpy(newptr, ptr, size);
57
    free(ptr);
58
    return newptr ;
59
}
60
 
61
 
62
/*---------------------------------------------------------------------------
63
                                                        Function codes
64
 ---------------------------------------------------------------------------*/
65
 
66
/*-------------------------------------------------------------------------*/
67
/**
68
  @brief        Compute the hash key for a string.
69
  @param        key             Character string to use for key.
70
  @return       1 unsigned int on at least 32 bits.
71
 
72
  This hash function has been taken from an Article in Dr Dobbs Journal.
73
  This is normally a collision-free function, distributing keys evenly.
74
  The key is stored anyway in the struct so that collision can be avoided
75
  by comparing the key itself in last resort.
76
 */
77
/*--------------------------------------------------------------------------*/
78
 
79
unsigned dictionary_hash(char * key)
80
{
81
        int                     len ;
82
        unsigned        hash ;
83
        int                     i ;
84
 
85
        len = strlen(key);
86
        for (hash=0, i=0 ; i<len ; i++) {
87
                hash += (unsigned)key[i] ;
88
                hash += (hash<<10);
89
                hash ^= (hash>>6) ;
90
        }
91
        hash += (hash <<3);
92
        hash ^= (hash >>11);
93
        hash += (hash <<15);
94
        return hash ;
95
}
96
 
97
 
98
/*-------------------------------------------------------------------------*/
99
/**
100
  @brief        Create a new dictionary object.
101
  @param        size    Optional initial size of the dictionary.
102
  @return       1 newly allocated dictionary objet.
103
 
104
  This function allocates a new dictionary object of given size and returns
105
  it. If you do not know in advance (roughly) the number of entries in the
106
  dictionary, give size=0.
107
 */
108
/*--------------------------------------------------------------------------*/
109
 
110
dictionary * dictionary_new(int size)
111
{
112
        dictionary      *       d ;
113
 
114
        /* If no size was specified, allocate space for DICTMINSZ */
115
        if (size<DICTMINSZ) size=DICTMINSZ ;
116
 
117
        if (!(d = (dictionary *)calloc(1, sizeof(dictionary)))) {
118
                return NULL;
119
        }
120
        d->size = size ;
121
        d->val  = (char **)calloc(size, sizeof(char*));
122
        d->key  = (char **)calloc(size, sizeof(char*));
123
        d->hash = (unsigned int *)calloc(size, sizeof(unsigned));
124
        return d ;
125
}
126
 
127
 
128
/*-------------------------------------------------------------------------*/
129
/**
130
  @brief        Delete a dictionary object
131
  @param        d       dictionary object to deallocate.
132
  @return       void
133
 
134
  Deallocate a dictionary object and all memory associated to it.
135
 */
136
/*--------------------------------------------------------------------------*/
137
 
138
void dictionary_del(dictionary * d)
139
{
140
        int             i ;
141
 
142
        if (d==NULL) return ;
143
        for (i=0 ; i<d->size ; i++) {
144
                if (d->key[i]!=NULL)
145
                        free(d->key[i]);
146
                if (d->val[i]!=NULL)
147
                        free(d->val[i]);
148
        }
149
        free(d->val);
150
        free(d->key);
151
        free(d->hash);
152
        free(d);
153
        return ;
154
}
155
 
156
 
157
 
158
/*-------------------------------------------------------------------------*/
159
/**
160
  @brief        Get a value from a dictionary.
161
  @param        d               dictionary object to search.
162
  @param        key             Key to look for in the dictionary.
163
  @param    def     Default value to return if key not found.
164
  @return       1 pointer to internally allocated character string.
165
 
166
  This function locates a key in a dictionary and returns a pointer to its
167
  value, or the passed 'def' pointer if no such key can be found in
168
  dictionary. The returned character pointer points to data internal to the
169
  dictionary object, you should not try to free it or modify it.
170
 */
171
/*--------------------------------------------------------------------------*/
172
char * dictionary_get(dictionary * d, char * key, char * def)
173
{
174
        unsigned        hash ;
175
        int                     i ;
176
 
177
        hash = dictionary_hash(key);
178
        for (i=0 ; i<d->size ; i++) {
179
        if (d->key==NULL)
180
            continue ;
181
        /* Compare hash */
182
                if (hash==d->hash[i]) {
183
            /* Compare string, to avoid hash collisions */
184
            if (!strcmp(key, d->key[i])) {
185
                                return d->val[i] ;
186
                        }
187
                }
188
        }
189
        return def ;
190
}
191
 
192
/*-------------------------------------------------------------------------*/
193
/**
194
  @brief        Get a value from a dictionary, as a char.
195
  @param        d               dictionary object to search.
196
  @param        key             Key to look for in the dictionary.
197
  @param        def             Default value for the key if not found.
198
  @return       char   
199
 
200
  This function locates a key in a dictionary using dictionary_get,
201
  and returns the first char of the found string.
202
 */
203
/*--------------------------------------------------------------------------*/
204
char dictionary_getchar(dictionary * d, char * key, char def)
205
{
206
        char * v ;
207
 
208
        if ((v=dictionary_get(d,key,DICT_INVALID_KEY))==DICT_INVALID_KEY) {
209
                return def ;
210
        } else {
211
                return v[0] ;
212
        }
213
}
214
 
215
 
216
/*-------------------------------------------------------------------------*/
217
/**
218
  @brief        Get a value from a dictionary, as an int.
219
  @param        d               dictionary object to search.
220
  @param        key             Key to look for in the dictionary.
221
  @param        def             Default value for the key if not found.
222
  @return       int
223
 
224
  This function locates a key in a dictionary using dictionary_get,
225
  and applies atoi on it to return an int. If the value cannot be found
226
  in the dictionary, the default is returned.
227
 */
228
/*--------------------------------------------------------------------------*/
229
int dictionary_getint(dictionary * d, char * key, int def)
230
{
231
        char * v ;
232
 
233
        if ((v=dictionary_get(d,key,DICT_INVALID_KEY))==DICT_INVALID_KEY) {
234
                return def ;
235
        } else {
236
                return atoi(v);
237
        }
238
}
239
 
240
/*-------------------------------------------------------------------------*/
241
/**
242
  @brief                Get a value from a dictionary, as a double.
243
  @param        d               dictionary object to search.
244
  @param        key             Key to look for in the dictionary.
245
  @param        def             Default value for the key if not found.
246
  @return       double
247
 
248
  This function locates a key in a dictionary using dictionary_get,
249
  and applies atof on it to return a double. If the value cannot be found
250
  in the dictionary, the default is returned.
251
 */
252
/*--------------------------------------------------------------------------*/
253
double dictionary_getdouble(dictionary * d, char * key, double def)
254
{
255
        char * v ;
256
 
257
        if ((v=dictionary_get(d,key,DICT_INVALID_KEY))==DICT_INVALID_KEY) {
258
                return def ;
259
        } else {
260
                return atof(v);
261
        }
262
}
263
 
264
 
265
/*-------------------------------------------------------------------------*/
266
/**
267
  @brief        Set a value in a dictionary.
268
  @param        d               dictionary object to modify.
269
  @param        key             Key to modify or add.
270
  @param        val     Value to add.
271
  @return       void
272
 
273
  If the given key is found in the dictionary, the associated value is
274
  replaced by the provided one. If the key cannot be found in the
275
  dictionary, it is added to it.
276
 
277
  It is Ok to provide a NULL value for val, but NULL values for the dictionary
278
  or the key are considered as errors: the function will return immediately
279
  in such a case.
280
 
281
  Notice that if you dictionary_set a variable to NULL, a call to
282
  dictionary_get will return a NULL value: the variable will be found, and
283
  its value (NULL) is returned. In other words, setting the variable
284
  content to NULL is equivalent to deleting the variable from the
285
  dictionary. It is not possible (in this implementation) to have a key in
286
  the dictionary without value.
287
 */
288
/*--------------------------------------------------------------------------*/
289
 
290
void dictionary_set(dictionary * d, char * key, char * val)
291
{
292
        int                     i ;
293
        unsigned        hash ;
294
 
295
        if (d==NULL || key==NULL) return ;
296
 
297
        /* Compute hash for this key */
298
        hash = dictionary_hash(key) ;
299
        /* Find if value is already in blackboard */
300
        if (d->n>0) {
301
                for (i=0 ; i<d->size ; i++) {
302
            if (d->key[i]==NULL)
303
                continue ;
304
                        if (hash==d->hash[i]) { /* Same hash value */
305
                                if (!strcmp(key, d->key[i])) {   /* Same key */
306
                                        /* Found a value: modify and return */
307
                                        if (d->val[i]!=NULL)
308
                                                free(d->val[i]);
309
                    d->val[i] = val ? strdup(val) : NULL ;
310
                    /* Value has been modified: return */
311
                                        return ;
312
                                }
313
                        }
314
                }
315
        }
316
        /* Add a new value */
317
        /* See if dictionary needs to grow */
318
        if (d->n==d->size) {
319
 
320
                /* Reached maximum size: reallocate blackboard */
321
                d->val  = (char **)mem_double(d->val,  d->size * sizeof(char*)) ;
322
                d->key  = (char **)mem_double(d->key,  d->size * sizeof(char*)) ;
323
                d->hash = (unsigned int *)mem_double(d->hash, d->size * sizeof(unsigned)) ;
324
 
325
                /* Double size */
326
                d->size *= 2 ;
327
        }
328
 
329
    /* Insert key in the first empty slot */
330
    for (i=0 ; i<d->size ; i++) {
331
        if (d->key[i]==NULL) {
332
            /* Add key here */
333
            break ;
334
        }
335
    }
336
        /* Copy key */
337
        d->key[i]  = strdup(key);
338
    d->val[i]  = val ? strdup(val) : NULL ;
339
        d->hash[i] = hash;
340
        d->n ++ ;
341
        return ;
342
}
343
 
344
/*-------------------------------------------------------------------------*/
345
/**
346
  @brief        Delete a key in a dictionary
347
  @param        d               dictionary object to modify.
348
  @param        key             Key to remove.
349
  @return   void
350
 
351
  This function deletes a key in a dictionary. Nothing is done if the
352
  key cannot be found.
353
 */
354
/*--------------------------------------------------------------------------*/
355
void dictionary_unset(dictionary * d, char * key)
356
{
357
        unsigned        hash ;
358
        int                     i ;
359
 
360
        if (key == NULL) {
361
                return;
362
        }
363
 
364
        hash = dictionary_hash(key);
365
        for (i=0 ; i<d->size ; i++) {
366
        if (d->key[i]==NULL)
367
            continue ;
368
        /* Compare hash */
369
                if (hash==d->hash[i]) {
370
            /* Compare string, to avoid hash collisions */
371
            if (!strcmp(key, d->key[i])) {
372
                /* Found key */
373
                break ;
374
                        }
375
                }
376
        }
377
    if (i>=d->size)
378
        /* Key not found */
379
        return ;
380
 
381
    free(d->key[i]);
382
    d->key[i] = NULL ;
383
    if (d->val[i]!=NULL) {
384
        free(d->val[i]);
385
        d->val[i] = NULL ;
386
    }
387
    d->hash[i] = 0 ;
388
    d->n -- ;
389
    return ;
390
}
391
 
392
 
393
/*-------------------------------------------------------------------------*/
394
/**
395
  @brief        Set a key in a dictionary, providing an int.
396
  @param        d               Dictionary to update.
397
  @param        key             Key to modify or add
398
  @param        val             Integer value to store (will be stored as a string).
399
  @return       void
400
 
401
  This helper function calls dictionary_set() with the provided integer
402
  converted to a string using %d.
403
 */
404
/*--------------------------------------------------------------------------*/
405
 
406
 
407
void dictionary_setint(dictionary * d, char * key, int val)
408
{
409
        char    sval[MAXVALSZ];
410
        sprintf(sval, "%d", val);
411
        dictionary_set(d, key, sval);
412
}
413
 
414
 
415
/*-------------------------------------------------------------------------*/
416
/**
417
  @brief        Set a key in a dictionary, providing a double.
418
  @param        d               Dictionary to update.
419
  @param        key             Key to modify or add
420
  @param        val             Double value to store (will be stored as a string).
421
  @return       void
422
 
423
  This helper function calls dictionary_set() with the provided double
424
  converted to a string using %g.
425
 */
426
/*--------------------------------------------------------------------------*/
427
 
428
 
429
void dictionary_setdouble(dictionary * d, char * key, double val)
430
{
431
        char    sval[MAXVALSZ];
432
        sprintf(sval, "%g", val);
433
        dictionary_set(d, key, sval);
434
}
435
 
436
 
437
 
438
/*-------------------------------------------------------------------------*/
439
/**
440
  @brief        Dump a dictionary to an opened file pointer.
441
  @param        d       Dictionary to dump
442
  @param        f       Opened file pointer.
443
  @return       void
444
 
445
  Dumps a dictionary onto an opened file pointer. Key pairs are printed out
446
  as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as
447
  output file pointers.
448
 */
449
/*--------------------------------------------------------------------------*/
450
 
451
void dictionary_dump(dictionary * d, FILE * out)
452
{
453
        int             i ;
454
 
455
        if (d==NULL || out==NULL) return ;
456
        if (d->n<1) {
457
                fprintf(out, "empty dictionary\n");
458
                return ;
459
        }
460
        for (i=0 ; i<d->size ; i++) {
461
        if (d->key[i]) {
462
            fprintf(out, "%20s\t[%s]\n",
463
                    d->key[i],
464
                    d->val[i] ? d->val[i] : "UNDEF");
465
        }
466
        }
467
        return ;
468
}
469
 
470
 
471
 
472
/* Example code */
473
#ifdef TESTDIC
474
#define NVALS 20000
475
int main(int argc, char *argv[])
476
{
477
        dictionary      *       d ;
478
        char    *       val ;
479
        int                     i ;
480
        char            cval[90] ;
481
 
482
        /* allocate blackboard */
483
        printf("allocating...\n");
484
        d = dictionary_new(0);
485
 
486
        /* Set values in blackboard */
487
        printf("setting %d values...\n", NVALS);
488
        for (i=0 ; i<NVALS ; i++) {
489
                sprintf(cval, "%04d", i);
490
                dictionary_set(d, cval, "salut");
491
        }
492
        printf("getting %d values...\n", NVALS);
493
        for (i=0 ; i<NVALS ; i++) {
494
                sprintf(cval, "%04d", i);
495
                val = dictionary_get(d, cval, DICT_INVALID_KEY);
496
                if (val==DICT_INVALID_KEY) {
497
                        printf("cannot get value for key [%s]\n", cval);
498
                }
499
        }
500
    printf("unsetting %d values...\n", NVALS);
501
        for (i=0 ; i<NVALS ; i++) {
502
                sprintf(cval, "%04d", i);
503
                dictionary_unset(d, cval);
504
        }
505
    if (d->n != 0) {
506
        printf("error deleting values\n");
507
    }
508
 
509
        printf("deallocating...\n");
510
        dictionary_del(d);
511
        return 0 ;
512
}
513
#endif
514
/* vim: set ts=4 et sw=4 tw=75 */