diff --git a/Makefile b/Makefile index 04d333f9081036c666f5d251412b3b820249c675..78708a53288e4366e3a54423e38663c5293e88c6 100644 --- a/Makefile +++ b/Makefile @@ -4,8 +4,13 @@ # Compiler settings CC ?= gcc -CFLAGS ?= -O2 -CFLAGS += -fPIC -Wall -ansi -std=c99 -pedantic + +CFLAGS += -fPIC -Wall -Wextra -ansi -pedantic +ifndef DEBUG +CFLAGS += -O2 +else +CFLAGS += -g +endif # Ar settings to build the library AR ?= ar @@ -57,16 +62,20 @@ libiniparser.so: $(OBJS) clean: $(RM) $(OBJS) + @(cd test ; $(MAKE) clean) veryclean: $(RM) $(OBJS) libiniparser.a libiniparser.so* rm -rf ./html ; mkdir html + cd example ; $(MAKE) veryclean cd test ; $(MAKE) veryclean docs: @(cd doc ; $(MAKE)) -check: default +check: libiniparser.so @(cd test ; $(MAKE)) -.PHONY: default clean veryclean docs check +.PHONY: example +example: libiniparser.a + @(cd example ; $(MAKE)) diff --git a/README b/README deleted file mode 100644 index 6f5d6f5c91696f1671542a79142b2d48588e9ebe..0000000000000000000000000000000000000000 --- a/README +++ /dev/null @@ -1,11 +0,0 @@ - -Welcome to iniParser -- version 3.2 -released 16 May 2015 - -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 diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..d2f781a37f4d75e575065197c1f2d4df3db042d3 --- /dev/null +++ b/README.md @@ -0,0 +1,37 @@ +[![Build Status](https://travis-ci.org/touilleMan/iniparser4.svg?branch=master)](https://travis-ci.org/touilleMan/iniparser4) + +# Iniparser 4 # + + +## I - Overview + +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. + +Key features : + + - Small : around 1500 sloc inside 4 files (2 .c and 2 .h) + - Portable : no dependancies, written in `-ansi -pedantic` C89 + - Fully reintrant : easy to make it thread-safe (just surround + library calls by mutex) + +## II - Building project + +A simple `make` at the root of the project should be enough to get the static +(i.e. `libiniparser.a`) and shared (i.e. `libiniparser.so.0`) libraries compiled. + +You should consider trying the following rules too : + + - `make check` : run the unitary tests + - `make example` : compile the example, run it with `./example/iniexample` + +## III - License + +This software is released under MIT License. +See LICENSE for full informations + +## IV - Versions + +Current version is 4.0 which introduces breaking changes in the api. +Older versions 3.1 and 3.2 with the legacy api are available as tags. diff --git a/doc/iniparser.dox b/doc/iniparser.dox index 44e972108ea7a3e436d19a3d892ee6bea90679b3..8c3bee34367f3a38b51476dcb711ea6e8a7b6820 100644 --- a/doc/iniparser.dox +++ b/doc/iniparser.dox @@ -1,5 +1,5 @@ PROJECT_NAME = iniparser -PROJECT_NUMBER = 3.2 +PROJECT_NUMBER = 4.0 OUTPUT_DIRECTORY = .. OUTPUT_LANGUAGE = English EXTRACT_ALL = YES diff --git a/example/Makefile b/example/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c18b19ad03547716f048ed17eb4efd028c8739a2 --- /dev/null +++ b/example/Makefile @@ -0,0 +1,27 @@ +# +# iniparser tests Makefile +# + +CC = gcc +CFLAGS = -g -I../src +LFLAGS = -L.. -liniparser +AR = ar +ARFLAGS = rcv +RM = rm -f + + +default: all + +all: iniexample parse + +iniexample: iniexample.c + $(CC) $(CFLAGS) -o iniexample iniexample.c -I../src -L.. -liniparser + +parse: parse.c + $(CC) $(CFLAGS) -o parse parse.c -I../src -L.. -liniparser + +clean veryclean: + $(RM) iniexample example.ini parse + + + diff --git a/test/iniexample.c b/example/iniexample.c similarity index 93% rename from test/iniexample.c rename to example/iniexample.c index 1c567aff706afaf751cd1537a86ab1d30084ffcb..81013f0fc98a49ce8370099524a5685428f9bdb4 100644 --- a/test/iniexample.c +++ b/example/iniexample.c @@ -25,7 +25,11 @@ void create_example_ini_file(void) { FILE * ini ; - ini = fopen("example.ini", "w"); + if ((ini=fopen("example.ini", "w"))==NULL) { + fprintf(stderr, "iniparser: cannot create example.ini\n"); + return ; + } + fprintf(ini, "#\n" "# This is an example of ini file\n" @@ -58,7 +62,7 @@ int parse_ini_file(char * ini_name) int b ; int i ; double d ; - char * s ; + const char * s ; ini = iniparser_load(ini_name); if (ini==NULL) { diff --git a/test/parse.c b/example/parse.c similarity index 100% rename from test/parse.c rename to example/parse.c diff --git a/test/twisted-errors.ini b/example/twisted-errors.ini similarity index 100% rename from test/twisted-errors.ini rename to example/twisted-errors.ini diff --git a/test/twisted-genhuge.py b/example/twisted-genhuge.py similarity index 100% rename from test/twisted-genhuge.py rename to example/twisted-genhuge.py diff --git a/test/twisted-ofkey.ini b/example/twisted-ofkey.ini similarity index 100% rename from test/twisted-ofkey.ini rename to example/twisted-ofkey.ini diff --git a/test/twisted-ofval.ini b/example/twisted-ofval.ini similarity index 100% rename from test/twisted-ofval.ini rename to example/twisted-ofval.ini diff --git a/test/twisted.ini b/example/twisted.ini similarity index 100% rename from test/twisted.ini rename to example/twisted.ini diff --git a/src/dictionary.c b/src/dictionary.c index 0e88506479f289ae16005219a286146bea5d0cb6..9da3070c143ae2231f83395f10cca2d33117d7a0 100644 --- a/src/dictionary.c +++ b/src/dictionary.c @@ -18,10 +18,7 @@ #include #include #include -#ifdef WIN32 -#else #include -#endif /** Maximum value size for integers and doubles. */ #define MAXVALSZ 1024 @@ -36,21 +33,6 @@ Private functions ---------------------------------------------------------------------------*/ -/* Doubles the allocated size associated to a pointer */ -/* 'size' is the current allocated size. */ -static void * mem_double(void * ptr, size_t size) -{ - void * newptr ; - - newptr = calloc(2*size, 1); - if (newptr==NULL) { - return NULL ; - } - memcpy(newptr, ptr, size); - free(ptr); - return newptr ; -} - /*-------------------------------------------------------------------------*/ /** @brief Duplicate a string @@ -61,7 +43,7 @@ static void * mem_double(void * ptr, size_t size) for systems that do not have it. */ /*--------------------------------------------------------------------------*/ -char * xstrdup(const char * s) +static char * xstrdup(const char * s) { char * t ; size_t len ; @@ -69,13 +51,55 @@ char * xstrdup(const char * s) return NULL ; len = strlen(s) + 1 ; - t = malloc(len) ; + t = (char*) malloc(len) ; if (t) { memcpy(t, s, len) ; } return t ; } +/*-------------------------------------------------------------------------*/ +/** + @brief Double the size of the dictionary + @param d Dictionary to grow + @return This function returns non-zero in case of failure + */ +/*--------------------------------------------------------------------------*/ +static int dictionary_grow(dictionary * d) +{ + char ** new_val ; + char ** new_key ; + unsigned * new_hash ; + + new_val = (char**) calloc(d->size * 2, sizeof *d->val); + new_key = (char**) calloc(d->size * 2, sizeof *d->key); + new_hash = (unsigned*) calloc(d->size * 2, sizeof *d->hash); + if (!new_val || !new_key || !new_hash) { + /* An allocation failed, leave the dictionary unchanged */ + if (new_val) + free(new_val); + if (new_key) + free(new_key); + if (new_hash) + free(new_hash); + return -1 ; + } + /* Initialize the newly allocated space */ + memcpy(new_val, d->val, d->size * sizeof(char *)); + memcpy(new_key, d->key, d->size * sizeof(char *)); + memcpy(new_hash, d->hash, d->size * sizeof(unsigned)); + /* Delete previous data */ + free(d->val); + free(d->key); + free(d->hash); + /* Actually update the dictionary */ + d->size *= 2 ; + d->val = new_val; + d->key = new_key; + d->hash = new_hash; + return 0 ; +} + /*--------------------------------------------------------------------------- Function codes ---------------------------------------------------------------------------*/ @@ -97,6 +121,9 @@ unsigned dictionary_hash(const char * key) unsigned hash ; size_t i ; + if (!key) + return 0 ; + len = strlen(key); for (hash=0, i=0 ; isize = size ; - d->val = calloc(size, sizeof *d->val); - d->key = calloc(size, sizeof *d->key); - d->hash = calloc(size, sizeof *d->hash); + d->val = (char**) calloc(size, sizeof *d->val); + d->key = (char**) calloc(size, sizeof *d->key); + d->hash = (unsigned*) calloc(size, sizeof *d->hash); } return d ; } @@ -149,10 +176,10 @@ dictionary * dictionary_new(size_t size) /*--------------------------------------------------------------------------*/ void dictionary_del(dictionary * d) { - size_t i ; + ssize_t i ; if (d==NULL) return ; - for (i=0 ; i< (size_t)d->size ; i++) { + for (i=0 ; isize ; i++) { if (d->key[i]!=NULL) free(d->key[i]); if (d->val[i]!=NULL) @@ -179,13 +206,13 @@ void dictionary_del(dictionary * d) dictionary object, you should not try to free it or modify it. */ /*--------------------------------------------------------------------------*/ -char * dictionary_get(dictionary * d, const char * key, char * def) +const char * dictionary_get(const dictionary * d, const char * key, const char * def) { unsigned hash ; - size_t i ; + ssize_t i ; hash = dictionary_hash(key); - for (i=0 ; i<(size_t)d->size ; i++) { + for (i=0 ; isize ; i++) { if (d->key[i]==NULL) continue ; /* Compare hash */ @@ -227,8 +254,8 @@ char * dictionary_get(dictionary * d, const char * key, char * def) /*--------------------------------------------------------------------------*/ int dictionary_set(dictionary * d, const char * key, const char * val) { - size_t i ; - unsigned hash ; + ssize_t i ; + unsigned hash ; if (d==NULL || key==NULL) return -1 ; @@ -236,7 +263,7 @@ int dictionary_set(dictionary * d, const char * key, const char * val) hash = dictionary_hash(key) ; /* Find if value is already in dictionary */ if (d->n>0) { - for (i=0 ; i<(size_t)d->size ; i++) { + for (i=0 ; isize ; i++) { if (d->key[i]==NULL) continue ; if (hash==d->hash[i]) { /* Same hash value */ @@ -244,7 +271,7 @@ int dictionary_set(dictionary * d, const char * key, const char * val) /* Found a value: modify and return */ if (d->val[i]!=NULL) free(d->val[i]); - d->val[i] = val ? xstrdup(val) : NULL ; + d->val[i] = (val ? xstrdup(val) : NULL); /* Value has been modified: return */ return 0 ; } @@ -254,17 +281,9 @@ int dictionary_set(dictionary * d, const char * key, const char * val) /* Add a new value */ /* See if dictionary needs to grow */ if (d->n==d->size) { - /* Reached maximum size: reallocate dictionary */ - d->val = mem_double(d->val, d->size * sizeof *d->val) ; - d->key = mem_double(d->key, d->size * sizeof *d->key) ; - d->hash = mem_double(d->hash, d->size * sizeof *d->hash) ; - if ((d->val==NULL) || (d->key==NULL) || (d->hash==NULL)) { - /* Cannot grow dictionary */ - return -1 ; - } - /* Double size */ - d->size *= 2 ; + if (dictionary_grow(d) != 0) + return -1; } /* Insert key in the first empty slot. Start at d->n and wrap at @@ -275,7 +294,7 @@ int dictionary_set(dictionary * d, const char * key, const char * val) } /* Copy key */ d->key[i] = xstrdup(key); - d->val[i] = val ? xstrdup(val) : NULL ; + d->val[i] = (val ? xstrdup(val) : NULL) ; d->hash[i] = hash; d->n ++ ; return 0 ; @@ -295,14 +314,14 @@ int dictionary_set(dictionary * d, const char * key, const char * val) void dictionary_unset(dictionary * d, const char * key) { unsigned hash ; - size_t i ; + ssize_t i ; - if (key == NULL) { + if (key == NULL || d == NULL) { return; } hash = dictionary_hash(key); - for (i=0 ; i<(size_t)d->size ; i++) { + for (i=0 ; isize ; i++) { if (d->key[i]==NULL) continue ; /* Compare hash */ @@ -314,7 +333,7 @@ void dictionary_unset(dictionary * d, const char * key) } } } - if (i>=(size_t)d->size) + if (i>=d->size) /* Key not found */ return ; @@ -341,16 +360,16 @@ void dictionary_unset(dictionary * d, const char * key) output file pointers. */ /*--------------------------------------------------------------------------*/ -void dictionary_dump(dictionary * d, FILE * out) +void dictionary_dump(const dictionary * d, FILE * out) { - size_t i ; + ssize_t i ; if (d==NULL || out==NULL) return ; if (d->n<1) { fprintf(out, "empty dictionary\n"); return ; } - for (i=0 ; i<(size_t)d->size ; i++) { + for (i=0 ; isize ; i++) { if (d->key[i]) { fprintf(out, "%20s\t[%s]\n", d->key[i], @@ -359,47 +378,3 @@ void dictionary_dump(dictionary * d, FILE * out) } return ; } - - -/* Test code */ -#ifdef TESTDIC -#define NVALS 20000 -int main(int argc, char *argv[]) -{ - dictionary * d ; - char * val ; - int i ; - char cval[90] ; - - /* Allocate dictionary */ - printf("allocating...\n"); - d = dictionary_new(0); - - /* Set values in dictionary */ - printf("setting %d values...\n", NVALS); - for (i=0 ; in != 0) { - printf("error deleting values\n"); - } - printf("deallocating...\n"); - dictionary_del(d); - return 0 ; -} -#endif -/* vim: set ts=4 et sw=4 tw=75 */ diff --git a/src/dictionary.h b/src/dictionary.h index 8971aaf2ac8c0d6df123cbee930e9388cd85b080..d04b6ce715d91efc2fd0f57b2f5e962ed4ac49c9 100644 --- a/src/dictionary.h +++ b/src/dictionary.h @@ -21,11 +21,7 @@ #include #include #include - -#ifdef WIN32 -#else #include -#endif #ifdef __cplusplus extern "C" { @@ -48,7 +44,7 @@ extern "C" { /*-------------------------------------------------------------------------*/ typedef struct _dictionary_ { int n ; /** Number of entries in dictionary */ - int size ; /** Storage size */ + ssize_t size ; /** Storage size */ char ** val ; /** List of string values */ char ** key ; /** List of string keys */ unsigned * hash ; /** List of hash values for keys */ @@ -111,7 +107,7 @@ void dictionary_del(dictionary * vd); dictionary object, you should not try to free it or modify it. */ /*--------------------------------------------------------------------------*/ -char * dictionary_get(dictionary * d, const char * key, char * def); +const char * dictionary_get(const dictionary * d, const char * key, const char * def); /*-------------------------------------------------------------------------*/ @@ -168,19 +164,7 @@ void dictionary_unset(dictionary * d, const char * key); output file pointers. */ /*--------------------------------------------------------------------------*/ -void dictionary_dump(dictionary * d, FILE * out); - -/*-------------------------------------------------------------------------*/ -/** - @brief Duplicate a string - @param s String to duplicate - @return Pointer to a newly allocated string, to be freed with free() - - This is a replacement for strdup(). This implementation is provided - for systems that do not have it. - */ -/*--------------------------------------------------------------------------*/ -char * xstrdup(const char * s); +void dictionary_dump(const dictionary * d, FILE * out); #ifdef __cplusplus } diff --git a/src/iniparser.c b/src/iniparser.c index 0a8e4ba249c9cdb47c577dfd4654fbd18ef70227..1b22fc7056169c7d09d49ce59320c64b65daa675 100644 --- a/src/iniparser.c +++ b/src/iniparser.c @@ -10,15 +10,6 @@ #include #include "iniparser.h" -#ifdef WIN32 -#include -#include -#include -#include - -#define snprintf sprintf_s -#endif - /*---------------------------- Defines -------------------------------------*/ #define ASCIILINESZ (1024) #define INI_INVALID_KEY ((char*)-1) @@ -41,54 +32,70 @@ typedef enum _line_status_ { /*-------------------------------------------------------------------------*/ /** @brief Convert a string to lowercase. - @param s String to convert. + @param in String to convert. + @param out Output buffer. + @param len Size of the out buffer. + @return ptr to the out buffer or NULL if an error occured. - This function modifies the string passed, the modified string - contains a lowercased version of the input string. + This function convert a string into lowercase. + At most len - 1 elements of the input string will be converted. */ /*--------------------------------------------------------------------------*/ - -static void strlwc(char * s) +static const char * strlwc(const char * in, char *out, unsigned len) { - int i ; + unsigned i ; - if (s==NULL) return; + if (in==NULL || out == NULL || len==0) return NULL ; i=0 ; - while (s[i]) { - s[i] = (char)tolower((int)s[i]); + while (in[i] != '\0' && i < len-1) { + out[i] = (char)tolower((int)in[i]); i++ ; } + out[i] = '\0'; + return out ; } /*-------------------------------------------------------------------------*/ /** - @brief Remove blanks at the beginning and the end of a string. - @param s String to parse. + @brief Copy string in a newly mallocced area + @param str String to copy. + @return str Copied version of the given string allocated with malloc + + Original strdup is not portable, need to implement our own + */ +/*--------------------------------------------------------------------------*/ +static char * _strdup(const char *s) +{ + char * copy = (char*) malloc(strlen(s)); + strcpy(copy, s); + return copy ; +} - This function modifies the input string and returns a modified string - which is identical to the input string, except that all blank - characters at the end and the beg. of the string have been removed. +/*-------------------------------------------------------------------------*/ +/** + @brief Remove blanks at the beginning and the end of a string. + @param str String to parse and alter. + @return unsigned New size of the string. */ /*--------------------------------------------------------------------------*/ -static void strstrip(char * s) +unsigned strstrip(char * s) { - if (s==NULL) return; - else - { - - char *last = s + strlen(s); - char *dest = s; - - while (isspace((int)*s) && *s) s++; - while (last > s) { - if (!isspace((int)*(last-1))) - break ; - last -- ; - } - *last = (char)0; - - memmove(dest, s, last - s + 1); - } + char *last = NULL ; + char *dest = s; + + if (s==NULL) return 0; + + last = s + strlen(s); + while (isspace((int)*s) && *s) s++; + while (last > s) { + if (!isspace((int)*(last-1))) + break ; + last -- ; + } + *last = (char)0; + + memmove(dest,s,last - s + 1); + return last - s; } /*-------------------------------------------------------------------------*/ @@ -109,7 +116,7 @@ static void strstrip(char * s) This function returns -1 in case of error. */ /*--------------------------------------------------------------------------*/ -int iniparser_getnsec(dictionary * d) +int iniparser_getnsec(const dictionary * d) { int i ; int nsec ; @@ -140,7 +147,7 @@ int iniparser_getnsec(dictionary * d) This function returns NULL in case of error. */ /*--------------------------------------------------------------------------*/ -char * iniparser_getsecname(dictionary * d, int n) +const char * iniparser_getsecname(const dictionary * d, int n) { int i ; int foundsec ; @@ -175,7 +182,7 @@ char * iniparser_getsecname(dictionary * d, int n) purposes mostly. */ /*--------------------------------------------------------------------------*/ -void iniparser_dump(dictionary * d, FILE * f) +void iniparser_dump(const dictionary * d, FILE * f) { int i ; @@ -203,11 +210,11 @@ void iniparser_dump(dictionary * d, FILE * f) It is Ok to specify @c stderr or @c stdout as output files. */ /*--------------------------------------------------------------------------*/ -void iniparser_dump_ini(dictionary * d, FILE * f) +void iniparser_dump_ini(const dictionary * d, FILE * f) { - int i ; - int nsec ; - char * secname ; + int i ; + int nsec ; + const char * secname ; if (d==NULL || f==NULL) return ; @@ -223,7 +230,7 @@ void iniparser_dump_ini(dictionary * d, FILE * f) } for (i=0 ; isize ; j++) { if (d->key[j]==NULL) continue ; - if (!strncmp(d->key[j], keym, secsize-1)) { + if (!strncmp(d->key[j], keym, seclen+1)) { fprintf(f, "%-30s = %s\n", - d->key[j]+secsize-1, + d->key[j]+seclen+1, d->val[j] ? d->val[j] : ""); } } fprintf(f, "\n"); - free(keym); return ; } @@ -277,10 +282,10 @@ void iniparser_dumpsection_ini(dictionary * d, char * s, FILE * f) @return Number of keys in section */ /*--------------------------------------------------------------------------*/ -int iniparser_getsecnkeys(dictionary * d, char * s) +int iniparser_getsecnkeys(const dictionary * d, const char * s) { - int secsize, nkeys ; - char *keym; + int seclen, nkeys ; + char keym[ASCIILINESZ+1]; int j ; nkeys = 0; @@ -288,17 +293,16 @@ int iniparser_getsecnkeys(dictionary * d, char * s) if (d==NULL) return nkeys; if (! iniparser_find_entry(d, s)) return nkeys; - secsize = (int)strlen(s)+2; - keym = malloc(secsize); - snprintf(keym, secsize, "%s:", s); + seclen = (int)strlen(s); + sprintf(keym, "%s:", s); for (j=0 ; jsize ; j++) { if (d->key[j]==NULL) continue ; - if (!strncmp(d->key[j], keym, secsize-1)) + if (!strncmp(d->key[j], keym, seclen+1)) nkeys++; } - free(keym); + return nkeys; } @@ -311,20 +315,22 @@ int iniparser_getsecnkeys(dictionary * d, char * s) @return pointer to statically allocated character strings This function queries a dictionary and finds all keys in a given section. + The returned pointer is obtained with malloc(3), and can be freed + with free(3). Each pointer in the returned char pointer-to-pointer is pointing to a string allocated in the dictionary; do not free or modify them. This function returns NULL in case of error. */ /*--------------------------------------------------------------------------*/ -char ** iniparser_getseckeys(dictionary * d, char * s) +const char ** iniparser_getseckeys(const dictionary * d, const char * s) { - char **keys; + const char **keys; int i, j ; - char *keym; - int secsize, nkeys ; + char keym[ASCIILINESZ+1]; + int seclen, nkeys ; keys = NULL; @@ -333,23 +339,22 @@ char ** iniparser_getseckeys(dictionary * d, char * s) nkeys = iniparser_getsecnkeys(d, s); - keys = (char**) malloc(nkeys*sizeof(char*)); + keys = (const char**) malloc(nkeys*sizeof(char*)); - secsize = (int)strlen(s) + 2; - keym = malloc(secsize); - snprintf(keym, secsize, "%s:", s); + seclen = (int)strlen(s); + sprintf(keym, "%s:", s); i = 0; for (j=0 ; jsize ; j++) { if (d->key[j]==NULL) continue ; - if (!strncmp(d->key[j], keym, secsize-1)) { + if (!strncmp(d->key[j], keym, seclen+1)) { keys[i] = d->key[j]; i++; } } - free(keym); + return keys; } @@ -369,18 +374,17 @@ char ** iniparser_getseckeys(dictionary * d, char * s) the dictionary, do not free or modify it. */ /*--------------------------------------------------------------------------*/ -char * iniparser_getstring(dictionary * d, const char * key, char * def) +const char * iniparser_getstring(const dictionary * d, const char * key, const char * def) { - char * lc_key ; - char * sval ; + const char * lc_key ; + const char * sval ; + char tmp_str[ASCIILINESZ+1]; if (d==NULL || key==NULL) return def ; - lc_key = xstrdup(key); - strlwc(lc_key); + lc_key = strlwc(key, tmp_str, sizeof(tmp_str)); sval = dictionary_get(d, lc_key, def); - free(lc_key); return sval ; } @@ -411,9 +415,9 @@ char * iniparser_getstring(dictionary * d, const char * key, char * def) Credits: Thanks to A. Becker for suggesting strtol() */ /*--------------------------------------------------------------------------*/ -int iniparser_getint(dictionary * d, const char * key, int notfound) +int iniparser_getint(const dictionary * d, const char * key, int notfound) { - char * str ; + const char * str ; str = iniparser_getstring(d, key, INI_INVALID_KEY); if (str==INI_INVALID_KEY) return notfound ; @@ -433,9 +437,9 @@ int iniparser_getint(dictionary * d, const char * key, int notfound) the notfound value is returned. */ /*--------------------------------------------------------------------------*/ -double iniparser_getdouble(dictionary * d, const char * key, double notfound) +double iniparser_getdouble(const dictionary * d, const char * key, double notfound) { - char * str ; + const char * str ; str = iniparser_getstring(d, key, INI_INVALID_KEY); if (str==INI_INVALID_KEY) return notfound ; @@ -474,10 +478,10 @@ double iniparser_getdouble(dictionary * d, const char * key, double notfound) necessarily have to be 0 or 1. */ /*--------------------------------------------------------------------------*/ -int iniparser_getboolean(dictionary * d, const char * key, int notfound) +int iniparser_getboolean(const dictionary * d, const char * key, int notfound) { - char * c ; - int ret ; + int ret ; + const char * c ; c = iniparser_getstring(d, key, INI_INVALID_KEY); if (c==INI_INVALID_KEY) return notfound ; @@ -503,10 +507,7 @@ int iniparser_getboolean(dictionary * d, const char * key, int notfound) of querying for the presence of sections in a dictionary. */ /*--------------------------------------------------------------------------*/ -int iniparser_find_entry( - dictionary * ini, - const char * entry -) +int iniparser_find_entry(const dictionary * ini, const char * entry) { int found=0 ; if (iniparser_getstring(ini, entry, INI_INVALID_KEY)!=INI_INVALID_KEY) { @@ -524,18 +525,14 @@ int iniparser_find_entry( @return int 0 if Ok, -1 otherwise. If the given entry can be found in the dictionary, it is modified to - contain the provided value. If it cannot be found, -1 is returned. + contain the provided value. If it cannot be found, the entry is created. It is Ok to set val to NULL. */ /*--------------------------------------------------------------------------*/ int iniparser_set(dictionary * ini, const char * entry, const char * val) { - int result = 0; - char *lc_entry = xstrdup(entry); - strlwc(lc_entry); - result = dictionary_set(ini, lc_entry, val) ; - free(lc_entry); - return result; + char tmp_str[ASCIILINESZ+1]; + return dictionary_set(ini, strlwc(entry, tmp_str, sizeof(tmp_str)), val) ; } /*-------------------------------------------------------------------------*/ @@ -550,10 +547,8 @@ int iniparser_set(dictionary * ini, const char * entry, const char * val) /*--------------------------------------------------------------------------*/ void iniparser_unset(dictionary * ini, const char * entry) { - char* lc_entry = xstrdup(entry); - strlwc(lc_entry); - dictionary_unset(ini, lc_entry); - free(lc_entry); + char tmp_str[ASCIILINESZ+1]; + dictionary_unset(ini, strlwc(entry, tmp_str, sizeof(tmp_str))); } /*-------------------------------------------------------------------------*/ @@ -567,48 +562,17 @@ void iniparser_unset(dictionary * ini, const char * entry) */ /*--------------------------------------------------------------------------*/ static line_status iniparser_line( - int line_size, const char * input_line, - char ** section_out, - char ** key_out, - char ** value_out) + char * section, + char * key, + char * value) { line_status sta ; - int len = line_size-1; - char * line = malloc(line_size); - char * key = NULL; - char * value = NULL; - char * equals = NULL; - - if (!line) { - fprintf(stderr, "iniparser: memory alloc error\n"); - return LINE_ERROR; - } - - *line = 0; + char * line = NULL; + size_t len ; - - strcpy(line, input_line); - strstrip(line); - len = (int)strlen(line); - - /* only allocate necessary space for key & val */ - equals = strchr(line, '='); - if (equals) { - value = malloc((len + line) - equals + 1); - key = malloc(equals - line + 1); - *value = 0; - } else { - key = malloc(line_size + 1); - } - - if (!key || (equals && !value)) { - fprintf(stderr, "iniparser: memory alloc error\n"); - sta = LINE_ERROR; - goto out; - } - - *key = 0; + line = _strdup(input_line); + len = strstrip(line); sta = LINE_UNPROCESSED ; if (len<1) { @@ -619,19 +583,16 @@ static line_status iniparser_line( sta = LINE_COMMENT ; } else if (line[0]=='[' && line[len-1]==']') { /* Section name */ - sscanf(line, "[%[^]]", key); - strstrip(key); - strlwc(key); + sscanf(line, "[%[^]]", section); + strstrip(section); + strlwc(section, section, len); sta = LINE_SECTION ; - *section_out=key; - /* don't free key's memory */ - key = NULL; - } else if (equals && (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2 + } else if (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2 || sscanf (line, "%[^=] = '%[^\']'", key, value) == 2 - || sscanf (line, "%[^=] = %[^;#]", key, value) == 2)) { + || sscanf (line, "%[^=] = %[^;#]", key, value) == 2) { /* Usual key=value, with or without comments */ strstrip(key); - strlwc(key); + strlwc(key, key, len); strstrip(value); /* * sscanf cannot handle '' or "" as empty values @@ -640,13 +601,9 @@ static line_status iniparser_line( if (!strcmp(value, "\"\"") || (!strcmp(value, "''"))) { value[0]=0 ; } - *key_out = key; - *value_out = value; - key = NULL; - value = NULL; sta = LINE_VALUE ; - } else if (equals && (sscanf(line, "%[^=] = %[;#]", key, value)==2 - || sscanf(line, "%[^=] %[=]", key, value) == 2)) { + } else if (sscanf(line, "%[^=] = %[;#]", key, value)==2 + || sscanf(line, "%[^=] %[=]", key, value) == 2) { /* * Special cases: * key= @@ -654,33 +611,15 @@ static line_status iniparser_line( * key=# */ strstrip(key); - strlwc(key); + strlwc(key, key, len); value[0]=0 ; - *key_out = key; - *value_out = value; - - /* don't free out params key or val's memory */ - key = NULL; - value = NULL; sta = LINE_VALUE ; } else { /* Generate syntax error */ sta = LINE_ERROR ; } -out: - if (line) { - free(line); - line = NULL; - } - if (key) { - free(key); - key = NULL; - } - if (value) { - free(value); - value= NULL; - } + free(line); return sta ; } @@ -700,49 +639,39 @@ out: /*--------------------------------------------------------------------------*/ dictionary * iniparser_load(const char * ininame) { - FILE * in = NULL ; + FILE * in ; char line [ASCIILINESZ+1] ; - char *section = xstrdup(""); - char *current_section = NULL; - char *key = NULL; - char *val = NULL; - char* full_line = NULL; - char* prev_line = NULL; + char section [ASCIILINESZ+1] ; + char key [ASCIILINESZ+1] ; + char tmp [(ASCIILINESZ * 2) + 1] ; + char val [ASCIILINESZ+1] ; + int last=0 ; int len ; int lineno=0 ; int errs=0; - int seckey_size=0; - dictionary * dict = NULL ; + dictionary * dict ; if ((in=fopen(ininame, "r"))==NULL) { fprintf(stderr, "iniparser: cannot open %s\n", ininame); - goto out; + return NULL ; } dict = dictionary_new(0) ; if (!dict) { - goto out; + fclose(in); + return NULL ; } memset(line, 0, ASCIILINESZ); + memset(section, 0, ASCIILINESZ); + memset(key, 0, ASCIILINESZ); + memset(val, 0, ASCIILINESZ); + last=0 ; - while (fgets(line, ASCIILINESZ, in)!=NULL) { - int prev_line_len = 0; - int multi_line = 0; - int total_size = 0; - - if (key) { - free(key); - key = NULL; - } - if (val) { - free(val); - val = NULL; - } - + while (fgets(line+last, ASCIILINESZ-last, in)!=NULL) { lineno++ ; len = (int)strlen(line)-1; if (len==0) @@ -753,8 +682,9 @@ dictionary * iniparser_load(const char * ininame) "iniparser: input line too long in %s (%d)\n", ininame, lineno); - errs++; - goto out; + dictionary_del(dict); + fclose(in); + return NULL ; } /* Get rid of \n and spaces at end of line */ while ((len>=0) && @@ -762,97 +692,36 @@ dictionary * iniparser_load(const char * ininame) line[len]=0 ; len-- ; } - if (len < 0) { /* Line was entirely \n and/or spaces */ len = 0; } - /* Detect multi-line */ if (line[len]=='\\') { - multi_line = 1; - } - if (multi_line) { /* Multi-line value */ - /* length without trailing '\' */ - /* remove multi-line indicator before appending*/ - line[len] = 0; - len--; - } - - /* - * If processing a multi-line then append it the previous portion, - * at this point 'full_line' has the previously read portion of a - * multi-line line (or NULL) - */ - prev_line = full_line; - prev_line_len=0; - if (prev_line) { - prev_line_len = strlen(prev_line); - } - - /* len is not strlen(line) but strlen(line) -1 */ - total_size = (len+1) + prev_line_len + 1; - - full_line = malloc(total_size); - if (!full_line) { - fprintf(stderr, - "iniparser: out of mem\n"); - errs++; - goto out; - } - - memset(full_line, 0, total_size); - - if (prev_line) { - strcpy(full_line, prev_line); - } - - strcpy(full_line + prev_line_len, line); - free(prev_line); - prev_line = NULL; - - if (multi_line) { + last=len ; continue ; + } else { + last=0 ; } - - switch (iniparser_line(total_size, full_line, ¤t_section, &key, &val)) { + switch (iniparser_line(line, section, key, val)) { case LINE_EMPTY: case LINE_COMMENT: break ; case LINE_SECTION: - if (section) { - free(section); - section=NULL; - } - errs = dictionary_set(dict, current_section, NULL); - section = current_section; + errs = dictionary_set(dict, section, NULL); break ; case LINE_VALUE: - { - char *seckey; - /* section + ':' + key + eos */ - seckey_size = strlen(section) + strlen(key) +2; - seckey = malloc(seckey_size); - if (!seckey) { - errs++; - fprintf(stderr, - "iniparser: out of mem\n"); - goto out; - } - snprintf(seckey, seckey_size, "%s:%s", section, key); - errs = dictionary_set(dict, seckey, val) ; - free(seckey); - seckey = NULL; - } + sprintf(tmp, "%s:%s", section, key); + errs = dictionary_set(dict, tmp, val) ; break ; case LINE_ERROR: fprintf(stderr, "iniparser: syntax error in %s (%d):\n", ininame, lineno); - fprintf(stderr, "-> %s\n", full_line); + fprintf(stderr, "-> %s\n", line); errs++ ; break; @@ -860,43 +729,17 @@ dictionary * iniparser_load(const char * ininame) break ; } memset(line, 0, ASCIILINESZ); - if (full_line) { - free(full_line); - full_line = NULL; - } + last=0; if (errs<0) { fprintf(stderr, "iniparser: memory allocation failure\n"); break ; } } -out: if (errs) { dictionary_del(dict); dict = NULL ; } - if (val) { - free(val); - val = NULL; - } - if (key) { - free(key); - key = NULL; - } - if (section) { - free(section); - section = NULL; - } - if (full_line) { - free(full_line); - full_line = NULL; - } - if (prev_line) { - free(prev_line); - prev_line = NULL; - } - if (in) { - fclose(in); - } + fclose(in); return dict ; } @@ -915,5 +758,3 @@ void iniparser_freedict(dictionary * d) { dictionary_del(d); } - -/* vim: set ts=4 et sw=4 tw=75 */ diff --git a/src/iniparser.h b/src/iniparser.h index 153ad0769cd54b3d3744a770149b6e9cd7d6137c..92ca600c550e26da438a59e39e691821e46cf75d 100644 --- a/src/iniparser.h +++ b/src/iniparser.h @@ -50,7 +50,7 @@ extern "C" { */ /*--------------------------------------------------------------------------*/ -int iniparser_getnsec(dictionary * d); +int iniparser_getnsec(const dictionary * d); /*-------------------------------------------------------------------------*/ @@ -68,7 +68,7 @@ int iniparser_getnsec(dictionary * d); */ /*--------------------------------------------------------------------------*/ -char * iniparser_getsecname(dictionary * d, int n); +const char * iniparser_getsecname(const dictionary * d, int n); /*-------------------------------------------------------------------------*/ @@ -83,7 +83,7 @@ char * iniparser_getsecname(dictionary * d, int n); */ /*--------------------------------------------------------------------------*/ -void iniparser_dump_ini(dictionary * d, FILE * f); +void iniparser_dump_ini(const dictionary * d, FILE * f); /*-------------------------------------------------------------------------*/ /** @@ -98,7 +98,7 @@ void iniparser_dump_ini(dictionary * d, FILE * f); */ /*--------------------------------------------------------------------------*/ -void iniparser_dumpsection_ini(dictionary * d, char * s, FILE * f); +void iniparser_dumpsection_ini(const dictionary * d, const char * s, FILE * f); /*-------------------------------------------------------------------------*/ /** @@ -113,7 +113,7 @@ void iniparser_dumpsection_ini(dictionary * d, char * s, FILE * f); purposes mostly. */ /*--------------------------------------------------------------------------*/ -void iniparser_dump(dictionary * d, FILE * f); +void iniparser_dump(const dictionary * d, FILE * f); /*-------------------------------------------------------------------------*/ /** @@ -123,7 +123,7 @@ void iniparser_dump(dictionary * d, FILE * f); @return Number of keys in section */ /*--------------------------------------------------------------------------*/ -int iniparser_getsecnkeys(dictionary * d, char * s); +int iniparser_getsecnkeys(const dictionary * d, const char * s); /*-------------------------------------------------------------------------*/ /** @@ -133,13 +133,15 @@ int iniparser_getsecnkeys(dictionary * d, char * s); @return pointer to statically allocated character strings This function queries a dictionary and finds all keys in a given section. + The returned pointer is obtained with malloc(3), and can be freed + with free(3). Each pointer in the returned char pointer-to-pointer is pointing to a string allocated in the dictionary; do not free or modify them. This function returns NULL in case of error. */ /*--------------------------------------------------------------------------*/ -char ** iniparser_getseckeys(dictionary * d, char * s); +const char ** iniparser_getseckeys(const dictionary * d, const char * s); /*-------------------------------------------------------------------------*/ /** @@ -156,7 +158,7 @@ char ** iniparser_getseckeys(dictionary * d, char * s); the dictionary, do not free or modify it. */ /*--------------------------------------------------------------------------*/ -char * iniparser_getstring(dictionary * d, const char * key, char * def); +const char * iniparser_getstring(const dictionary * d, const char * key, const char * def); /*-------------------------------------------------------------------------*/ /** @@ -185,7 +187,7 @@ char * iniparser_getstring(dictionary * d, const char * key, char * def); Credits: Thanks to A. Becker for suggesting strtol() */ /*--------------------------------------------------------------------------*/ -int iniparser_getint(dictionary * d, const char * key, int notfound); +int iniparser_getint(const dictionary * d, const char * key, int notfound); /*-------------------------------------------------------------------------*/ /** @@ -200,7 +202,7 @@ int iniparser_getint(dictionary * d, const char * key, int notfound); the notfound value is returned. */ /*--------------------------------------------------------------------------*/ -double iniparser_getdouble(dictionary * d, const char * key, double notfound); +double iniparser_getdouble(const dictionary * d, const char * key, double notfound); /*-------------------------------------------------------------------------*/ /** @@ -234,7 +236,7 @@ double iniparser_getdouble(dictionary * d, const char * key, double notfound); necessarily have to be 0 or 1. */ /*--------------------------------------------------------------------------*/ -int iniparser_getboolean(dictionary * d, const char * key, int notfound); +int iniparser_getboolean(const dictionary * d, const char * key, int notfound); /*-------------------------------------------------------------------------*/ @@ -243,10 +245,10 @@ int iniparser_getboolean(dictionary * d, const char * key, int notfound); @param ini Dictionary to modify. @param entry Entry to modify (entry name) @param val New value to associate to the entry. - @return int 0 if Ok, -1 otherwise. + @return int 0 if Ok, -1 otherwise. If the given entry can be found in the dictionary, it is modified to - contain the provided value. If it cannot be found, -1 is returned. + contain the provided value. If it cannot be found, the entry is created. It is Ok to set val to NULL. */ /*--------------------------------------------------------------------------*/ @@ -277,7 +279,7 @@ void iniparser_unset(dictionary * ini, const char * entry); of querying for the presence of sections in a dictionary. */ /*--------------------------------------------------------------------------*/ -int iniparser_find_entry(dictionary * ini, const char * entry) ; +int iniparser_find_entry(const dictionary * ini, const char * entry) ; /*-------------------------------------------------------------------------*/ /** diff --git a/test/CuTest.c b/test/CuTest.c new file mode 100644 index 0000000000000000000000000000000000000000..144f8c30613b88b303d28b57434ff403be67d44e --- /dev/null +++ b/test/CuTest.c @@ -0,0 +1,339 @@ +#include +#include +#include +#include +#include +#include + +#include "CuTest.h" + +/*-------------------------------------------------------------------------* + * CuStr + *-------------------------------------------------------------------------*/ + +char* CuStrAlloc(int size) +{ + char* newStr = (char*) malloc( sizeof(char) * (size) ); + return newStr; +} + +char* CuStrCopy(const char* old) +{ + int len = strlen(old); + char* newStr = CuStrAlloc(len + 1); + strcpy(newStr, old); + return newStr; +} + +/*-------------------------------------------------------------------------* + * CuString + *-------------------------------------------------------------------------*/ + +void CuStringInit(CuString* str) +{ + str->length = 0; + str->size = STRING_MAX; + str->buffer = (char*) malloc(sizeof(char) * str->size); + str->buffer[0] = '\0'; +} + +CuString* CuStringNew(void) +{ + CuString* str = (CuString*) malloc(sizeof(CuString)); + str->length = 0; + str->size = STRING_MAX; + str->buffer = (char*) malloc(sizeof(char) * str->size); + str->buffer[0] = '\0'; + return str; +} + +void CuStringDelete(CuString *str) +{ + if (!str) return; + free(str->buffer); + free(str); +} + +void CuStringResize(CuString* str, int newSize) +{ + str->buffer = (char*) realloc(str->buffer, sizeof(char) * newSize); + str->size = newSize; +} + +void CuStringAppend(CuString* str, const char* text) +{ + int length; + + if (text == NULL) { + text = "NULL"; + } + + length = strlen(text); + if (str->length + length + 1 >= str->size) + CuStringResize(str, str->length + length + 1 + STRING_INC); + str->length += length; + strcat(str->buffer, text); +} + +void CuStringAppendChar(CuString* str, char ch) +{ + char text[2]; + text[0] = ch; + text[1] = '\0'; + CuStringAppend(str, text); +} + +void CuStringAppendFormat(CuString* str, const char* format, ...) +{ + va_list argp; + char buf[HUGE_STRING_LEN]; + va_start(argp, format); + vsprintf(buf, format, argp); + va_end(argp); + CuStringAppend(str, buf); +} + +void CuStringInsert(CuString* str, const char* text, int pos) +{ + int length = strlen(text); + if (pos > str->length) + pos = str->length; + if (str->length + length + 1 >= str->size) + CuStringResize(str, str->length + length + 1 + STRING_INC); + memmove(str->buffer + pos + length, str->buffer + pos, (str->length - pos) + 1); + str->length += length; + memcpy(str->buffer + pos, text, length); +} + +/*-------------------------------------------------------------------------* + * CuTest + *-------------------------------------------------------------------------*/ + +void CuTestInit(CuTest* t, const char* name, TestFunction function) +{ + t->name = CuStrCopy(name); + t->failed = 0; + t->ran = 0; + t->message = NULL; + t->function = function; + t->jumpBuf = NULL; +} + +CuTest* CuTestNew(const char* name, TestFunction function) +{ + CuTest* tc = CU_ALLOC(CuTest); + CuTestInit(tc, name, function); + return tc; +} + +void CuTestDelete(CuTest *t) +{ + if (!t) return; + free(t->name); + free(t); +} + +void CuTestRun(CuTest* tc) +{ + jmp_buf buf; + tc->jumpBuf = &buf; + if (setjmp(buf) == 0) + { + tc->ran = 1; + (tc->function)(tc); + } + tc->jumpBuf = 0; +} + +static void CuFailInternal(CuTest* tc, const char* file, int line, CuString* string) +{ + char buf[HUGE_STRING_LEN]; + + sprintf(buf, "%s:%d: ", file, line); + CuStringInsert(string, buf, 0); + + tc->failed = 1; + tc->message = string->buffer; + if (tc->jumpBuf != 0) longjmp(*(tc->jumpBuf), 0); +} + +void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message) +{ + CuString string; + + CuStringInit(&string); + if (message2 != NULL) + { + CuStringAppend(&string, message2); + CuStringAppend(&string, ": "); + } + CuStringAppend(&string, message); + CuFailInternal(tc, file, line, &string); +} + +void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition) +{ + if (condition) return; + CuFail_Line(tc, file, line, NULL, message); +} + +void CuAssertStrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, + const char* expected, const char* actual) +{ + CuString string; + if ((expected == NULL && actual == NULL) || + (expected != NULL && actual != NULL && + strcmp(expected, actual) == 0)) + { + return; + } + + CuStringInit(&string); + if (message != NULL) + { + CuStringAppend(&string, message); + CuStringAppend(&string, ": "); + } + CuStringAppend(&string, "expected <"); + CuStringAppend(&string, expected); + CuStringAppend(&string, "> but was <"); + CuStringAppend(&string, actual); + CuStringAppend(&string, ">"); + CuFailInternal(tc, file, line, &string); +} + +void CuAssertIntEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, + int expected, int actual) +{ + char buf[STRING_MAX]; + if (expected == actual) return; + sprintf(buf, "expected <%d> but was <%d>", expected, actual); + CuFail_Line(tc, file, line, message, buf); +} + +void CuAssertDblEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, + double expected, double actual, double delta) +{ + char buf[STRING_MAX]; + if (fabs(expected - actual) <= delta) return; + sprintf(buf, "expected <%f> but was <%f>", expected, actual); + + CuFail_Line(tc, file, line, message, buf); +} + +void CuAssertPtrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, + const void* expected, const void* actual) +{ + char buf[STRING_MAX]; + if (expected == actual) return; + sprintf(buf, "expected pointer <0x%p> but was <0x%p>", expected, actual); + CuFail_Line(tc, file, line, message, buf); +} + + +/*-------------------------------------------------------------------------* + * CuSuite + *-------------------------------------------------------------------------*/ + +void CuSuiteInit(CuSuite* testSuite) +{ + testSuite->count = 0; + testSuite->failCount = 0; + memset(testSuite->list, 0, sizeof(testSuite->list)); +} + +CuSuite* CuSuiteNew(void) +{ + CuSuite* testSuite = CU_ALLOC(CuSuite); + CuSuiteInit(testSuite); + return testSuite; +} + +void CuSuiteDelete(CuSuite *testSuite) +{ + unsigned int n; + for (n=0; n < MAX_TEST_CASES; n++) + { + if (testSuite->list[n]) + { + CuTestDelete(testSuite->list[n]); + } + } + free(testSuite); + +} + +void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase) +{ + assert(testSuite->count < MAX_TEST_CASES); + testSuite->list[testSuite->count] = testCase; + testSuite->count++; +} + +void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2) +{ + int i; + for (i = 0 ; i < testSuite2->count ; ++i) + { + CuTest* testCase = testSuite2->list[i]; + CuSuiteAdd(testSuite, testCase); + } +} + +void CuSuiteRun(CuSuite* testSuite) +{ + int i; + for (i = 0 ; i < testSuite->count ; ++i) + { + CuTest* testCase = testSuite->list[i]; + CuTestRun(testCase); + if (testCase->failed) { testSuite->failCount += 1; } + } +} + +void CuSuiteSummary(CuSuite* testSuite, CuString* summary) +{ + int i; + for (i = 0 ; i < testSuite->count ; ++i) + { + CuTest* testCase = testSuite->list[i]; + CuStringAppend(summary, testCase->failed ? "F" : "."); + } + CuStringAppend(summary, "\n\n"); +} + +void CuSuiteDetails(CuSuite* testSuite, CuString* details) +{ + int i; + int failCount = 0; + + if (testSuite->failCount == 0) + { + int passCount = testSuite->count - testSuite->failCount; + const char* testWord = passCount == 1 ? "test" : "tests"; + CuStringAppendFormat(details, "OK (%d %s)\n", passCount, testWord); + } + else + { + if (testSuite->failCount == 1) + CuStringAppend(details, "There was 1 failure:\n"); + else + CuStringAppendFormat(details, "There were %d failures:\n", testSuite->failCount); + + for (i = 0 ; i < testSuite->count ; ++i) + { + CuTest* testCase = testSuite->list[i]; + if (testCase->failed) + { + failCount++; + CuStringAppendFormat(details, "%d) %s: %s\n", + failCount, testCase->name, testCase->message); + } + } + CuStringAppend(details, "\n!!!FAILURES!!!\n"); + + CuStringAppendFormat(details, "Runs: %d ", testSuite->count); + CuStringAppendFormat(details, "Passes: %d ", testSuite->count - testSuite->failCount); + CuStringAppendFormat(details, "Fails: %d\n", testSuite->failCount); + } +} diff --git a/test/CuTest.h b/test/CuTest.h new file mode 100644 index 0000000000000000000000000000000000000000..2f7ef5422b1aa0ea3b0c5f69e0e726f1d6a14525 --- /dev/null +++ b/test/CuTest.h @@ -0,0 +1,116 @@ +#ifndef CU_TEST_H +#define CU_TEST_H + +#include +#include + +#define CUTEST_VERSION "CuTest 1.5" + +/* CuString */ + +char* CuStrAlloc(int size); +char* CuStrCopy(const char* old); + +#define CU_ALLOC(TYPE) ((TYPE*) malloc(sizeof(TYPE))) + +#define HUGE_STRING_LEN 8192 +#define STRING_MAX 256 +#define STRING_INC 256 + +typedef struct +{ + int length; + int size; + char* buffer; +} CuString; + +void CuStringInit(CuString* str); +CuString* CuStringNew(void); +void CuStringRead(CuString* str, const char* path); +void CuStringAppend(CuString* str, const char* text); +void CuStringAppendChar(CuString* str, char ch); +void CuStringAppendFormat(CuString* str, const char* format, ...); +void CuStringInsert(CuString* str, const char* text, int pos); +void CuStringResize(CuString* str, int newSize); +void CuStringDelete(CuString* str); + +/* CuTest */ + +typedef struct CuTest CuTest; + +typedef void (*TestFunction)(CuTest *); + +struct CuTest +{ + char* name; + TestFunction function; + int failed; + int ran; + const char* message; + jmp_buf *jumpBuf; +}; + +void CuTestInit(CuTest* t, const char* name, TestFunction function); +CuTest* CuTestNew(const char* name, TestFunction function); +void CuTestRun(CuTest* tc); +void CuTestDelete(CuTest *t); + +/* Internal versions of assert functions -- use the public versions */ +void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message); +void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition); +void CuAssertStrEquals_LineMsg(CuTest* tc, + const char* file, int line, const char* message, + const char* expected, const char* actual); +void CuAssertIntEquals_LineMsg(CuTest* tc, + const char* file, int line, const char* message, + int expected, int actual); +void CuAssertDblEquals_LineMsg(CuTest* tc, + const char* file, int line, const char* message, + double expected, double actual, double delta); +void CuAssertPtrEquals_LineMsg(CuTest* tc, + const char* file, int line, const char* message, + const void* expected, const void* actual); + +/* public assert functions */ + +#define CuFail(tc, ms) CuFail_Line( (tc), __FILE__, __LINE__, NULL, (ms)) +#define CuAssert(tc, ms, cond) CuAssert_Line((tc), __FILE__, __LINE__, (ms), (cond)) +#define CuAssertTrue(tc, cond) CuAssert_Line((tc), __FILE__, __LINE__, "assert failed", (cond)) + +#define CuAssertStrEquals(tc,ex,ac) CuAssertStrEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac)) +#define CuAssertStrEquals_Msg(tc,ms,ex,ac) CuAssertStrEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac)) +#define CuAssertIntEquals(tc,ex,ac) CuAssertIntEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac)) +#define CuAssertIntEquals_Msg(tc,ms,ex,ac) CuAssertIntEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac)) +#define CuAssertDblEquals(tc,ex,ac,dl) CuAssertDblEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac),(dl)) +#define CuAssertDblEquals_Msg(tc,ms,ex,ac,dl) CuAssertDblEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac),(dl)) +#define CuAssertPtrEquals(tc,ex,ac) CuAssertPtrEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac)) +#define CuAssertPtrEquals_Msg(tc,ms,ex,ac) CuAssertPtrEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac)) + +#define CuAssertPtrNotNull(tc,p) CuAssert_Line((tc),__FILE__,__LINE__,"null pointer unexpected",(p != NULL)) +#define CuAssertPtrNotNullMsg(tc,msg,p) CuAssert_Line((tc),__FILE__,__LINE__,(msg),(p != NULL)) + +/* CuSuite */ + +#define MAX_TEST_CASES 1024 + +#define SUITE_ADD_TEST(SUITE,TEST) CuSuiteAdd(SUITE, CuTestNew(#TEST, TEST)) + +typedef struct +{ + int count; + CuTest* list[MAX_TEST_CASES]; + int failCount; + +} CuSuite; + + +void CuSuiteInit(CuSuite* testSuite); +CuSuite* CuSuiteNew(void); +void CuSuiteDelete(CuSuite *testSuite); +void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase); +void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2); +void CuSuiteRun(CuSuite* testSuite); +void CuSuiteSummary(CuSuite* testSuite, CuString* summary); +void CuSuiteDetails(CuSuite* testSuite, CuString* details); + +#endif /* CU_TEST_H */ diff --git a/test/CuTest_license.txt b/test/CuTest_license.txt new file mode 100644 index 0000000000000000000000000000000000000000..5f053ba4581a7dc74fdb397b2241bd90b0a9845e --- /dev/null +++ b/test/CuTest_license.txt @@ -0,0 +1,38 @@ +NOTE + +The license is based on the zlib/libpng license. For more details see +http://www.opensource.org/licenses/zlib-license.html. The intent of the +license is to: + +- keep the license as simple as possible +- encourage the use of CuTest in both free and commercial applications + and libraries +- keep the source code together +- give credit to the CuTest contributors for their work + +If you ship CuTest in source form with your source distribution, the +following license document must be included with it in unaltered form. +If you find CuTest useful we would like to hear about it. + +LICENSE + +Copyright (c) 2003 Asim Jalis + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software in +a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not +be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. diff --git a/test/Makefile b/test/Makefile index c18b19ad03547716f048ed17eb4efd028c8739a2..31e8d2a915bfaa13cecb9cffafef2380b24f7a60 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,27 +1,34 @@ -# -# iniparser tests Makefile -# +CC ?= gcc -CC = gcc -CFLAGS = -g -I../src -LFLAGS = -L.. -liniparser -AR = ar -ARFLAGS = rcv -RM = rm -f +ifndef V +QUIET_CC = @echo "CC $@"; +QUIET_MAKE_TESTS = @echo "GN Alltests.c"; +endif +DEPS = $(shell ls ../src/*.[ch]) -default: all +SRC = $(shell ls *.c | sed 's/AllTests.c//') +OBJ = $(SRC:.c=.o) -all: iniexample parse +INCLUDE = -I../src +CFLAGS = -pipe -ansi -pedantic -Wall -Wextra -g +LDFLAGS = +all: check -iniexample: iniexample.c - $(CC) $(CFLAGS) -o iniexample iniexample.c -I../src -L.. -liniparser +check: testrun + @./testrun -parse: parse.c - $(CC) $(CFLAGS) -o parse parse.c -I../src -L.. -liniparser - -clean veryclean: - $(RM) iniexample example.ini parse +testrun: AllTests.o $(OBJ) + $(QUIET_CC)$(CC) -o $@ AllTests.o $(OBJ) $(LDFLAGS) +AllTests.o: $(OBJ) + $(QUIET_MAKE_TESTS)./make-tests.sh > AllTests.c + $(QUIET_CC)$(CC) -c -o AllTests.o AllTests.c $(CFLAGS) $(INCLUDE) +%.o: %.c $(DEPS) + $(QUIET_CC)$(CC) -c -o $@ $< $(CFLAGS) $(INCLUDE) +clean veryclean: + rm -rf AllTests.c + rm -rf $(OBJ) AllTests.o + rm -rf testrun diff --git a/test/make-tests.sh b/test/make-tests.sh new file mode 100755 index 0000000000000000000000000000000000000000..f2a3f2ac89df637a7c0acd22c4e58b2436fc09b3 --- /dev/null +++ b/test/make-tests.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash + +# Auto generate single AllTests file for CuTest. +# Searches through all *.c files in the current directory. +# Prints to stdout. +# Author: Asim Jalis +# Date: 01/08/2003 + +if test $# -eq 0 ; then FILES=*.c ; else FILES=$* ; fi + +echo ' + +/* This is auto-generated code. Edit at your own peril. */ +#include +#include + +#include "CuTest.h" + +' + +cat $FILES | grep '^void Test' | + sed -e 's/(.*$//' \ + -e 's/$/(CuTest*);/' \ + -e 's/^/extern /' + +echo \ +' + +void RunAllTests(void) +{ + CuString *output = CuStringNew(); + CuSuite* suite = CuSuiteNew(); + +' +cat $FILES | grep '^void Test' | + sed -e 's/^void //' \ + -e 's/(.*$//' \ + -e 's/^/ SUITE_ADD_TEST(suite, /' \ + -e 's/$/);/' + +echo \ +' + CuSuiteRun(suite); + CuSuiteSummary(suite, output); + CuSuiteDetails(suite, output); + printf("%s\n", output->buffer); + CuStringDelete(output); + CuSuiteDelete(suite); +} + +int main(void) +{ + RunAllTests(); + return 0; +} +' diff --git a/test/ressources/bad_ini/twisted-errors.ini b/test/ressources/bad_ini/twisted-errors.ini new file mode 100644 index 0000000000000000000000000000000000000000..4dc3bbe6e93204547a75390573695ff8ce13c95a --- /dev/null +++ b/test/ressources/bad_ini/twisted-errors.ini @@ -0,0 +1,9 @@ +# +# All of these should trigger syntax errors +# +[section] +hello +world +hello \ +world +a + b ; diff --git a/test/ressources/bad_ini/twisted-ofkey.ini b/test/ressources/bad_ini/twisted-ofkey.ini new file mode 100644 index 0000000000000000000000000000000000000000..4f2e72e8c80508432b0f01929132179328630634 --- /dev/null +++ b/test/ressources/bad_ini/twisted-ofkey.ini @@ -0,0 +1,66 @@ +# Stress testing buffers for overflows +[long] +# Shitload key size +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa=1 + diff --git a/test/ressources/bad_ini/twisted-ofval.ini b/test/ressources/bad_ini/twisted-ofval.ini new file mode 100644 index 0000000000000000000000000000000000000000..2a3cedf75d22e2ab91ea5f337f481d8d3dd251d2 --- /dev/null +++ b/test/ressources/bad_ini/twisted-ofval.ini @@ -0,0 +1,56 @@ +# Shitload data size +[long] +a=\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890; + diff --git a/test/ressources/good_ini/empty.ini b/test/ressources/good_ini/empty.ini new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/test/ressources/good_ini/spaced.ini b/test/ressources/good_ini/spaced.ini new file mode 100644 index 0000000000000000000000000000000000000000..8e78e3bfa22fd1128e724dfe13949548e9b9a433 --- /dev/null +++ b/test/ressources/good_ini/spaced.ini @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/test/ressources/good_ini/spaced2.ini b/test/ressources/good_ini/spaced2.ini new file mode 100644 index 0000000000000000000000000000000000000000..2acbd74e59638f9dfd58b114797614ac4d05ada8 --- /dev/null +++ b/test/ressources/good_ini/spaced2.ini @@ -0,0 +1,20 @@ + +# spaced2.ini + +[blanks] + + + + + + + + + + + +a=1 +b=1; +c=1; comment +d=1# comment + \ No newline at end of file diff --git a/test/ressources/good_ini/twisted.ini b/test/ressources/good_ini/twisted.ini new file mode 100644 index 0000000000000000000000000000000000000000..86e549fcbd3100384858a58b789f1861e81fe817 --- /dev/null +++ b/test/ressources/good_ini/twisted.ini @@ -0,0 +1,131 @@ +# +# Twisted.ini +# This file is meant for regression tests + +# Different blank settings around the equal sign +[blanks] +a=1 +b=1; +c=1; comment +d=1# comment + +e =1 +f =1; +g =1; comment +h =1# comment + +i= 1 +j= 1; +k= 1; comment +l= 1# comment + +m = 1 +n = 1; +o = 1; comment +p = 1# comment + +q=1 ; +r=1 ; comment +s=1 ;comment +t=1 #comment + +# Empty values +[empty] +a = '' +b = "" + +c = '' ; +d = "" ; + +e = '' ; comment +f = "" ; comment + +g = +h = ; +i = ; comment +j = # comment + +k= +l=; +m=;comment +n=# + +# Peculiar values +[peculiar] +a=';'; +b='#'# +c=';';comment +d='#'#comment +e=\; +f=\# +g=\;comment +h=\#comment +i=;; +j=## +k=;;;;;;;;;; +l=########## + +# Quotes +[quotes] +s1=' +s2='' +s3=''' +s4='''' + +d1=" +d2="" +d3=""" +d4="""" + +m1='"' +m2="'" + +h1=hello'world +h2='hello'world +h3='hello'world' + +h4=hello"world +h5="hello"world +h6="hello"world" + +# Section names +[a] +[ b] +[c ] +[ d ] +[ begin end ] +[ open[ ] + +# Multi-line inputs +[multi] +a = begin\ +end +b = begin \ +end +c = begin \ + end +d = 1\ +2\ +3\ +4 +e = 1 \ + 2 \ + 3 \ + 4 +f = 1 ; \ +hidden = because of the preceding backslash multi-lining the comment ; +visible = 1 +g = 1 #\ +and now this comment is hidden too \ +and this one too +h = 1 +multi \ +line \ +key = 1 +multi \ +line \ +key = \ +multi \ +line \ +value ; +# end of file diff --git a/test/test_dictionary.c b/test/test_dictionary.c new file mode 100644 index 0000000000000000000000000000000000000000..6d91d1081c540166777eb3203f03ec1413924202 --- /dev/null +++ b/test/test_dictionary.c @@ -0,0 +1,234 @@ +#include +#include + +#include "CuTest.h" + +/* We need to directly insert the .c file in order to test the */ +/* static functions as well */ +#include "dictionary.c" + +void Test_xstrdup(CuTest *tc) +{ + size_t i; + char *dup_str; + const char *strings[] = { + "", + "test", + " " + }; + char *string_very_long; + + /* NULL test */ + CuAssertPtrEquals(tc, NULL, xstrdup(NULL)); + + for (i = 0 ; i < sizeof(strings) / sizeof(char *) ; ++i) { + dup_str = xstrdup(strings[i]); + CuAssertStrEquals(tc, strings[i], dup_str); + free(dup_str); + } + + /* test a overflowing string */ + string_very_long = (char*) malloc(10 * 1024); + memset(string_very_long, '#', 10 * 1024); + string_very_long[10 * 1024 - 1] = '\0'; + dup_str = xstrdup(string_very_long); + CuAssertStrEquals(tc, string_very_long, dup_str); + + free(string_very_long); + free(dup_str); +} + +void Test_dictionary_grow(CuTest *tc) +{ + unsigned i; + dictionary *dic; + + dic = dictionary_new(DICTMINSZ); + CuAssertPtrNotNull(tc, dic); + CuAssertIntEquals(tc, 0, dic->n); + CuAssertIntEquals(tc, DICTMINSZ, dic->size); + + for (i = 1 ; i < 10 ; ++i) { + CuAssertIntEquals(tc, 0, dictionary_grow(dic)); + CuAssertIntEquals(tc, 0, dic->n); + CuAssertIntEquals(tc, (1 << i) * DICTMINSZ, dic->size); + } +} + +void Test_dictionary_hash(CuTest *tc) +{ + /* NULL test */ + CuAssertIntEquals(tc, 0, dictionary_hash(NULL)); +} + +void Test_dictionary_growing(CuTest *tc) +{ + int i, j; + char sec_name[32]; + char key_name[64]; + dictionary *dic; + + dic = dictionary_new(DICTMINSZ); + CuAssertPtrNotNull(tc, dic); + CuAssertIntEquals(tc, 0, dic->n); + + /* Makes the dictionary grow */ + for (i = 1 ; i < 101; ++i) { + sprintf(sec_name, "sec%d", i); + CuAssertIntEquals(tc, 0, dictionary_set(dic, sec_name, "")); + for (j = 1 ; j < 11; ++j) { + sprintf(key_name, "%s:key%d", sec_name, j); + CuAssertIntEquals(tc, 0, dictionary_set(dic, key_name, "dummy_value")); + CuAssertIntEquals(tc, i + (i - 1) * 10 + j, dic->n); + } + } + + /* Shrink the dictionary */ + for (i = 100 ; i > 0; --i) { + sprintf(sec_name, "sec%d", i); + for (j = 10 ; j > 0; --j) { + sprintf(key_name, "%s:key%d", sec_name, j); + dictionary_unset(dic, key_name); + } + dictionary_unset(dic, sec_name); + CuAssertIntEquals(tc, (i - 1) * (11), dic->n); + } + + dictionary_del(dic); +} + +static char *get_dump(dictionary *d) +{ + FILE *fd; + char *dump_buff; + int dump_size; + + /* Dump the dictionary in temporary file */ + fd = tmpfile(); + if (fd == NULL) + return NULL; + dictionary_dump(d, fd); + + /* Retrieve the dump file */ + dump_size = ftell(fd); + if (dump_size == -1) { + fclose(fd); + return NULL; + } + rewind(fd); + + dump_buff = (char*) calloc(1, dump_size + 1); + if (dump_buff == NULL) { + fclose(fd); + return NULL; + } + fread(dump_buff, 1, dump_size, fd); + + fclose(fd); + return dump_buff; +} + +void Test_dictionary_unset(CuTest *tc) +{ + int i, j; + char sec_name[32]; + char key_name[64]; + dictionary *dic1; + dictionary *dic2; + char *dic1_dump; + char *dic2_dump; + + /* try dummy unsets */ + dictionary_unset(NULL, NULL); + dictionary_unset(NULL, key_name); + + /* Generate two similar dictionaries */ + dic1 = dictionary_new(DICTMINSZ); + CuAssertPtrNotNull(tc, dic1); + for (i = 1 ; i < 10; ++i) { + sprintf(sec_name, "sec%d", i); + dictionary_set(dic1, sec_name, ""); + for (j = 1 ; j < 10; ++j) { + sprintf(key_name, "%s:key%d", sec_name, j); + dictionary_set(dic1, key_name, "dummy_value"); + } + } + dic2 = dictionary_new(DICTMINSZ); + CuAssertPtrNotNull(tc, dic2); + for (i = 1 ; i < 10; ++i) { + sprintf(sec_name, "sec%d", i); + dictionary_set(dic2, sec_name, ""); + for (j = 1 ; j < 10; ++j) { + sprintf(key_name, "%s:key%d", sec_name, j); + dictionary_set(dic2, key_name, "dummy_value"); + } + } + + /* Make sure the dictionaries are the same */ + dic1_dump = get_dump(dic1); + dic2_dump = get_dump(dic2); + CuAssertStrEquals(tc, dic1_dump, dic2_dump); + free(dic1_dump); + free(dic2_dump); + + /* Those tests should not change the dictionary */ + dictionary_unset(dic2, NULL); + dictionary_unset(dic2, "bad_key"); + + /* dic1 and dic2 must still be the same */ + dic1_dump = get_dump(dic1); + dic2_dump = get_dump(dic2); + CuAssertStrEquals(tc, dic1_dump, dic2_dump); + free(dic1_dump); + free(dic2_dump); +} + +void Test_dictionary_dump(CuTest *tc) +{ + int i, j; + char sec_name[32]; + char key_name[64]; + dictionary *dic; + char *dump_buff; + const char dump_real[] = "\ + sec1\t[]\n\ + sec1:key1\t[dummy_value]\n\ + sec1:key2\t[dummy_value]\n\ + sec1:key3\t[dummy_value]\n\ + sec1:key4\t[dummy_value]\n\ + sec2\t[]\n\ + sec2:key1\t[dummy_value]\n\ + sec2:key2\t[dummy_value]\n\ + sec2:key3\t[dummy_value]\n\ + sec2:key4\t[dummy_value]\n\ +"; + + dic = dictionary_new(DICTMINSZ); + CuAssertPtrNotNull(tc, dic); + + /* Try dummy values */ + dictionary_dump(NULL, NULL); + dictionary_dump(dic, NULL); + + /* Try with empty dictionary first */ + dump_buff = get_dump(dic); + CuAssertStrEquals(tc, "empty dictionary\n", dump_buff); + free(dump_buff); + + /* Populate the dictionary */ + for (i = 1 ; i < 3; ++i) { + sprintf(sec_name, "sec%d", i); + dictionary_set(dic, sec_name, ""); + for (j = 1 ; j < 5; ++j) { + sprintf(key_name, "%s:key%d", sec_name, j); + dictionary_set(dic, key_name, "dummy_value"); + } + } + + /* Check the dump file */ + dump_buff = get_dump(dic); + CuAssertStrEquals(tc, dump_real, dump_buff); + free(dump_buff); + + dictionary_del(dic); +} diff --git a/test/test_iniparser.c b/test/test_iniparser.c new file mode 100644 index 0000000000000000000000000000000000000000..6e8c7a19ca46509efb49d4053a559d0b354d97e6 --- /dev/null +++ b/test/test_iniparser.c @@ -0,0 +1,574 @@ +#include +#include +#include +#include +#include + +#include "CuTest.h" +#include "dictionary.h" + +/* We need to directly insert the .c file in order to test the */ +/* static functions as well */ +#include "iniparser.c" + +#define GOOD_INI_PATH "ressources/good_ini" +#define BAD_INI_PATH "ressources/bad_ini" + + +/* Tool function to create and populate a generic non-empty dictionary */ +static dictionary * generate_dictionary(unsigned sections, unsigned entries_per_section) +{ + unsigned i, j ; + dictionary * dic; + char sec_name[32]; + char key_name[64]; + char key_value[32]; + + dic = dictionary_new(sections + sections * entries_per_section); + if (dic == NULL) + return NULL; + + /* Insert the sections */ + for (i = 0; i < sections; ++i) { + sprintf(sec_name, "sec%d", i); + dictionary_set(dic, sec_name, ""); + for (j = 0; j < entries_per_section; ++j) { + /* Populate the section with the entries */ + sprintf(key_name, "%s:key%d", sec_name, j); + sprintf(key_value, "value-%d/%d", i, j); + dictionary_set(dic, key_name, key_value); + } + } + + return dic; +} + +void Test_iniparser_strlwc(CuTest *tc) +{ + char out_buffer[128]; + + /* NULL ptr as input */ + CuAssertPtrEquals(tc, NULL, strlwc(NULL, NULL, 0)); + CuAssertPtrEquals(tc, NULL, strlwc(NULL, out_buffer, sizeof (out_buffer))); + CuAssertPtrEquals(tc, NULL, strlwc("", NULL, sizeof (out_buffer))); + CuAssertPtrEquals(tc, NULL, strlwc("", out_buffer, 0)); + CuAssertPtrEquals(tc, NULL, strlwc(NULL, NULL, 0)); + + /* empty string */ + CuAssertStrEquals(tc, "", strlwc("", out_buffer, sizeof (out_buffer))); + + CuAssertStrEquals(tc, " ", strlwc(" ", out_buffer, sizeof (out_buffer))); + CuAssertStrEquals(tc, "test", strlwc("test", out_buffer, sizeof (out_buffer))); + CuAssertStrEquals(tc, "test", strlwc("TEST", out_buffer, sizeof (out_buffer))); + CuAssertStrEquals(tc, "test", strlwc("TeSt", out_buffer, sizeof (out_buffer))); + CuAssertStrEquals(tc, "test test", + strlwc("TEST TEST", out_buffer, sizeof (out_buffer))); + CuAssertStrEquals(tc, "very long string !!!!!!!", + strlwc("very long string !!!!!!!", out_buffer, sizeof (out_buffer))); + CuAssertStrEquals(tc, "cutted string", strlwc("cutted string<---here", out_buffer, 14)); + + /* test using same buffer as input and output */ + strcpy(out_buffer, "OVERWRITE ME !"); + CuAssertPtrNotNull(tc, strlwc(out_buffer, out_buffer, sizeof(out_buffer))); + CuAssertStrEquals(tc, "overwrite me !", out_buffer); +} + +void Test_iniparser_strstrip(CuTest *tc) +{ + /* First element in the array is the expected stripping result */ + const char *strings_empty[] = { + "", + " ", + "\n\n\n\n", + "\t\t\t\t", + "\n \t\n\t\n " + }; + const char *strings_test[] = { + "test", + "test ", + "test ", + " test", + " test ", + "\ttest\t", + "\ttest\n" + + }; + const char *test_with_spaces = "I am a test with\tspaces."; + char stripped[ASCIILINESZ+1]; + char error_msg[128]; + unsigned i; + + /* NULL ptr as input */ + strstrip(NULL); + + /* empty string */ + for (i = 0 ; i < sizeof (strings_empty) / sizeof (char *) ; ++i) { + strcpy(stripped, strings_empty[i]); + strstrip(stripped); + sprintf(error_msg, "Bad stripping : strstrip(\"%s\") ==> \"%s\"", + strings_empty[i], stripped); + CuAssertStrEquals_Msg(tc, error_msg, stripped, strings_empty[0]); + } + + /* test string */ + for (i = 0 ; i < sizeof (strings_test) / sizeof (char *) ; ++i) { + strcpy(stripped, strings_test[i]); + strstrip(stripped); + sprintf(error_msg, "Bad stripping : strstrip(\"%s\") ==> \"%s\"", + strings_test[i], stripped); + CuAssertStrEquals_Msg(tc, error_msg, strings_test[0], stripped); + } + strcpy(stripped, "."); + strstrip(stripped); + CuAssertStrEquals(tc, ".", stripped); + + /* string containing spaces */ + strcpy(stripped, test_with_spaces); + strstrip(stripped); + CuAssertStrEquals(tc, test_with_spaces, stripped); +} + +void Test_iniparser_getnsec(CuTest *tc) +{ + int i; + char sec_name[32]; + dictionary *dic; + + /* NULL test */ + CuAssertIntEquals(tc, -1, iniparser_getnsec(NULL)); + + /* Empty dictionary */ + dic = dictionary_new(10); + CuAssertIntEquals(tc, 0, iniparser_getnsec(dic)); + dictionary_del(dic); + + /* Regular dictionary */ + dic = generate_dictionary(512, 0); + CuAssertIntEquals(tc, 512, iniparser_getnsec(dic)); + + /* Check after removing sections */ + for (i = 1; i < 512; ++i) { + sprintf(sec_name, "sec%d", i); + dictionary_unset(dic, sec_name); + CuAssertIntEquals(tc, 512 - i, iniparser_getnsec(dic)); + } + dictionary_del(dic); + + /* Mix sections and regular keys */ + dic = generate_dictionary(10, 512); + CuAssertIntEquals(tc, 10, iniparser_getnsec(dic)); + dictionary_del(dic); +} + +void Test_iniparser_getsecname(CuTest *tc) +{ + unsigned i; + char sec_name[32]; + dictionary *dic; + /* NULL test */ + CuAssertTrue(tc, iniparser_getsecname(NULL, 0) == NULL); + + /* Empty dictionary */ + dic = dictionary_new(10); + CuAssertPtrEquals(tc, NULL, iniparser_getsecname(dic, 0)); + dictionary_del(dic); + + /* Sections without entries dictionary */ + dic = generate_dictionary(100, 0); + for (i = 0; i < 100; ++i) { + sprintf(sec_name, "sec%d", i); + CuAssertStrEquals(tc, sec_name, iniparser_getsecname(dic, i)); + } + dictionary_del(dic); + + /* Generic dictionary */ + dic = generate_dictionary(10, 100); + for (i = 0; i < 10; ++i) { + sprintf(sec_name, "sec%d", i); + CuAssertStrEquals(tc, sec_name, iniparser_getsecname(dic, i)); + } + dictionary_del(dic); +} + +void Test_iniparser_getseckeys(CuTest *tc) +{ + unsigned i; + char key_name[64]; + dictionary *dic; + const char ** sections; + /* NULL test */ + CuAssertPtrEquals(tc, NULL, iniparser_getseckeys(NULL, NULL)); + CuAssertPtrEquals(tc, NULL, iniparser_getseckeys(NULL, "dummy")); + + /* Empty dictionary */ + dic = dictionary_new(10); + CuAssertPtrEquals(tc, NULL, iniparser_getseckeys(dic, NULL)); + CuAssertPtrEquals(tc, NULL, iniparser_getseckeys(dic, "dummy")); + dictionary_del(dic); + + /* Generic dictionary */ + dic = generate_dictionary(100, 10); + CuAssertPtrEquals(tc, NULL, iniparser_getseckeys(dic, NULL)); + CuAssertPtrEquals(tc, NULL, iniparser_getseckeys(dic, "dummy")); + sections = iniparser_getseckeys(dic, "sec42"); + CuAssertPtrNotNull(tc, sections); + for (i = 0; i < 10; ++i) { + sprintf(key_name, "sec42:key%d", i); + CuAssertStrEquals(tc, key_name, sections[i]); + } + free(sections); + + /* Remove some keys to make the dictionary more real */ + dictionary_unset(dic, "sec42"); + dictionary_unset(dic, "sec99:key9"); + dictionary_unset(dic, "sec0:key0"); + dictionary_unset(dic, "sec0:key1"); + dictionary_unset(dic, "sec0:key2"); + + CuAssertPtrEquals(tc, NULL, iniparser_getseckeys(dic, "sec42")); + sections = iniparser_getseckeys(dic, "sec99"); + CuAssertPtrNotNull(tc, sections); + for (i = 0; i < 9; ++i) { + sprintf(key_name, "sec99:key%d", i); + CuAssertStrEquals(tc, key_name, sections[i]); + } + free(sections); + sections = iniparser_getseckeys(dic, "sec0"); + CuAssertPtrNotNull(tc, sections); + for (i = 0; i < 7; ++i) { + sprintf(key_name, "sec0:key%d", i + 3); + CuAssertStrEquals(tc, key_name, sections[i]); + } + free(sections); + + dictionary_del(dic); +} + +void Test_iniparser_getstring(CuTest *tc) +{ + dictionary *dic; + /* NULL test */ + CuAssertPtrEquals(tc, NULL, iniparser_getstring(NULL, NULL, NULL)); + CuAssertPtrEquals(tc, NULL, iniparser_getstring(NULL, "dummy", NULL)); + + /* Check the def return element */ + dic = dictionary_new(10); + CuAssertPtrEquals(tc, NULL, iniparser_getstring(dic, "dummy", NULL)); + CuAssertStrEquals(tc, "def", iniparser_getstring(dic, NULL, "def")); + CuAssertStrEquals(tc, "def", iniparser_getstring(dic, "dummy", "def")); + dictionary_del(dic); + + /* Generic dictionary */ + dic = generate_dictionary(100, 10); + CuAssertStrEquals(tc, "value-0/0", + iniparser_getstring(dic, "sec0:key0", NULL)); + CuAssertStrEquals(tc, "value-42/5", + iniparser_getstring(dic, "sec42:key5", NULL)); + CuAssertStrEquals(tc, "value-99/9", + iniparser_getstring(dic, "sec99:key9", NULL)); + dictionary_del(dic); +} + +void Test_iniparser_getint(CuTest *tc) +{ + unsigned i; + char key_name[64]; + dictionary *dic; + const struct { int num; const char *value; } good_val[] = { + { 0, "0" }, + { 1, "1" }, + { -1, "-1" }, + { 1000, "1000" }, + { 077, "077" }, + { -01000, "-01000" }, + { 0xFFFF, "0xFFFF" }, + { -0xFFFF, "-0xFFFF" }, + { 0x4242, "0x4242" }, + { 0, NULL} /* must be last */ + }; + const char *bad_val[] = { + "", + "notanumber", + "0x", + "k2000", + " ", + "0xG1" + }; + /* NULL test */ + CuAssertIntEquals(tc, -42, iniparser_getint(NULL, NULL, -42)); + CuAssertIntEquals(tc, -42, iniparser_getint(NULL, "dummy", -42)); + + /* Check the def return element */ + dic = dictionary_new(10); + CuAssertIntEquals(tc, 42, iniparser_getint(dic, "dummy", 42)); + CuAssertIntEquals(tc, 0xFFFF, iniparser_getint(dic, NULL, 0xFFFF)); + CuAssertIntEquals(tc, -0xFFFF, iniparser_getint(dic, "dummy", -0xFFFF)); + dictionary_del(dic); + + /* Generic dictionary */ + dic = dictionary_new(10); + for (i = 0; good_val[i].value != NULL; ++i) { + sprintf(key_name, "int:value%d", i); + dictionary_set(dic, key_name, good_val[i].value); + } + for (i = 0; good_val[i].value != NULL; ++i) { + sprintf(key_name, "int:value%d", i); + CuAssertIntEquals(tc, good_val[i].num, + iniparser_getint(dic, key_name, 0)); + } + dictionary_del(dic); + + /* Test bad names */ + dic = dictionary_new(10); + for (i = 0; i < sizeof (bad_val) / sizeof (char *); ++i) { + sprintf(key_name, "int:bad%d", i); + dictionary_set(dic, key_name, bad_val[i]); + } + for (i = 0; i < sizeof (bad_val) / sizeof (char *); ++i) { + sprintf(key_name, "int:bad%d", i); + CuAssertIntEquals(tc, 0, + iniparser_getint(dic, key_name, 0)); + } + dictionary_del(dic); +} + +void Test_iniparser_getdouble(CuTest *tc) +{ + dictionary *dic; + + /* NULL test */ + CuAssertDblEquals(tc, -42, iniparser_getdouble(NULL, NULL, -42), 0); + CuAssertDblEquals(tc, 4.2, iniparser_getdouble(NULL, "dummy", 4.2), 0); + + /* Check the def return element */ + dic = dictionary_new(10); + CuAssertDblEquals(tc, 3.1415, iniparser_getdouble(dic, "dummy", 3.1415), 0); + CuAssertDblEquals(tc, 0xFFFFFFFF, iniparser_getdouble(dic, NULL, 0xFFFFFFFF), 0); + CuAssertDblEquals(tc, -0xFFFFFFFF, iniparser_getdouble(dic, "dummy", -0xFFFFFFFF), 0); + + /* Insert some values */ + dictionary_set(dic, "double", ""); + dictionary_set(dic, "double:good0", "0"); + dictionary_set(dic, "double:good1", "-0"); + dictionary_set(dic, "double:good2", "1.0"); + dictionary_set(dic, "double:good3", "3.1415"); + dictionary_set(dic, "double:good4", "6.6655957"); + dictionary_set(dic, "double:good5", "-123456789.123456789"); + + /* Add dummy stuff too */ + dictionary_set(dic, "double:bad0", "foo"); + + /* Get back the values */ + CuAssertDblEquals(tc, 0, iniparser_getdouble(dic, "double:good0", 0xFF), 0); + CuAssertDblEquals(tc, 0, iniparser_getdouble(dic, "double:good1", 0xFF), 0); + CuAssertDblEquals(tc, 1.0, iniparser_getdouble(dic, "double:good2", 0xFF), 0); + CuAssertDblEquals(tc, 3.1415, iniparser_getdouble(dic, "double:good3", 0xFF), 0); + CuAssertDblEquals(tc, 6.6655957, iniparser_getdouble(dic, "double:good4", 0xFF), 0); + CuAssertDblEquals(tc, -123456789.123456789, + iniparser_getdouble(dic, "double:good5", 0xFF), 0); + + CuAssertDblEquals(tc, 0, iniparser_getdouble(dic, "double:bad0", 42.42), 0); + + dictionary_del(dic); +} + +void Test_iniparser_getboolean(CuTest *tc) +{ + unsigned i; + char key_name[64]; + + dictionary *dic; + const char *token_true[] = { + "1", + "true", + "t", + "TRUE", + "T", + "yes", + "y", + "YES" + "Y", + NULL + }; + const char *token_false[] = { + "0", + "false", + "f", + "FALSE", + "F", + "no", + "n", + "NO", + "N", + NULL + }; + + /* NULL test */ + CuAssertIntEquals(tc, 1, iniparser_getboolean(NULL, NULL, 1)); + CuAssertIntEquals(tc, 1, iniparser_getboolean(NULL, "dummy", 1)); + + /* Check the def return element */ + dic = dictionary_new(10); + CuAssertIntEquals(tc, 1, iniparser_getboolean(dic, "dummy", 1)); + CuAssertIntEquals(tc, 0, iniparser_getboolean(dic, NULL, 0)); + CuAssertIntEquals(tc, 1, iniparser_getboolean(dic, "dummy", 1)); + + for (i = 0; token_true[i] != NULL; ++i) { + sprintf(key_name, "bool:true%d", i); + iniparser_set(dic, key_name, token_true[i]); + } + for (i = 0; token_false[i] != NULL; ++i) { + sprintf(key_name, "bool:false%d", i); + iniparser_set(dic, key_name, token_false[i]); + } + + for (i = 0; token_true[i] != NULL; ++i) { + sprintf(key_name, "bool:true%d", i); + CuAssertIntEquals(tc, 1, iniparser_getboolean(dic, key_name, 0)); + } + for (i = 0; token_false[i] != NULL; ++i) { + sprintf(key_name, "bool:false%d", i); + CuAssertIntEquals(tc, 0, iniparser_getboolean(dic, key_name, 1)); + } + + /* Test bad boolean */ + iniparser_set(dic, "bool:bad0", ""); + iniparser_set(dic, "bool:bad1", "m'kay"); + iniparser_set(dic, "bool:bad2", "42"); + iniparser_set(dic, "bool:bad3", "_true"); + CuAssertIntEquals(tc, 0xFF, iniparser_getboolean(dic, "bool:bad0", 0xFF)); + CuAssertIntEquals(tc, 0xFF, iniparser_getboolean(dic, "bool:bad1", 0xFF)); + CuAssertIntEquals(tc, 0xFF, iniparser_getboolean(dic, "bool:bad2", 0xFF)); + CuAssertIntEquals(tc, 0xFF, iniparser_getboolean(dic, "bool:bad3", 0xFF)); + + dictionary_del(dic); +} + +void Test_iniparser_line(CuTest *tc) +{ + char section [ASCIILINESZ+1] ; + char key [ASCIILINESZ+1] ; + char val [ASCIILINESZ+1] ; + + /* Test empty line */ + CuAssertIntEquals(tc, LINE_EMPTY, iniparser_line("", section, key, val)); + CuAssertIntEquals(tc, LINE_EMPTY, iniparser_line(" ", section, key, val)); + CuAssertIntEquals(tc, LINE_EMPTY, iniparser_line("\t", section, key, val)); + + /* Test valid syntax */ + CuAssertIntEquals(tc, LINE_SECTION, iniparser_line("[s]", section, key, val)); + CuAssertStrEquals(tc, "s", section); + + CuAssertIntEquals(tc, LINE_SECTION, iniparser_line("[ section ]", section, key, val)); + CuAssertStrEquals(tc, "section", section); + + CuAssertIntEquals(tc, LINE_VALUE, iniparser_line("k=1", section, key, val)); + CuAssertStrEquals(tc, "k", key); + CuAssertStrEquals(tc, "1", val); + + CuAssertIntEquals(tc, LINE_VALUE, iniparser_line("key = 0x42", section, key, val)); + CuAssertStrEquals(tc, "key", key); + CuAssertStrEquals(tc, "0x42", val); + + CuAssertIntEquals(tc, LINE_VALUE, iniparser_line("key= value with spaces", section, key, val)); + CuAssertStrEquals(tc, "key", key); + CuAssertStrEquals(tc, "value with spaces", val); + + CuAssertIntEquals(tc, LINE_VALUE, iniparser_line("k =_!<>''", section, key, val)); + CuAssertStrEquals(tc, "k", key); + CuAssertStrEquals(tc, "_!<>''", val); + + CuAssertIntEquals(tc, LINE_VALUE, iniparser_line("empty_value =", section, key, val)); + CuAssertStrEquals(tc, "empty_value", key); + CuAssertStrEquals(tc, "", val); + + CuAssertIntEquals(tc, LINE_VALUE, iniparser_line("key =\tval # comment", section, key, val)); + CuAssertStrEquals(tc, "key", key); + CuAssertStrEquals(tc, "val", val); + + CuAssertIntEquals(tc, LINE_VALUE, iniparser_line("key \n\n = \n val", section, key, val)); + CuAssertStrEquals(tc, "key", key); + CuAssertStrEquals(tc, "val", val); + + CuAssertIntEquals(tc, LINE_COMMENT, iniparser_line(";comment", section, key, val)); + CuAssertIntEquals(tc, LINE_COMMENT, iniparser_line(" # comment", section, key, val)); + + /* Test syntax error */ + CuAssertIntEquals(tc, LINE_ERROR, iniparser_line("empty_value", section, key, val)); + CuAssertIntEquals(tc, LINE_ERROR, iniparser_line("not finished\\", section, key, val)); + CuAssertIntEquals(tc, LINE_ERROR, iniparser_line("0x42 / 0b101010", section, key, val)); +} + +void Test_iniparser_load(CuTest *tc) +{ + DIR *dir; + struct dirent *curr; + struct stat curr_stat; + dictionary *dic; + char ini_path[256]; + + /* Dummy tests */ + dic = iniparser_load("/you/shall/not/path"); + CuAssertPtrEquals(tc, NULL, dic); + + /* Test all the good .ini files */ + dir = opendir(GOOD_INI_PATH); + CuAssertPtrNotNullMsg(tc, "Cannot open good .ini conf directory", dir); + for (curr = readdir(dir); curr != NULL; curr = readdir(dir)) { + sprintf(ini_path, "%s/%s", GOOD_INI_PATH, curr->d_name); + stat(ini_path, &curr_stat); + if (S_ISREG(curr_stat.st_mode)) { + dic = iniparser_load(ini_path); + CuAssertPtrNotNullMsg(tc, ini_path, dic); + dictionary_del(dic); + } + } + closedir(dir); + + /* Test all the bad .ini files */ + dir = opendir(BAD_INI_PATH); + CuAssertPtrNotNullMsg(tc, "Cannot open bad .ini conf directory", dir); + for (curr = readdir(dir); curr != NULL; curr = readdir(dir)) { + sprintf(ini_path, "%s/%s", BAD_INI_PATH, curr->d_name); + stat(ini_path, &curr_stat); + if (S_ISREG(curr_stat.st_mode)) { + dic = iniparser_load(ini_path); + CuAssertPtrEquals_Msg(tc, ini_path, NULL, dic); + dictionary_del(dic); + } + } + closedir(dir); +} + +void Test_dictionary_wrapper(CuTest *tc) +{ + dictionary *dic; + + dic = dictionary_new(10); + + CuAssertIntEquals(tc, -1, iniparser_set(dic, NULL, NULL)); + CuAssertIntEquals(tc, -1, iniparser_set(NULL, "section", "value")); + + CuAssertIntEquals(tc, 0, iniparser_set(dic, "section", NULL)); + CuAssertIntEquals(tc, 0, iniparser_set(dic, "section:key", "value")); + + CuAssertStrEquals(tc, "value", iniparser_getstring(dic, "section:key", NULL)); + /* reset the key's value*/ + CuAssertIntEquals(tc, 0, iniparser_set(dic, "section:key", NULL)); + CuAssertStrEquals(tc, NULL, iniparser_getstring(dic, "section:key", "dummy")); + CuAssertIntEquals(tc, 0, iniparser_set(dic, "section:key", "value")); + CuAssertStrEquals(tc, "value", iniparser_getstring(dic, "section:key", NULL)); + + iniparser_unset(dic, "section:key"); + CuAssertStrEquals(tc, "dummy", iniparser_getstring(dic, "section:key", "dummy")); + CuAssertStrEquals(tc, NULL, iniparser_getstring(dic, "section", "dummy")); + + CuAssertIntEquals(tc, 0, iniparser_set(dic, "section:key", NULL)); + CuAssertIntEquals(tc, 0, iniparser_set(dic, "section:key1", NULL)); + CuAssertIntEquals(tc, 0, iniparser_set(dic, "section:key2", NULL)); + + iniparser_unset(dic, "section"); + CuAssertStrEquals(tc, NULL, iniparser_getstring(dic, "section", NULL)); + + iniparser_freedict(dic); +}