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