Update iniparser

This commit is contained in:
Ralph S. (Coolguy3289) 2020-01-20 00:49:35 -05:00
parent d5103ffbe5
commit 5b34545a3b
36 changed files with 2388 additions and 483 deletions

View file

@ -1,4 +1,5 @@
Author: Nicolas Devillard <ndevilla@free.fr>
Authors:
Nicolas Devillard @ndevilla, Emmanuel Leblond @TouilleMan
This tiny library has received countless contributions and I have
not kept track of all the people who contributed. Let them be thanked

View file

@ -0,0 +1,37 @@
# iniparser FAQ #
## Is iniparser thread safe ?
Starting from version 4, iniparser is designed to be thread-safe, provided
you surround it with your own mutex logic. The choice to not add thread
safety inside the library has been made to provide more freedom for the
developer, especially when dealing with their own custom reading logic
e.g. acquiring the mutex, reading entries with iniparser, then releasing
the mutex.
## Your build system isn't portable, let me help you...
We have received countless contributions from distrib people to modify the
Makefile into what they think is the "standard", which we had to reject.
The default, standard Makefile for Debian bears absolutely no relationship
with the one from SuSE or RedHat and there is no possible way to merge them
all. A build system is something so specific to each environment that it
is completely pointless to try and push anything that claims to be
standard. The provided Makefile in this project is purely here to have
something to play with quickly.
## iniparser_dump() is slow
The dumping functions are based on fprintf, which can turn out to be
surprisingly slow on some embedded platforms. You can replace fprintf by a
combined use of sprintf and fwrite, or you can use setvbuf() to change
buffering parameters to accomodate fprintf(). Something like:
setvbuf(f, NULL, _IOFBF, 0);
## iniparser does not compile with my C++ compiler!
See the docs: iniparser is a C library. C++ is quite a different language,
despite the promises of compatibility. You will have to modify iniparser
quite heavily to make it work with a C++ compiler. Good luck!

View file

@ -0,0 +1,27 @@
# iniparser FAQ #
## iniparser线程安全吗 ?
从版本4开始iniparser被设计成线程安全的你需要围绕它处理你自己的互斥逻辑。
选择不在库中添加线程安全,是为开发者提供更多的自由,特别是在处理他们自己的读
逻辑。如获取互斥锁用iniparser阅读条目然后释放互斥体。
## 你的构建系统不可移植,让我来帮助你...
我们已经收到了来各地的开发人员的无数贡献将Makefile修改为他们认为是“标准”的
内容,但是我们不得不拒绝。 默认情况下Debian的标准Makefile与SuSE或RedHat完
全没有关系,没有可能的方式将它们全部合并。 构建系统对于每个环境来说都是特别的,
尝试推动任何声称是标准的东西是完全没有意义的。 在这个项目中提供的Makefile纯粹
是为了快速的把库跑起来。
## iniparser_dump() 速度慢
dump函数是基于fprintf的在嵌入式平台上它可能导致很慢。你可以把fprintf换成
sprintf和fwrite的组合或者可以使用setvbfu()来改变fprintf的缓存参数。比如
setvbuf(f, NULL, _IOFBF, 0);
## 用我的c++编译器不能编译iniparser!
看文档iniparser是一个C库。虽然C++兼容C但它却是另外一门语言。让iniparser在
C++编译器下工作,会是一份繁重的工作。祝你好运!

View file

