Path: blob/master/dependencies/all/iniparser/dictionary.cpp
774 views
/*-------------------------------------------------------------------------*/1/**2@file dictionary.c3@author N. Devillard4@brief Implements a dictionary for string variables.56This module implements a simple dictionary object, i.e. a list7of string/string associations. This object is useful to store e.g.8informations retrieved from a configuration file (ini files).9*/10/*--------------------------------------------------------------------------*/1112/*---------------------------------------------------------------------------13Includes14---------------------------------------------------------------------------*/15#include "dictionary.h"1617#include <stdio.h>18#include <stdlib.h>19#include <string.h>20#ifndef _MSC_VER21#include <unistd.h>22#else2324#ifdef _WIN6425#define ssize_t __int6426#else27#define ssize_t long28#endif2930#endif3132/** Maximum value size for integers and doubles. */33#define MAXVALSZ 10243435/** Minimal allocated number of entries in a dictionary */36#define DICTMINSZ 1283738/** Invalid key token */39#define DICT_INVALID_KEY ((char*)-1)4041/*---------------------------------------------------------------------------42Private functions43---------------------------------------------------------------------------*/4445/*-------------------------------------------------------------------------*/46/**47@brief Duplicate a string48@param s String to duplicate49@return Pointer to a newly allocated string, to be freed with free()5051This is a replacement for strdup(). This implementation is provided52for systems that do not have it.53*/54/*--------------------------------------------------------------------------*/55static char * xstrdup(const char * s)56{57char * t ;58size_t len ;59if (!s)60return NULL ;6162len = strlen(s) + 1 ;63t = (char*) malloc(len) ;64if (t) {65memcpy(t, s, len) ;66}67return t ;68}6970/*-------------------------------------------------------------------------*/71/**72@brief Double the size of the dictionary73@param d Dictionary to grow74@return This function returns non-zero in case of failure75*/76/*--------------------------------------------------------------------------*/77static int dictionary_grow(dictionary * d)78{79char ** new_val ;80char ** new_key ;81unsigned * new_hash ;8283new_val = (char**) calloc(d->size * 2, sizeof *d->val);84new_key = (char**) calloc(d->size * 2, sizeof *d->key);85new_hash = (unsigned*) calloc(d->size * 2, sizeof *d->hash);86if (!new_val || !new_key || !new_hash) {87/* An allocation failed, leave the dictionary unchanged */88if (new_val)89free(new_val);90if (new_key)91free(new_key);92if (new_hash)93free(new_hash);94return -1 ;95}96/* Initialize the newly allocated space */97memcpy(new_val, d->val, d->size * sizeof(char *));98memcpy(new_key, d->key, d->size * sizeof(char *));99memcpy(new_hash, d->hash, d->size * sizeof(unsigned));100/* Delete previous data */101free(d->val);102free(d->key);103free(d->hash);104/* Actually update the dictionary */105d->size *= 2 ;106d->val = new_val;107d->key = new_key;108d->hash = new_hash;109return 0 ;110}111112/*---------------------------------------------------------------------------113Function codes114---------------------------------------------------------------------------*/115/*-------------------------------------------------------------------------*/116/**117@brief Compute the hash key for a string.118@param key Character string to use for key.119@return 1 unsigned int on at least 32 bits.120121This hash function has been taken from an Article in Dr Dobbs Journal.122This is normally a collision-free function, distributing keys evenly.123The key is stored anyway in the struct so that collision can be avoided124by comparing the key itself in last resort.125*/126/*--------------------------------------------------------------------------*/127unsigned dictionary_hash(const char * key)128{129size_t len ;130unsigned hash ;131size_t i ;132133if (!key)134return 0 ;135136len = strlen(key);137for (hash=0, i=0 ; i<len ; i++) {138hash += (unsigned)key[i] ;139hash += (hash<<10);140hash ^= (hash>>6) ;141}142hash += (hash <<3);143hash ^= (hash >>11);144hash += (hash <<15);145return hash ;146}147148/*-------------------------------------------------------------------------*/149/**150@brief Create a new dictionary object.151@param size Optional initial size of the dictionary.152@return 1 newly allocated dictionary objet.153154This function allocates a new dictionary object of given size and returns155it. If you do not know in advance (roughly) the number of entries in the156dictionary, give size=0.157*/158/*-------------------------------------------------------------------------*/159dictionary * dictionary_new(size_t size)160{161dictionary * d ;162163/* If no size was specified, allocate space for DICTMINSZ */164if (size<DICTMINSZ) size=DICTMINSZ ;165166d = (dictionary*) calloc(1, sizeof *d) ;167168if (d) {169d->size = size ;170d->val = (char**) calloc(size, sizeof *d->val);171d->key = (char**) calloc(size, sizeof *d->key);172d->hash = (unsigned*) calloc(size, sizeof *d->hash);173}174return d ;175}176177void dictionary_del(dictionary * d)178{179ssize_t i ;180181if (d==NULL) return ;182for (i=0 ; i<d->size ; i++) {183if (d->key[i]!=NULL)184free(d->key[i]);185if (d->val[i]!=NULL)186free(d->val[i]);187}188free(d->val);189free(d->key);190free(d->hash);191free(d);192return ;193}194195const char * dictionary_get(const dictionary * d, const char * key, const char * def)196{197unsigned hash ;198ssize_t i ;199200hash = dictionary_hash(key);201for (i=0 ; i<d->size ; i++) {202if (d->key[i]==NULL)203continue ;204/* Compare hash */205if (hash==d->hash[i]) {206/* Compare string, to avoid hash collisions */207if (!strcmp(key, d->key[i])) {208return d->val[i] ;209}210}211}212return def ;213}214215int dictionary_set(dictionary * d, const char * key, const char * val)216{217ssize_t i ;218unsigned hash ;219220if (d==NULL || key==NULL) return -1 ;221222/* Compute hash for this key */223hash = dictionary_hash(key) ;224/* Find if value is already in dictionary */225if (d->n>0) {226for (i=0 ; i<d->size ; i++) {227if (d->key[i]==NULL)228continue ;229if (hash==d->hash[i]) { /* Same hash value */230if (!strcmp(key, d->key[i])) { /* Same key */231/* Found a value: modify and return */232if (d->val[i]!=NULL)233free(d->val[i]);234d->val[i] = (val ? xstrdup(val) : NULL);235/* Value has been modified: return */236return 0 ;237}238}239}240}241/* Add a new value */242/* See if dictionary needs to grow */243if (d->n==d->size) {244/* Reached maximum size: reallocate dictionary */245if (dictionary_grow(d) != 0)246return -1;247}248249/* Insert key in the first empty slot. Start at d->n and wrap at250d->size. Because d->n < d->size this will necessarily251terminate. */252for (i=d->n ; d->key[i] ; ) {253if(++i == d->size) i = 0;254}255/* Copy key */256d->key[i] = xstrdup(key);257d->val[i] = (val ? xstrdup(val) : NULL) ;258d->hash[i] = hash;259d->n ++ ;260return 0 ;261}262263void dictionary_unset(dictionary * d, const char * key)264{265unsigned hash ;266ssize_t i ;267268if (key == NULL || d == NULL) {269return;270}271272hash = dictionary_hash(key);273for (i=0 ; i<d->size ; i++) {274if (d->key[i]==NULL)275continue ;276/* Compare hash */277if (hash==d->hash[i]) {278/* Compare string, to avoid hash collisions */279if (!strcmp(key, d->key[i])) {280/* Found key */281break ;282}283}284}285if (i>=d->size)286/* Key not found */287return ;288289free(d->key[i]);290d->key[i] = NULL ;291if (d->val[i]!=NULL) {292free(d->val[i]);293d->val[i] = NULL ;294}295d->hash[i] = 0 ;296d->n -- ;297return ;298}299300void dictionary_dump(const dictionary * d, FILE * out)301{302ssize_t i ;303304if (d==NULL || out==NULL) return ;305if (d->n<1) {306fprintf(out, "empty dictionary\n");307return ;308}309for (i=0 ; i<d->size ; i++) {310if (d->key[i]) {311fprintf(out, "%20s\t[%s]\n",312d->key[i],313d->val[i] ? d->val[i] : "UNDEF");314}315}316return ;317}318319