Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Rubberduckycooly
GitHub Repository: Rubberduckycooly/RSDKv5-Decompilation
Path: blob/master/dependencies/all/iniparser/dictionary.cpp
774 views
1
/*-------------------------------------------------------------------------*/
2
/**
3
@file dictionary.c
4
@author N. Devillard
5
@brief Implements a dictionary for string variables.
6
7
This module implements a simple dictionary object, i.e. a list
8
of string/string associations. This object is useful to store e.g.
9
informations retrieved from a configuration file (ini files).
10
*/
11
/*--------------------------------------------------------------------------*/
12
13
/*---------------------------------------------------------------------------
14
Includes
15
---------------------------------------------------------------------------*/
16
#include "dictionary.h"
17
18
#include <stdio.h>
19
#include <stdlib.h>
20
#include <string.h>
21
#ifndef _MSC_VER
22
#include <unistd.h>
23
#else
24
25
#ifdef _WIN64
26
#define ssize_t __int64
27
#else
28
#define ssize_t long
29
#endif
30
31
#endif
32
33
/** Maximum value size for integers and doubles. */
34
#define MAXVALSZ 1024
35
36
/** Minimal allocated number of entries in a dictionary */
37
#define DICTMINSZ 128
38
39
/** Invalid key token */
40
#define DICT_INVALID_KEY ((char*)-1)
41
42
/*---------------------------------------------------------------------------
43
Private functions
44
---------------------------------------------------------------------------*/
45
46
/*-------------------------------------------------------------------------*/
47
/**
48
@brief Duplicate a string
49
@param s String to duplicate
50
@return Pointer to a newly allocated string, to be freed with free()
51
52
This is a replacement for strdup(). This implementation is provided
53
for systems that do not have it.
54
*/
55
/*--------------------------------------------------------------------------*/
56
static char * xstrdup(const char * s)
57
{
58
char * t ;
59
size_t len ;
60
if (!s)
61
return NULL ;
62
63
len = strlen(s) + 1 ;
64
t = (char*) malloc(len) ;
65
if (t) {
66
memcpy(t, s, len) ;
67
}
68
return t ;
69
}
70
71
/*-------------------------------------------------------------------------*/
72
/**
73
@brief Double the size of the dictionary
74
@param d Dictionary to grow
75
@return This function returns non-zero in case of failure
76
*/
77
/*--------------------------------------------------------------------------*/
78
static int dictionary_grow(dictionary * d)
79
{
80
char ** new_val ;
81
char ** new_key ;
82
unsigned * new_hash ;
83
84
new_val = (char**) calloc(d->size * 2, sizeof *d->val);
85
new_key = (char**) calloc(d->size * 2, sizeof *d->key);
86
new_hash = (unsigned*) calloc(d->size * 2, sizeof *d->hash);
87
if (!new_val || !new_key || !new_hash) {
88
/* An allocation failed, leave the dictionary unchanged */
89
if (new_val)
90
free(new_val);
91
if (new_key)
92
free(new_key);
93
if (new_hash)
94
free(new_hash);
95
return -1 ;
96
}
97
/* Initialize the newly allocated space */
98
memcpy(new_val, d->val, d->size * sizeof(char *));
99
memcpy(new_key, d->key, d->size * sizeof(char *));
100
memcpy(new_hash, d->hash, d->size * sizeof(unsigned));
101
/* Delete previous data */
102
free(d->val);
103
free(d->key);
104
free(d->hash);
105
/* Actually update the dictionary */
106
d->size *= 2 ;
107
d->val = new_val;
108
d->key = new_key;
109
d->hash = new_hash;
110
return 0 ;
111
}
112
113
/*---------------------------------------------------------------------------
114
Function codes
115
---------------------------------------------------------------------------*/
116
/*-------------------------------------------------------------------------*/
117
/**
118
@brief Compute the hash key for a string.
119
@param key Character string to use for key.
120
@return 1 unsigned int on at least 32 bits.
121
122
This hash function has been taken from an Article in Dr Dobbs Journal.
123
This is normally a collision-free function, distributing keys evenly.
124
The key is stored anyway in the struct so that collision can be avoided
125
by comparing the key itself in last resort.
126
*/
127
/*--------------------------------------------------------------------------*/
128
unsigned dictionary_hash(const char * key)
129
{
130
size_t len ;
131
unsigned hash ;
132
size_t i ;
133
134
if (!key)
135
return 0 ;
136
137
len = strlen(key);
138
for (hash=0, i=0 ; i<len ; i++) {
139
hash += (unsigned)key[i] ;
140
hash += (hash<<10);
141
hash ^= (hash>>6) ;
142
}
143
hash += (hash <<3);
144
hash ^= (hash >>11);
145
hash += (hash <<15);
146
return hash ;
147
}
148
149
/*-------------------------------------------------------------------------*/
150
/**
151
@brief Create a new dictionary object.
152
@param size Optional initial size of the dictionary.
153
@return 1 newly allocated dictionary objet.
154
155
This function allocates a new dictionary object of given size and returns
156
it. If you do not know in advance (roughly) the number of entries in the
157
dictionary, give size=0.
158
*/
159
/*-------------------------------------------------------------------------*/
160
dictionary * dictionary_new(size_t size)
161
{
162
dictionary * d ;
163
164
/* If no size was specified, allocate space for DICTMINSZ */
165
if (size<DICTMINSZ) size=DICTMINSZ ;
166
167
d = (dictionary*) calloc(1, sizeof *d) ;
168
169
if (d) {
170
d->size = size ;
171
d->val = (char**) calloc(size, sizeof *d->val);
172
d->key = (char**) calloc(size, sizeof *d->key);
173
d->hash = (unsigned*) calloc(size, sizeof *d->hash);
174
}
175
return d ;
176
}
177
178
void dictionary_del(dictionary * d)
179
{
180
ssize_t i ;
181
182
if (d==NULL) return ;
183
for (i=0 ; i<d->size ; i++) {
184
if (d->key[i]!=NULL)
185
free(d->key[i]);
186
if (d->val[i]!=NULL)
187
free(d->val[i]);
188
}
189
free(d->val);
190
free(d->key);
191
free(d->hash);
192
free(d);
193
return ;
194
}
195
196
const char * dictionary_get(const dictionary * d, const char * key, const char * def)
197
{
198
unsigned hash ;
199
ssize_t i ;
200
201
hash = dictionary_hash(key);
202
for (i=0 ; i<d->size ; i++) {
203
if (d->key[i]==NULL)
204
continue ;
205
/* Compare hash */
206
if (hash==d->hash[i]) {
207
/* Compare string, to avoid hash collisions */
208
if (!strcmp(key, d->key[i])) {
209
return d->val[i] ;
210
}
211
}
212
}
213
return def ;
214
}
215
216
int dictionary_set(dictionary * d, const char * key, const char * val)
217
{
218
ssize_t i ;
219
unsigned hash ;
220
221
if (d==NULL || key==NULL) return -1 ;
222
223
/* Compute hash for this key */
224
hash = dictionary_hash(key) ;
225
/* Find if value is already in dictionary */
226
if (d->n>0) {
227
for (i=0 ; i<d->size ; i++) {
228
if (d->key[i]==NULL)
229
continue ;
230
if (hash==d->hash[i]) { /* Same hash value */
231
if (!strcmp(key, d->key[i])) { /* Same key */
232
/* Found a value: modify and return */
233
if (d->val[i]!=NULL)
234
free(d->val[i]);
235
d->val[i] = (val ? xstrdup(val) : NULL);
236
/* Value has been modified: return */
237
return 0 ;
238
}
239
}
240
}
241
}
242
/* Add a new value */
243
/* See if dictionary needs to grow */
244
if (d->n==d->size) {
245
/* Reached maximum size: reallocate dictionary */
246
if (dictionary_grow(d) != 0)
247
return -1;
248
}
249
250
/* Insert key in the first empty slot. Start at d->n and wrap at
251
d->size. Because d->n < d->size this will necessarily
252
terminate. */
253
for (i=d->n ; d->key[i] ; ) {
254
if(++i == d->size) i = 0;
255
}
256
/* Copy key */
257
d->key[i] = xstrdup(key);
258
d->val[i] = (val ? xstrdup(val) : NULL) ;
259
d->hash[i] = hash;
260
d->n ++ ;
261
return 0 ;
262
}
263
264
void dictionary_unset(dictionary * d, const char * key)
265
{
266
unsigned hash ;
267
ssize_t i ;
268
269
if (key == NULL || d == NULL) {
270
return;
271
}
272
273
hash = dictionary_hash(key);
274
for (i=0 ; i<d->size ; i++) {
275
if (d->key[i]==NULL)
276
continue ;
277
/* Compare hash */
278
if (hash==d->hash[i]) {
279
/* Compare string, to avoid hash collisions */
280
if (!strcmp(key, d->key[i])) {
281
/* Found key */
282
break ;
283
}
284
}
285
}
286
if (i>=d->size)
287
/* Key not found */
288
return ;
289
290
free(d->key[i]);
291
d->key[i] = NULL ;
292
if (d->val[i]!=NULL) {
293
free(d->val[i]);
294
d->val[i] = NULL ;
295
}
296
d->hash[i] = 0 ;
297
d->n -- ;
298
return ;
299
}
300
301
void dictionary_dump(const dictionary * d, FILE * out)
302
{
303
ssize_t i ;
304
305
if (d==NULL || out==NULL) return ;
306
if (d->n<1) {
307
fprintf(out, "empty dictionary\n");
308
return ;
309
}
310
for (i=0 ; i<d->size ; i++) {
311
if (d->key[i]) {
312
fprintf(out, "%20s\t[%s]\n",
313
d->key[i],
314
d->val[i] ? d->val[i] : "UNDEF");
315
}
316
}
317
return ;
318
}
319