@ -1,11 +1,19 @@
#
# iniparser Makefile
#
.PHONY: example
# Compiler settings
CC ?= gcc
CFLAGS ?= -g -O0
CFLAGS += -fPIC -Wall -ansi -std=c99 -pedantic
CFLAGS += -fPIC -Wall -Wextra -ansi -pedantic
ifndef DEBUG
ADDITIONAL_CFLAGS ?= -O2
else
ADDITIONAL_CFLAGS ?= -g
endif
CFLAGS += ${ADDITIONAL_CFLAGS}
# Ar settings to build the library
AR ?= ar
@ -15,6 +23,9 @@ SHLD = ${CC} ${CFLAGS}
LDSHFLAGS = -shared -Wl,-Bsymbolic
LDFLAGS += -Wl,-rpath -Wl,/usr/lib -Wl,-rpath,/usr/lib
# .so.0 is for version 3.x, .so.1 is 4.x
SO_TARGET ?= libiniparser.so.1
# Set RANLIB to ranlib on systems that require it (Sun OS < 4, Mac OSX)
# RANLIB = ranlib
RANLIB = true
@ -45,28 +56,31 @@ SRCS = src/iniparser.c \
OBJS = $(SRCS:.c=.o)
default: libiniparser.a libiniparser.so
default: libiniparser.a $(SO_TARGET)
libiniparser.a: $(OBJS)
$(AR) $(ARFLAGS) $@ $^
$(RANLIB) $@
$(QUIET_AR)$(AR) $(ARFLAGS) $@ $^
$(QUIET_RANLIB)$(RANLIB) $@
libiniparser.so: $(OBJS)
$(QUIET_LINK)$(SHLD) $(LDSHFLAGS) $(LDFLAGS) -o $@.0 $(OBJS) \
-Wl,-soname=`basename $@`.0
$(SO_TARGET): $(OBJS)
$(QUIET_LINK)$(SHLD) $(LDSHFLAGS) $(LDFLAGS) -o $(SO_TARGET) $(OBJS) \
-Wl,-soname=`basename $(SO_TARGET)`
clean:
$(RM) $(OBJS)
@(cd test ; $(MAKE) clean)
veryclean:
$(RM) $(OBJS) libiniparser.a libiniparser.so*
$(RM) $(OBJS) libiniparser.a $(SO_TARGET)
rm -rf ./html ; mkdir html
cd example ; $(MAKE) veryclean
cd test ; $(MAKE) veryclean
docs:
@(cd doc ; $(MAKE))
check: default
check: $(SO_TARGET)
@(cd test ; $(MAKE))
.PHONY: default clean veryclean docs check
example: libiniparser.a
@(cd example ; $(MAKE))

View file

@ -1,12 +0,0 @@
Welcome to iniParser -- version 3.1
released 08 Apr 2012
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
Sun Apr 8 16:38:09 CEST 2012

View file

@ -0,0 +1,44 @@
[![Build Status](https://travis-ci.org/ndevilla/iniparser.svg?branch=master)](https://travis-ci.org/ndevilla/iniparser)
# 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.1. Version 4.0 introduces breaking changes in the api.
Older versions 3.1 and 3.2 with the legacy api are available as tags.
## V - FAQ
See [FAQ-en.md](FAQ-en.md) in this directory for answers to Frequently Asked Questions.
还有简化中国翻译在[FAQ-zhcn.md](FAQ-zhcn.md).

View file

@ -1,5 +1,5 @@
PROJECT_NAME = iniparser
PROJECT_NUMBER = 3.1
PROJECT_NUMBER = 4.1
OUTPUT_DIRECTORY = ..
OUTPUT_LANGUAGE = English
EXTRACT_ALL = YES

View file

@ -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

View file

@ -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) {

View file

@ -9,7 +9,7 @@
<body>
<!-- Generated by Doxygen 1.6.3 -->
<div class="contents">
<h1>iniparser documentation </h1><h3 class="version">3.0 </h3><h2><a class="anchor" id="welcome">
<h1>iniparser documentation </h1><h3 class="version">4.0 </h3><h2><a class="anchor" id="welcome">
Introduction</a></h2>
<p>iniParser is a simple C library offering ini file parsing services. The library is pretty small (less than 1500 lines of C) and robust, and does not depend on any other external library to compile. It is written in ANSI C and should compile on most platforms without difficulty.</p>
<h2><a class="anchor" id="inidef">
@ -94,8 +94,8 @@ Known defects</a></h2>
Authors</a></h2>
<p>Nicolas Devillard (ndevilla AT free DOT fr). </p>
</div>
<hr class="footer"/><address style="text-align: right;"><small>Generated on Wed Mar 2 22:04:58 2011 for iniparser by&nbsp;
<hr class="footer"/><address style="text-align: right;"><small>Generated on Sun Jun 12 19:07:18 2016 for iniparser by&nbsp;
<a href="http://www.doxygen.org/index.html">
<img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.6.3 </small></address>
<img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.8.11 </small></address>
</body>
</html>

View file

@ -0,0 +1,12 @@
prefix=/usr
exec_prefix=/usr
libdir=${exec_prefix}/lib
includedir=${prefix}/include
datarootdir=${prefix}/share
datadir=${datarootdir}
Name: libiniparser
Description: Iniparser library
Version: 4.1
Libs: -L${libdir} -liniparser
Cflags: -I${includedir}

View file

@ -33,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
@ -58,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 ;
@ -66,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
---------------------------------------------------------------------------*/
@ -94,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 ; i<len ; i++) {
hash += (unsigned)key[i] ;
@ -116,7 +146,7 @@ unsigned dictionary_hash(const char * key)
it. If you do not know in advance (roughly) the number of entries in the
dictionary, give size=0.
*/
/*--------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
dictionary * dictionary_new(size_t size)
{
dictionary * d ;
@ -124,13 +154,13 @@ dictionary * dictionary_new(size_t size)
/* If no size was specified, allocate space for DICTMINSZ */
if (size<DICTMINSZ) size=DICTMINSZ ;
d = calloc(1, sizeof *d) ;
d = (dictionary*) calloc(1, sizeof *d) ;
if (d) {
d->size = 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 ;
}
@ -146,7 +176,7 @@ 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<d->size ; i++) {
@ -176,10 +206,10 @@ 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<d->size ; i++) {
@ -224,7 +254,7 @@ char * dictionary_get(dictionary * d, const char * key, char * def)
/*--------------------------------------------------------------------------*/
int dictionary_set(dictionary * d, const char * key, const char * val)
{
size_t i ;
ssize_t i ;
unsigned hash ;
if (d==NULL || key==NULL) return -1 ;
@ -241,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 ;
}
@ -251,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
@ -272,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 ;
@ -292,9 +314,9 @@ 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;
}
@ -338,9 +360,9 @@ 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) {
@ -356,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 ; i<NVALS ; i++) {
sprintf(cval, "%04d", i);
dictionary_set(d, cval, "salut");
}
printf("getting %d values...\n", NVALS);
for (i=0 ; i<NVALS ; i++) {
sprintf(cval, "%04d", i);
val = dictionary_get(d, cval, DICT_INVALID_KEY);
if (val==DICT_INVALID_KEY) {
printf("cannot get value for key [%s]\n", cval);
}
}
printf("unsetting %d values...\n", NVALS);
for (i=0 ; i<NVALS ; i++) {
sprintf(cval, "%04d", i);
dictionary_unset(d, cval);
}
if (d->n != 0) {
printf("error deleting values\n");
}
printf("deallocating...\n");
dictionary_del(d);
return 0 ;
}
#endif
/* vim: set ts=4 et sw=4 tw=75 */

View file

@ -44,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 */
@ -107,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);
/*-------------------------------------------------------------------------*/
@ -164,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
}

View file

@ -8,6 +8,7 @@
/*--------------------------------------------------------------------------*/
/*---------------------------- Includes ------------------------------------*/
#include <ctype.h>
#include <stdarg.h>
#include "iniparser.h"
/*---------------------------- Defines -------------------------------------*/
@ -32,42 +33,69 @@ 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 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.
*/
/*--------------------------------------------------------------------------*/
static char * xstrdup(const char * s)
{
char * t ;
size_t len ;
if (!s)
return NULL ;
len = strlen(s) + 1 ;
t = (char*) malloc(len) ;
if (t) {
memcpy(t, s, len) ;
}
return t ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Remove blanks at the beginning and the end of a string.
@param s String to parse.
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.
@param str String to parse and alter.
@return unsigned New size of the string.
*/
/*--------------------------------------------------------------------------*/
void strstrip(char * s)
static unsigned strstrip(char * s)
{
if (s==NULL) return ;
char *last = s + strlen(s);
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)))
@ -77,6 +105,42 @@ void strstrip(char * s)
*last = (char)0;
memmove(dest,s,last - s + 1);
return last - s;
}
/*-------------------------------------------------------------------------*/
/**
@brief Default error callback for iniparser: wraps `fprintf(stderr, ...)`.
*/
/*--------------------------------------------------------------------------*/
static int default_error_callback(const char *format, ...)
{
int ret;
va_list argptr;
va_start(argptr, format);
ret = vfprintf(stderr, format, argptr);
va_end(argptr);
return ret;
}
static int (*iniparser_error_callback)(const char*, ...) = default_error_callback;
/*-------------------------------------------------------------------------*/
/**
@brief Configure a function to receive the error messages.
@param errback Function to call.
By default, the error will be printed on stderr. If a null pointer is passed
as errback the error callback will be switched back to default.
*/
/*--------------------------------------------------------------------------*/
void iniparser_set_error_callback(int (*errback)(const char *, ...))
{
if (errback) {
iniparser_error_callback = errback;
} else {
iniparser_error_callback = default_error_callback;
}
}
/*-------------------------------------------------------------------------*/
@ -97,7 +161,7 @@ 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 ;
@ -128,7 +192,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 ;
@ -163,7 +227,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 ;
@ -191,11 +255,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 ;
const char * secname ;
if (d==NULL || f==NULL) return ;
@ -211,7 +275,7 @@ void iniparser_dump_ini(dictionary * d, FILE * f)
}
for (i=0 ; i<nsec ; i++) {
secname = iniparser_getsecname(d, i) ;
iniparser_dumpsection_ini(d, secname, f) ;
iniparser_dumpsection_ini(d, secname, f);
}
fprintf(f, "\n");
return ;
@ -229,31 +293,29 @@ void iniparser_dump_ini(dictionary * d, FILE * f)
file. It is Ok to specify @c stderr or @c stdout as output files.
*/
/*--------------------------------------------------------------------------*/
void iniparser_dumpsection_ini(dictionary * d, char * s, FILE * f)
void iniparser_dumpsection_ini(const dictionary * d, const char * s, FILE * f)
{
int j ;
char *keym;
int secsize ;
char keym[ASCIILINESZ+1];
int seclen ;
if (d==NULL || f==NULL) return ;
if (! iniparser_find_entry(d, s)) return ;
seclen = (int)strlen(s);
fprintf(f, "\n[%s]\n", s);
secsize = (int)strlen(s) + 2;
keym = malloc(secsize);
snprintf(keym, secsize, "%s:", s);
sprintf(keym, "%s:", s);
for (j=0 ; j<d->size ; 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 ;
}
@ -265,10 +327,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;
@ -276,17 +338,17 @@ 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);
strlwc(s, keym, sizeof(keym));
keym[seclen] = ':';
for (j=0 ; j<d->size ; 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;
}
@ -296,50 +358,41 @@ int iniparser_getsecnkeys(dictionary * d, char * s)
@brief Get the number of keys in a section of a dictionary.
@param d Dictionary to examine
@param s Section name of dictionary to examine
@return pointer to statically allocated character strings
@param keys Already allocated array to store the keys in
@return The pointer passed as `keys` argument or NULL in case of error
This function queries a dictionary and finds all keys in a given section.
The keys argument should be an array of pointers which size has been
determined by calling `iniparser_getsecnkeys` function prior to this one.
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, const char ** keys)
{
int i, j, seclen ;
char keym[ASCIILINESZ+1];
char **keys;
if (d==NULL || keys==NULL) return NULL;
if (! iniparser_find_entry(d, s)) return NULL;
int i, j ;
char *keym;
int secsize, nkeys ;
keys = NULL;
if (d==NULL) return keys;
if (! iniparser_find_entry(d, s)) return keys;
nkeys = iniparser_getsecnkeys(d, s);
keys = (char**) malloc(nkeys*sizeof(char*));
secsize = (int)strlen(s) + 2;
keym = malloc(secsize);
snprintf(keym, secsize, "%s:", s);
seclen = (int)strlen(s);
strlwc(s, keym, sizeof(keym));
keym[seclen] = ':';
i = 0;
for (j=0 ; j<d->size ; 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;
return keys;
}
/*-------------------------------------------------------------------------*/
@ -357,21 +410,57 @@ 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 ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Get the string associated to a key, convert to an long int
@param d Dictionary to search
@param key Key string to look for
@param notfound Value to return in case of error
@return long integer
This function queries a dictionary for a key. A key as read from an
ini file is given as "section:key". If the key cannot be found,
the notfound value is returned.
Supported values for integers include the usual C notation
so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
are supported. Examples:
"42" -> 42
"042" -> 34 (octal -> decimal)
"0x42" -> 66 (hexa -> decimal)
Warning: the conversion may overflow in various ways. Conversion is
totally outsourced to strtol(), see the associated man page for overflow
handling.
Credits: Thanks to A. Becker for suggesting strtol()
*/
/*--------------------------------------------------------------------------*/
long int iniparser_getlongint(const dictionary * d, const char * key, long int notfound)
{
const char * str ;
str = iniparser_getstring(d, key, INI_INVALID_KEY);
if (str==INI_INVALID_KEY) return notfound ;
return strtol(str, NULL, 0);
}
/*-------------------------------------------------------------------------*/
/**
@brief Get the string associated to a key, convert to an int
@ -399,13 +488,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 ;
str = iniparser_getstring(d, key, INI_INVALID_KEY);
if (str==INI_INVALID_KEY) return notfound ;
return (int)strtol(str, NULL, 0);
return (int)iniparser_getlongint(d, key, notfound);
}
/*-------------------------------------------------------------------------*/
@ -421,9 +506,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 ;
@ -462,10 +547,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 ;
const char * c ;
c = iniparser_getstring(d, key, INI_INVALID_KEY);
if (c==INI_INVALID_KEY) return notfound ;
@ -491,10 +576,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) {
@ -512,18 +594,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) ;
}
/*-------------------------------------------------------------------------*/
@ -538,10 +616,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)));
}
/*-------------------------------------------------------------------------*/
@ -555,48 +631,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;
char * line = NULL;
size_t len ;
if (!line) {
fprintf(stderr, "iniparser: memory alloc error\n");
return LINE_ERROR;
}
*line = 0;
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 = xstrdup(input_line);
len = strstrip(line);
sta = LINE_UNPROCESSED ;
if (len<1) {
@ -607,19 +652,21 @@ 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
|| sscanf (line, "%[^=] = '%[^\']'", key, value) == 2
|| sscanf (line, "%[^=] = %[^;#]", key, value) == 2)) {
/* Usual key=value, with or without comments */
} else if (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2
|| sscanf (line, "%[^=] = '%[^\']'", key, value) == 2) {
/* Usual key=value with quotes, with or without comments */
strstrip(key);
strlwc(key);
strlwc(key, key, len);
/* Don't strip spaces from values surrounded with quotes */
sta = LINE_VALUE ;
} else if (sscanf (line, "%[^=] = %[^;#]", key, value) == 2) {
/* Usual key=value without quotes, with or without comments */
strstrip(key);
strlwc(key, key, len);
strstrip(value);
/*
* sscanf cannot handle '' or "" as empty values
@ -628,13 +675,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=
@ -642,33 +685,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;
}
return sta ;
}
@ -688,62 +713,53 @@ 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) + 2] ;
char val [ASCIILINESZ+1] ;
int last=0 ;
int len ;
int lineno=0 ;
int errs=0;
int seckey_size=0;
int mem_err=0;
dictionary * dict = NULL ;
dictionary * dict ;
if ((in=fopen(ininame, "r"))==NULL) {
fprintf(stderr, "iniparser: cannot open %s\n", ininame);
goto out;
iniparser_error_callback("iniparser: cannot open %s\n", ininame);
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)
if (len<=0)
continue;
/* Safety check against buffer overflows */
if (line[len]!='\n' && !feof(in)) {
fprintf(stderr,
iniparser_error_callback(
"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) &&
@ -751,93 +767,37 @@ 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, &current_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;
mem_err = 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);
mem_err = dictionary_set(dict, tmp, val);
break ;
case LINE_ERROR:
fprintf(stderr, "iniparser: syntax error in %s (%d):\n",
iniparser_error_callback(
"iniparser: syntax error in %s (%d):\n-> %s\n",
ininame,
lineno);
fprintf(stderr, "-> %s\n", full_line);
lineno,
line);
errs++ ;
break;
@ -845,43 +805,17 @@ dictionary * iniparser_load(const char * ininame)
break ;
}
memset(line, 0, ASCIILINESZ);
if (full_line) {
free(full_line);
full_line = NULL;
}
if (errs<0) {
fprintf(stderr, "iniparser: memory allocation failure\n");
last=0;
if (mem_err<0) {
iniparser_error_callback("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);
}
return dict ;
}
@ -900,5 +834,3 @@ void iniparser_freedict(dictionary * d)
{
dictionary_del(d);
}
/* vim: set ts=4 et sw=4 tw=75 */

View file

@ -31,6 +31,18 @@
extern "C" {
#endif
/*-------------------------------------------------------------------------*/
/**
@brief Configure a function to receive the error messages.
@param errback Function to call.
By default, the error will be printed on stderr. If a null pointer is passed
as errback the error callback will be switched back to default.
*/
/*--------------------------------------------------------------------------*/
void iniparser_set_error_callback(int (*errback)(const char *, ...));
/*-------------------------------------------------------------------------*/
/**
@brief Get number of sections in a dictionary
@ -50,7 +62,7 @@ extern "C" {
*/
/*--------------------------------------------------------------------------*/
int iniparser_getnsec(dictionary * d);
int iniparser_getnsec(const dictionary * d);
/*-------------------------------------------------------------------------*/
@ -68,7 +80,7 @@ int iniparser_getnsec(dictionary * d);
*/
/*--------------------------------------------------------------------------*/
char * iniparser_getsecname(dictionary * d, int n);
const char * iniparser_getsecname(const dictionary * d, int n);
/*-------------------------------------------------------------------------*/
@ -83,7 +95,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 +110,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 +125,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,23 +135,26 @@ 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);
/*-------------------------------------------------------------------------*/
/**
@brief Get the number of keys in a section of a dictionary.
@param d Dictionary to examine
@param s Section name of dictionary to examine
@return pointer to statically allocated character strings
@param keys Already allocated array to store the keys in
@return The pointer passed as `keys` argument or NULL in case of error
This function queries a dictionary and finds all keys in a given section.
The keys argument should be an array of pointers which size has been
determined by calling `iniparser_getsecnkeys` function prior to this one.
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, const char ** keys);
/*-------------------------------------------------------------------------*/
/**
@ -156,7 +171,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 +200,35 @@ 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);
/*-------------------------------------------------------------------------*/
/**
@brief Get the string associated to a key, convert to an long int
@param d Dictionary to search
@param key Key string to look for
@param notfound Value to return in case of error
@return integer
This function queries a dictionary for a key. A key as read from an
ini file is given as "section:key". If the key cannot be found,
the notfound value is returned.
Supported values for integers include the usual C notation
so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
are supported. Examples:
- "42" -> 42
- "042" -> 34 (octal -> decimal)
- "0x42" -> 66 (hexa -> decimal)
Warning: the conversion may overflow in various ways. Conversion is
totally outsourced to strtol(), see the associated man page for overflow
handling.
*/
/*--------------------------------------------------------------------------*/
long int iniparser_getlongint(const dictionary * d, const char * key, long int notfound);
/*-------------------------------------------------------------------------*/
/**
@ -200,7 +243,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 +277,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);
/*-------------------------------------------------------------------------*/
@ -246,7 +289,7 @@ int iniparser_getboolean(dictionary * d, const char * key, int notfound);
@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 +320,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) ;
/*-------------------------------------------------------------------------*/
/**

View file

@ -0,0 +1,348 @@
#include <assert.h>
#include <setjmp.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#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 CuAssertLongIntEquals_LineMsg(CuTest *tc, const char *file, int line, const char *message,
long int expected, long int actual)
{
char buf[STRING_MAX];
if (expected == actual) return;
sprintf(buf, "expected <%ld> but was <%ld>", 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);
}
}

View file

@ -0,0 +1,121 @@
#ifndef CU_TEST_H
#define CU_TEST_H
#include <setjmp.h>
#include <stdarg.h>
#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 CuAssertLongIntEquals_LineMsg(CuTest *tc,
const char *file, int line, const char *message,
long int expected, long 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 CuAssertLongIntEquals(tc,ex,ac) CuAssertLongIntEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac))
#define CuAssertLongIntEquals_Msg(tc,ms,ex,ac) CuAssertLongIntEquals_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 */

View file

@ -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.

View file

@ -1,27 +1,35 @@
#
# 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 +=
iniexample: iniexample.c
$(CC) $(CFLAGS) -o iniexample iniexample.c -I../src -L.. -liniparser
all: check
parse: parse.c
$(CC) $(CFLAGS) -o parse parse.c -I../src -L.. -liniparser
check: testrun
@./testrun
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) iniexample example.ini parse
rm -rf AllTests.c
rm -rf $(OBJ) AllTests.o
rm -rf testrun

View file

@ -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 <stdio.h>
#include <stdlib.h>
#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;
}
'

View file

@ -0,0 +1,6 @@
#
# This dict contains an error but ends up with a correct entry
#
[section]
error is here
a = b

View file

@ -0,0 +1,9 @@
#
# All of these should trigger syntax errors
#
[section]
hello
world
hello \
world
a + b ;

View file

@ -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

View file

@ -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;

View file

@ -0,0 +1,16 @@

View file

@ -0,0 +1,20 @@
# spaced2.ini
[blanks]
a=1
b=1;
c=1; comment
d=1# comment

View file

@ -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

View file

@ -0,0 +1,237 @@
#include <stdio.h>
#include <stdlib.h>
#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;
}
if (fread(dump_buff, 1, dump_size, fd) != (size_t)dump_size) {
fclose(fd);
return NULL;
}
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);
}

View file

@ -0,0 +1,698 @@
#include <stdio.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdarg.h>
#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[1060];
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;
int nkeys;
const char * keys[10]; /* At most 10 elements per section */
/* NULL test */
CuAssertPtrEquals(tc, NULL, iniparser_getseckeys(NULL, NULL, NULL));
CuAssertPtrEquals(tc, NULL, iniparser_getseckeys(NULL, "dummy", NULL));
CuAssertPtrEquals(tc, NULL, iniparser_getseckeys(NULL, "dummy", keys));
/* Empty dictionary */
dic = dictionary_new(10);
CuAssertPtrEquals(tc, NULL, iniparser_getseckeys(dic, NULL, keys));
CuAssertPtrEquals(tc, NULL, iniparser_getseckeys(dic, "dummy", keys));
dictionary_del(dic);
/* Generic dictionary */
dic = generate_dictionary(100, 10);
CuAssertPtrEquals(tc, NULL, iniparser_getseckeys(dic, NULL, keys));
CuAssertPtrEquals(tc, NULL, iniparser_getseckeys(dic, "dummy", keys));
CuAssertPtrEquals(tc, NULL, iniparser_getseckeys(dic, "sec0", NULL));
nkeys = iniparser_getsecnkeys(dic, "sec42");
CuAssertIntEquals(tc, nkeys, 10);
CuAssertPtrEquals(tc, keys, iniparser_getseckeys(dic, "sec42", keys));
for (i = 0; i < 10; ++i) {
sprintf(key_name, "sec42:key%d", i);
CuAssertStrEquals(tc, key_name, keys[i]);
}
/* 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", keys));
nkeys = iniparser_getsecnkeys(dic, "Sec99");
CuAssertIntEquals(tc, nkeys, 9);
CuAssertPtrEquals(tc, keys, iniparser_getseckeys(dic, "Sec99", keys));
for (i = 0; i < 9; ++i) {
sprintf(key_name, "sec99:key%d", i);
CuAssertStrEquals(tc, key_name, keys[i]);
}
nkeys = iniparser_getsecnkeys(dic, "sec0");
CuAssertIntEquals(tc, nkeys, 7);
CuAssertPtrEquals(tc, keys, iniparser_getseckeys(dic, "sec0", keys));
for (i = 0; i < 7; ++i) {
sprintf(key_name, "sec0:key%d", i + 3);
CuAssertStrEquals(tc, key_name, keys[i]);
}
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_getlongint(CuTest *tc)
{
unsigned i;
char key_name[64];
dictionary *dic;
const struct { long int num; const char *value; } good_val[] = {
{ 0, "0" },
{ 1, "1" },
{ -1, "-1" },
{ 1000, "1000" },
{ 077, "077" },
{ -01000, "-01000" },
{ 0x7FFFFFFFFFFFFFFF, "0x7FFFFFFFFFFFFFFF" },
{ -0x7FFFFFFFFFFFFFFF, "-0x7FFFFFFFFFFFFFFF" },
{ 0x4242, "0x4242" },
{ 0, NULL} /* must be last */
};
const char *bad_val[] = {
"",
"notanumber",
"0x",
"k2000",
" ",
"0xG1"
};
/* NULL test */
CuAssertLongIntEquals(tc, -42, iniparser_getlongint(NULL, NULL, -42));
CuAssertLongIntEquals(tc, -42, iniparser_getlongint(NULL, "dummy", -42));
/* Check the def return element */
dic = dictionary_new(10);
CuAssertLongIntEquals(tc, 42, iniparser_getlongint(dic, "dummy", 42));
CuAssertLongIntEquals(tc, 0x7FFFFFFFFFFFFFFF, iniparser_getlongint(dic, NULL, 0x7FFFFFFFFFFFFFFF));
CuAssertLongIntEquals(tc, -0x7FFFFFFFFFFFFFFF, iniparser_getlongint(dic, "dummy", -0x7FFFFFFFFFFFFFFF));
dictionary_del(dic);
/* Generic dictionary */
dic = dictionary_new(10);
for (i = 0; good_val[i].value != NULL; ++i) {
sprintf(key_name, "longint:value%d", i);
dictionary_set(dic, key_name, good_val[i].value);
}
for (i = 0; good_val[i].value != NULL; ++i) {
sprintf(key_name, "longint:value%d", i);
CuAssertLongIntEquals(tc, good_val[i].num,
iniparser_getlongint(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, "longint:bad%d", i);
dictionary_set(dic, key_name, bad_val[i]);
}
for (i = 0; i < sizeof (bad_val) / sizeof (char *); ++i) {
sprintf(key_name, "longint:bad%d", i);
CuAssertLongIntEquals(tc, 0,
iniparser_getlongint(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("empty_value = \t\n", 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));
CuAssertIntEquals(tc, LINE_VALUE, iniparser_line("key = \" do_not_strip \"", section, key, val));
CuAssertStrEquals(tc, "key", key);
CuAssertStrEquals(tc, " do_not_strip ", val);
CuAssertIntEquals(tc, LINE_VALUE, iniparser_line("key = ' '", section, key, val));
CuAssertStrEquals(tc, "key", key);
CuAssertStrEquals(tc, " ", val);
CuAssertIntEquals(tc, LINE_VALUE, iniparser_line("key = \"\"", section, key, val));
CuAssertStrEquals(tc, "key", key);
CuAssertStrEquals(tc, "", val);
CuAssertIntEquals(tc, LINE_VALUE, iniparser_line("key = ''", section, key, val));
CuAssertStrEquals(tc, "key", key);
CuAssertStrEquals(tc, "", 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[276];
/* 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);
}
static char _last_error[1024];
static int _error_callback(const char *format, ...)
{
int ret;
va_list argptr;
va_start(argptr, format);
ret = vsprintf(_last_error, format, argptr);
va_end(argptr);
return ret;
}
void Test_iniparser_error_callback(CuTest *tc)
{
dictionary *dic;
/* Specify our custom error_callback */
iniparser_set_error_callback(_error_callback);
/* Trigger an error and check it was written on the right output */
dic = iniparser_load("/path/to/nowhere.ini");
CuAssertPtrEquals(tc, NULL, dic);
CuAssertStrEquals(tc, "iniparser: cannot open /path/to/nowhere.ini\n", _last_error);
/* Reset erro_callback */
_last_error[0] = '\0';
iniparser_set_error_callback(NULL);
/* Make sure custom callback is no more called */
dic = iniparser_load("/path/to/nowhere.ini");
CuAssertPtrEquals(tc, NULL, dic);
CuAssertStrEquals(tc, "", _last_error);
}