aboutsummaryrefslogtreecommitdiff
path: root/iniparser-4.1
diff options
context:
space:
mode:
Diffstat (limited to 'iniparser-4.1')
-rw-r--r--iniparser-4.1/.gitignore11
-rw-r--r--iniparser-4.1/.travis.yml9
-rw-r--r--iniparser-4.1/AUTHORS6
-rw-r--r--iniparser-4.1/FAQ-en.md37
-rw-r--r--iniparser-4.1/FAQ-zhcn.md27
-rw-r--r--iniparser-4.1/INSTALL15
-rw-r--r--iniparser-4.1/LICENSE40
-rw-r--r--iniparser-4.1/Makefile86
-rw-r--r--iniparser-4.1/README.md44
-rw-r--r--iniparser-4.1/doc/Makefile16
-rw-r--r--iniparser-4.1/doc/iniparser.dox81
-rw-r--r--iniparser-4.1/doc/iniparser.main207
-rw-r--r--iniparser-4.1/example/Makefile27
-rw-r--r--iniparser-4.1/example/iniexample.c104
-rw-r--r--iniparser-4.1/example/parse.c24
-rw-r--r--iniparser-4.1/example/twisted-errors.ini9
-rw-r--r--iniparser-4.1/example/twisted-genhuge.py12
-rw-r--r--iniparser-4.1/example/twisted-ofkey.ini66
-rw-r--r--iniparser-4.1/example/twisted-ofval.ini56
-rw-r--r--iniparser-4.1/example/twisted.ini131
-rw-r--r--iniparser-4.1/src/dictionary.c406
-rw-r--r--iniparser-4.1/src/dictionary.h190
-rw-r--r--iniparser-4.1/src/getline.c58
-rw-r--r--iniparser-4.1/src/iniparser.c938
-rw-r--r--iniparser-4.1/src/iniparser.h386
-rw-r--r--iniparser-4.1/test/CuTest.c348
-rw-r--r--iniparser-4.1/test/CuTest.h121
-rw-r--r--iniparser-4.1/test/CuTest_license.txt38
-rw-r--r--iniparser-4.1/test/Makefile35
-rwxr-xr-xiniparser-4.1/test/make-tests.sh56
-rw-r--r--iniparser-4.1/test/ressources/bad_ini/ends_well.ini6
-rw-r--r--iniparser-4.1/test/ressources/bad_ini/twisted-errors.ini9
-rw-r--r--iniparser-4.1/test/ressources/bad_ini/twisted-ofkey.ini66
-rw-r--r--iniparser-4.1/test/ressources/bad_ini/twisted-ofval.ini56
-rw-r--r--iniparser-4.1/test/ressources/good_ini/empty.ini0
-rw-r--r--iniparser-4.1/test/ressources/good_ini/spaced.ini16
-rw-r--r--iniparser-4.1/test/ressources/good_ini/spaced2.ini20
-rw-r--r--iniparser-4.1/test/ressources/good_ini/twisted.ini131
-rw-r--r--iniparser-4.1/test/test_dictionary.c237
-rw-r--r--iniparser-4.1/test/test_iniparser.c698
40 files changed, 4823 insertions, 0 deletions
diff --git a/iniparser-4.1/.gitignore b/iniparser-4.1/.gitignore
new file mode 100644
index 0000000..8fc7b85
--- /dev/null
+++ b/iniparser-4.1/.gitignore
@@ -0,0 +1,11 @@
+### Ignore all files created by make
+#
+*.a
+*.o
+*.so
+*.so.*
+/example/iniexample
+/example/parse
+# Autogenerate source file
+/test/AllTests.c
+/test/testrun
diff --git a/iniparser-4.1/.travis.yml b/iniparser-4.1/.travis.yml
new file mode 100644
index 0000000..22a61fa
--- /dev/null
+++ b/iniparser-4.1/.travis.yml
@@ -0,0 +1,9 @@
+language: c
+
+env:
+ - ENV_CC=clang
+ - ENV_CC=clang++
+ - ENV_CC=gcc
+ - ENV_CC=g++
+
+script: CC=$ENV_CC make && CC=$ENV_CC make check
diff --git a/iniparser-4.1/AUTHORS b/iniparser-4.1/AUTHORS
new file mode 100644
index 0000000..d5a3f6b
--- /dev/null
+++ b/iniparser-4.1/AUTHORS
@@ -0,0 +1,6 @@
+Author: Nicolas Devillard <ndevilla@free.fr>
+
+This tiny library has received countless contributions and I have
+not kept track of all the people who contributed. Let them be thanked
+for their ideas, code, suggestions, corrections, enhancements!
+
diff --git a/iniparser-4.1/FAQ-en.md b/iniparser-4.1/FAQ-en.md
new file mode 100644
index 0000000..0bb43ba
--- /dev/null
+++ b/iniparser-4.1/FAQ-en.md
@@ -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!
+
diff --git a/iniparser-4.1/FAQ-zhcn.md b/iniparser-4.1/FAQ-zhcn.md
new file mode 100644
index 0000000..ad0286d
--- /dev/null
+++ b/iniparser-4.1/FAQ-zhcn.md
@@ -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++编译器下工作,会是一份繁重的工作。祝你好运!
diff --git a/iniparser-4.1/INSTALL b/iniparser-4.1/INSTALL
new file mode 100644
index 0000000..a5b05d0
--- /dev/null
+++ b/iniparser-4.1/INSTALL
@@ -0,0 +1,15 @@
+
+iniParser installation instructions
+-----------------------------------
+
+- Modify the Makefile to suit your environment.
+- Type 'make' to make the library.
+- Type 'make check' to make the test program.
+- Type 'test/iniexample' to launch the test program.
+- Type 'test/parse' to launch torture tests.
+
+
+
+Enjoy!
+N. Devillard
+Wed Mar 2 21:14:17 CET 2011
diff --git a/iniparser-4.1/LICENSE b/iniparser-4.1/LICENSE
new file mode 100644
index 0000000..4c073ba
--- /dev/null
+++ b/iniparser-4.1/LICENSE
@@ -0,0 +1,40 @@
+Most of the library code:
+
+Copyright (c) 2000-2011 by Nicolas Devillard.
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+-----------------------------------------------------------
+
+getline.c:
+The original code is public domain -- Will Hartung 4/9/09
+Modifications, public domain as well, by Antti Haapala, 11/10/17
+
+Additionaly, getline.c can be considered available under CC BY-SA 3.0,
+as required under the Terms of Service of StackOverflow where the code
+was taken from.
+
+-----------------------------------------------------------
+
+Modifications to make the library work with lines longer that 1024 chars:
+
+Copyright (C) 2021 Wojtek Kosior, dual licensed under either:
+ - GNU GPL, version 3 or (at Your option) any later version
+ - 0BSD
diff --git a/iniparser-4.1/Makefile b/iniparser-4.1/Makefile
new file mode 100644
index 0000000..bcf4dc4
--- /dev/null
+++ b/iniparser-4.1/Makefile
@@ -0,0 +1,86 @@
+#
+# iniparser Makefile
+#
+.PHONY: example
+
+# Compiler settings
+CC = i686-w64-mingw32-gcc
+
+CFLAGS += -Wall -Wextra -ansi -pedantic
+#CFLAGS += -fPIC
+ifndef DEBUG
+ADDITIONAL_CFLAGS ?= -O2
+else
+ADDITIONAL_CFLAGS ?= -g
+endif
+
+CFLAGS += ${ADDITIONAL_CFLAGS}
+
+# Ar settings to build the library
+AR = i686-w64-mingw32-ar
+ARFLAGS = rcs
+
+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
+
+RM ?= rm -f
+
+
+# Implicit rules
+
+SUFFIXES = .o .c .h .a .so .sl
+
+COMPILE.c ?= $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
+
+ifndef V
+QUIET_AR = @echo "AR $@";
+QUIET_CC = @echo "CC $@";
+QUIET_LINK = @echo "LINK $@";
+QUIET_RANLIB = @echo "RANLIB $@";
+endif
+
+.c.o:
+ $(QUIET_CC)$(COMPILE.c) $(OUTPUT_OPTION) $<
+
+
+SRCS = src/iniparser.c src/dictionary.c src/getline.c
+
+OBJS = $(SRCS:.c=.o)
+
+
+default: libiniparser.a $(SO_TARGET)
+
+libiniparser.a: $(OBJS)
+ $(QUIET_AR)$(AR) $(ARFLAGS) $@ $^
+ $(QUIET_RANLIB)$(RANLIB) $@
+
+$(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 $(SO_TARGET)
+ rm -rf ./html ; mkdir html
+ cd example ; $(MAKE) veryclean
+ cd test ; $(MAKE) veryclean
+
+docs:
+ @(cd doc ; $(MAKE))
+
+check: $(SO_TARGET)
+ @(cd test ; $(MAKE))
+
+example: libiniparser.a
+ @(cd example ; $(MAKE))
diff --git a/iniparser-4.1/README.md b/iniparser-4.1/README.md
new file mode 100644
index 0000000..dbc30d0
--- /dev/null
+++ b/iniparser-4.1/README.md
@@ -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).
diff --git a/iniparser-4.1/doc/Makefile b/iniparser-4.1/doc/Makefile
new file mode 100644
index 0000000..db925ec
--- /dev/null
+++ b/iniparser-4.1/doc/Makefile
@@ -0,0 +1,16 @@
+#
+# iniparser doc Makefile
+#
+
+all: html
+
+html:
+ doxygen iniparser.dox
+ rm -f ../html/annotated.html
+ rm -f ../html/classes.html
+ rm -f ../html/doxygen.gif
+ rm -f ../html/files.html
+ rm -f ../html/functions.html
+ rm -f ../html/globals.html
+ rm -f ../html/iniparser_main.html
+
diff --git a/iniparser-4.1/doc/iniparser.dox b/iniparser-4.1/doc/iniparser.dox
new file mode 100644
index 0000000..e4b2242
--- /dev/null
+++ b/iniparser-4.1/doc/iniparser.dox
@@ -0,0 +1,81 @@
+PROJECT_NAME = iniparser
+PROJECT_NUMBER = 4.1
+OUTPUT_DIRECTORY = ..
+OUTPUT_LANGUAGE = English
+EXTRACT_ALL = YES
+EXTRACT_PRIVATE = NO
+EXTRACT_STATIC = NO
+HIDE_UNDOC_MEMBERS = NO
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ALWAYS_DETAILED_SEC = NO
+FULL_PATH_NAMES = NO
+STRIP_FROM_PATH =
+INTERNAL_DOCS = NO
+SOURCE_BROWSER = NO
+INLINE_SOURCES = NO
+STRIP_CODE_COMMENTS = YES
+CASE_SENSE_NAMES = YES
+HIDE_SCOPE_NAMES = NO
+VERBATIM_HEADERS = NO
+SHOW_INCLUDE_FILES = NO
+JAVADOC_AUTOBRIEF = NO
+INHERIT_DOCS = YES
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+DISTRIBUTE_GROUP_DOC = NO
+TAB_SIZE = 4
+ENABLED_SECTIONS =
+GENERATE_TODOLIST = NO
+GENERATE_TESTLIST = NO
+ALIASES =
+MAX_INITIALIZER_LINES = 30
+OPTIMIZE_OUTPUT_FOR_C = YES
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+INPUT = iniparser.main ../src
+FILE_PATTERNS = iniparser.h
+RECURSIVE = NO
+EXCLUDE =
+EXCLUDE_PATTERNS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS =
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_SOURCE_FILES = NO
+ALPHABETICAL_INDEX = YES
+COLS_IN_ALPHA_INDEX = 5
+IGNORE_PREFIX =
+GENERATE_HTML = YES
+HTML_OUTPUT = html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YES
+GENERATE_HTMLHELP = NO
+DISABLE_INDEX = YES
+ENUM_VALUES_PER_LINE = 4
+GENERATE_TREEVIEW = NO
+TREEVIEW_WIDTH = 250
+
+GENERATE_LATEX = NO
+GENERATE_RTF = NO
+GENERATE_MAN = NO
+
+ENABLE_PREPROCESSING = NO
+MACRO_EXPANSION = NO
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = NO
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED =
+EXPAND_AS_DEFINED =
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS = NO
+PERL_PATH = /usr/bin/perl
+HAVE_DOT = NO
+SEARCHENGINE = NO
diff --git a/iniparser-4.1/doc/iniparser.main b/iniparser-4.1/doc/iniparser.main
new file mode 100644
index 0000000..47747c1
--- /dev/null
+++ b/iniparser-4.1/doc/iniparser.main
@@ -0,0 +1,207 @@
+
+/**
+
+ @mainpage iniparser documentation
+
+
+ @section welcome Introduction
+
+ 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.
+
+
+ @section inidef What is an ini file?
+
+ An ini file is an ASCII file describing simple parameters
+ (character strings, integers, floating-point values or booleans)
+ in an explicit format, easy to use and modify for users.
+
+ An ini file is segmented into Sections, declared by the following
+ syntax:
+
+ @verbatim
+ [Section Name]
+ @endverbatim
+
+ i.e. the section name enclosed in square brackets, alone on a
+ line. Sections names are allowed to contain any character but
+ square brackets or linefeeds.
+
+ In any section are zero or more variables, declared with the
+ following syntax:
+
+ @verbatim
+ Key = value ; comment
+ @endverbatim
+
+ The key is any string (possibly containing blanks). The value is
+ any character on the right side of the equal sign. Values can be
+ given enclosed with quotes. If no quotes are present, the value is
+ understood as containing all characters between the first and the
+ last non-blank characters before the comment. The following
+ declarations are identical:
+
+ @verbatim
+ Hello = "this is a long string value" ; comment
+ Hello = this is a long string value ; comment
+ @endverbatim
+
+ The semicolon and comment at the end of the line are optional. If
+ there is a comment, it starts from the first character after the
+ semicolon up to the end of the line.
+
+ Multi-line values can be provided by ending the line with a
+ backslash (\).
+
+ @verbatim
+ Multiple = Line 1 \
+ Line 2 \
+ Line 3 \
+ Line 4 ; comment
+ @endverbatim
+
+ This would yield: "multiple" <- "Line1 Line2 Line3 Line4"
+
+ Comments in an ini file are:
+
+ - Lines starting with a hash sign
+ - Blank lines (only blanks or tabs)
+ - Comments given on value lines after the semicolon (if present)
+
+
+ @section install Compiling/installing the library
+
+ Edit the Makefile to indicate the C compiler you want to use, the
+ options to provide to compile ANSI C, and possibly the options to pass
+ to the ar program on your machine to build a library (.a) from a set
+ of object (.o) files.
+
+ Defaults are set for the gcc compiler and the standard ar library
+ builder.
+
+ Type 'make', that should do it.
+
+ To use the library in your programs, add the following line on top
+ of your module:
+
+ @code
+ #include "iniparser.h"
+ @endcode
+
+ And link your program with the iniparser library by adding
+ @c -liniparser.a to the compile line.
+
+ See the file test/initest.c for an example.
+
+ iniparser is an ANSI C library. If you want to compile it
+ with a C++ compiler you will likely run into compatibility
+ issues. Headers probably have to include the extern "C"
+ hack and function prototypes will want to add some const
+ here and there to keep the compiler happy. This job is left
+ to the reader as there are too many C++ compilers around, each
+ with its own requirements as to what represents acceptable
+ C code in a C++ environment. You have been warned.
+
+
+ @section reference Library reference
+
+ The library is completely documented in its header file. On-line
+ documentation has been generated and can be consulted here:
+
+ - iniparser.h
+
+
+ @section usage Using the parser
+
+ Comments are discarded by the parser. Then sections are
+ identified, and in each section a new entry is created for every
+ keyword found. The keywords are stored with the following syntax:
+
+ @verbatim
+ [Section]
+ Keyword = value ; comment
+ @endverbatim
+
+ is converted to the following key pair:
+
+ @verbatim
+ ("section:keyword", "value")
+ @endverbatim
+
+ This means that if you want to retrieve the value that was stored
+ in the section called @c Pizza, in the keyword @c Cheese,
+ you would make a request to the dictionary for
+ @c "pizza:cheese". All section and keyword names are converted
+ to lowercase before storage in the structure. The value side is
+ conserved as it has been parsed, though.
+
+ Section names are also stored in the structure. They are stored
+ using as key the section name, and a NULL associated value. They
+ can be queried through iniparser_find_entry().
+
+ To launch the parser, use the function called iniparser_load(), which
+ takes an input file name and returns a newly allocated @e dictionary
+ structure. This latter object should remain opaque to the user and only
+ accessed through the following accessor functions:
+
+ - iniparser_getstring()
+ - iniparser_getint()
+ - iniparser_getdouble()
+ - iniparser_getboolean()
+
+ Finally, discard this structure using iniparser_freedict().
+
+ All values parsed from the ini file are stored as strings. The
+ accessors are just converting these strings to the requested type on
+ the fly, but you could basically perform this conversion by yourself
+ after having called the string accessor.
+
+ Notice that iniparser_getboolean() will return an integer (0 or 1),
+ trying to make sense of what was found in the file. Strings starting
+ with "y", "Y", "t", "T" or "1" are considered true values (return 1),
+ strings starting with "n", "N", "f", "F", "0" are considered false
+ (return 0). This allows some flexibility in handling of boolean
+ answers.
+
+ If you want to add extra information into the structure that was not
+ present in the ini file, you can use iniparser_set() to insert a
+ string.
+
+ If you want to add a section to the structure, add a key
+ with a NULL value. Example:
+ @verbatim
+ iniparser_set(ini, "section", NULL);
+ iniparser_set(ini, "section:key1", NULL);
+ iniparser_set(ini, "section:key2", NULL);
+ @endverbatim
+
+
+ @section implementation A word about the implementation
+
+ The dictionary structure is a pretty simple dictionary
+ implementation which might find some uses in other applications.
+ If you are curious, look into the source.
+
+
+ @section defects Known defects
+
+ The dictionary structure is extremely unefficient for searching
+ as keys are sorted in the same order as they are read from the
+ ini file, which is convenient when dumping back to a file. The
+ simplistic first-approach linear search implemented there can
+ become a bottleneck if you have a very large number of keys.
+
+ People who need to load large amounts of data from an ini file
+ should definitely turn to more appropriate solutions: sqlite3 or
+ similar. There are otherwise many other dictionary implementations
+ available on the net to replace this one.
+
+
+ @section authors Authors
+
+ Nicolas Devillard (ndevilla AT free DOT fr).
+
+
+*/
diff --git a/iniparser-4.1/example/Makefile b/iniparser-4.1/example/Makefile
new file mode 100644
index 0000000..cc6e54b
--- /dev/null
+++ b/iniparser-4.1/example/Makefile
@@ -0,0 +1,27 @@
+#
+# iniparser tests Makefile
+#
+
+CC = i686-w64-mingw32-gcc
+CFLAGS += -g -I../src
+LFLAGS += -L.. -liniparser
+AR = i686-w64-mingw32-ar
+ARFLAGS += rcv
+RM ?= rm -f
+
+
+default: all
+
+all: iniexample.exe parse.exe
+
+iniexample.exe: iniexample.c
+ $(CC) $(CFLAGS) -o iniexample.exe iniexample.c -I../src -L.. -liniparser
+
+parse.exe: parse.c
+ $(CC) $(CFLAGS) -o parse.exe parse.c -I../src -L.. -liniparser
+
+clean veryclean:
+ $(RM) iniexample.exe example.ini parse.exe
+
+
+
diff --git a/iniparser-4.1/example/iniexample.c b/iniparser-4.1/example/iniexample.c
new file mode 100644
index 0000000..81013f0
--- /dev/null
+++ b/iniparser-4.1/example/iniexample.c
@@ -0,0 +1,104 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "iniparser.h"
+
+void create_example_ini_file(void);
+int parse_ini_file(char * ini_name);
+
+int main(int argc, char * argv[])
+{
+ int status ;
+
+ if (argc<2) {
+ create_example_ini_file();
+ status = parse_ini_file("example.ini");
+ } else {
+ status = parse_ini_file(argv[1]);
+ }
+ return status ;
+}
+
+void create_example_ini_file(void)
+{
+ FILE * ini ;
+
+ 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"
+ "#\n"
+ "\n"
+ "[Pizza]\n"
+ "\n"
+ "Ham = yes ;\n"
+ "Mushrooms = TRUE ;\n"
+ "Capres = 0 ;\n"
+ "Cheese = Non ;\n"
+ "\n"
+ "\n"
+ "[Wine]\n"
+ "\n"
+ "Grape = Cabernet Sauvignon ;\n"
+ "Year = 1989 ;\n"
+ "Country = Spain ;\n"
+ "Alcohol = 12.5 ;\n"
+ "\n");
+ fclose(ini);
+}
+
+
+int parse_ini_file(char * ini_name)
+{
+ dictionary * ini ;
+
+ /* Some temporary variables to hold query results */
+ int b ;
+ int i ;
+ double d ;
+ const char * s ;
+
+ ini = iniparser_load(ini_name);
+ if (ini==NULL) {
+ fprintf(stderr, "cannot parse file: %s\n", ini_name);
+ return -1 ;
+ }
+ iniparser_dump(ini, stderr);
+
+ /* Get pizza attributes */
+ printf("Pizza:\n");
+
+ b = iniparser_getboolean(ini, "pizza:ham", -1);
+ printf("Ham: [%d]\n", b);
+ b = iniparser_getboolean(ini, "pizza:mushrooms", -1);
+ printf("Mushrooms: [%d]\n", b);
+ b = iniparser_getboolean(ini, "pizza:capres", -1);
+ printf("Capres: [%d]\n", b);
+ b = iniparser_getboolean(ini, "pizza:cheese", -1);
+ printf("Cheese: [%d]\n", b);
+
+ /* Get wine attributes */
+ printf("Wine:\n");
+ s = iniparser_getstring(ini, "wine:grape", NULL);
+ printf("Grape: [%s]\n", s ? s : "UNDEF");
+
+ i = iniparser_getint(ini, "wine:year", -1);
+ printf("Year: [%d]\n", i);
+
+ s = iniparser_getstring(ini, "wine:country", NULL);
+ printf("Country: [%s]\n", s ? s : "UNDEF");
+
+ d = iniparser_getdouble(ini, "wine:alcohol", -1.0);
+ printf("Alcohol: [%g]\n", d);
+
+ iniparser_freedict(ini);
+ return 0 ;
+}
+
+
diff --git a/iniparser-4.1/example/parse.c b/iniparser-4.1/example/parse.c
new file mode 100644
index 0000000..37d07aa
--- /dev/null
+++ b/iniparser-4.1/example/parse.c
@@ -0,0 +1,24 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "iniparser.h"
+
+int main(int argc, char * argv[])
+{
+ dictionary * ini ;
+ char * ini_name ;
+
+ if (argc<2) {
+ ini_name = "twisted.ini";
+ } else {
+ ini_name = argv[1] ;
+ }
+
+ ini = iniparser_load(ini_name);
+ iniparser_dump(ini, stdout);
+ iniparser_freedict(ini);
+
+ return 0 ;
+}
diff --git a/iniparser-4.1/example/twisted-errors.ini b/iniparser-4.1/example/twisted-errors.ini
new file mode 100644
index 0000000..4dc3bbe
--- /dev/null
+++ b/iniparser-4.1/example/twisted-errors.ini
@@ -0,0 +1,9 @@
+#
+# All of these should trigger syntax errors
+#
+[section]
+hello
+world
+hello \
+world
+a + b ;
diff --git a/iniparser-4.1/example/twisted-genhuge.py b/iniparser-4.1/example/twisted-genhuge.py
new file mode 100644
index 0000000..570973c
--- /dev/null
+++ b/iniparser-4.1/example/twisted-genhuge.py
@@ -0,0 +1,12 @@
+# -*- coding: utf-8 -*-
+import os
+import sys
+
+if __name__=="__main__":
+ f=open('twisted-massive.ini', 'w')
+ for i in range(100):
+ f.write('[%03d]\n' % i)
+ for j in range(100):
+ f.write('key-%03d=1;\n' % j)
+ f.close()
+
diff --git a/iniparser-4.1/example/twisted-ofkey.ini b/iniparser-4.1/example/twisted-ofkey.ini
new file mode 100644
index 0000000..4f2e72e
--- /dev/null
+++ b/iniparser-4.1/example/twisted-ofkey.ini
@@ -0,0 +1,66 @@
+# Stress testing buffers for overflows
+[long]
+# Shitload key size
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa=1
+
diff --git a/iniparser-4.1/example/twisted-ofval.ini b/iniparser-4.1/example/twisted-ofval.ini
new file mode 100644
index 0000000..2a3cedf
--- /dev/null
+++ b/iniparser-4.1/example/twisted-ofval.ini
@@ -0,0 +1,56 @@
+# Shitload data size
+[long]
+a=\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890;
+
diff --git a/iniparser-4.1/example/twisted.ini b/iniparser-4.1/example/twisted.ini
new file mode 100644
index 0000000..86e549f
--- /dev/null
+++ b/iniparser-4.1/example/twisted.ini
@@ -0,0 +1,131 @@
+#
+# Twisted.ini
+# This file is meant for regression tests
+
+# Different blank settings around the equal sign
+[blanks]
+a=1
+b=1;
+c=1; comment
+d=1# comment
+
+e =1
+f =1;
+g =1; comment
+h =1# comment
+
+i= 1
+j= 1;
+k= 1; comment
+l= 1# comment
+
+m = 1
+n = 1;
+o = 1; comment
+p = 1# comment
+
+q=1 ;
+r=1 ; comment
+s=1 ;comment
+t=1 #comment
+
+# Empty values
+[empty]
+a = ''
+b = ""
+
+c = '' ;
+d = "" ;
+
+e = '' ; comment
+f = "" ; comment
+
+g =
+h = ;
+i = ; comment
+j = # comment
+
+k=
+l=;
+m=;comment
+n=#
+
+# Peculiar values
+[peculiar]
+a=';';
+b='#'#
+c=';';comment
+d='#'#comment
+e=\;
+f=\#
+g=\;comment
+h=\#comment
+i=;;
+j=##
+k=;;;;;;;;;;
+l=##########
+
+# Quotes
+[quotes]
+s1='
+s2=''
+s3='''
+s4=''''
+
+d1="
+d2=""
+d3="""
+d4=""""
+
+m1='"'
+m2="'"
+
+h1=hello'world
+h2='hello'world
+h3='hello'world'
+
+h4=hello"world
+h5="hello"world
+h6="hello"world"
+
+# Section names
+[a]
+[ b]
+[c ]
+[ d ]
+[ begin end ]
+[ open[ ]
+
+# Multi-line inputs
+[multi]
+a = begin\
+end
+b = begin \
+end
+c = begin \
+ end
+d = 1\
+2\
+3\
+4
+e = 1 \
+ 2 \
+ 3 \
+ 4
+f = 1 ; \
+hidden = because of the preceding backslash multi-lining the comment ;
+visible = 1
+g = 1 #\
+and now this comment is hidden too \
+and this one too
+h = 1
+multi \
+line \
+key = 1
+multi \
+line \
+key = \
+multi \
+line \
+value ;
+# end of file
diff --git a/iniparser-4.1/src/dictionary.c b/iniparser-4.1/src/dictionary.c
new file mode 100644
index 0000000..7d6bc43
--- /dev/null
+++ b/iniparser-4.1/src/dictionary.c
@@ -0,0 +1,406 @@
+/*-------------------------------------------------------------------------*/
+/**
+ @file dictionary.c
+ @author N. Devillard
+ @brief Implements a dictionary for string variables.
+
+ This module implements a simple dictionary object, i.e. a list
+ of string/string associations. This object is useful to store e.g.
+ informations retrieved from a configuration file (ini files).
+*/
+/*--------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+ Includes
+ ---------------------------------------------------------------------------*/
+#include "dictionary.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/** Maximum value size for integers and doubles. */
+#define MAXVALSZ 1024
+
+/** Minimal allocated number of entries in a dictionary */
+#define DICTMINSZ 128
+
+/** Invalid key token */
+#define DICT_INVALID_KEY ((char*)-1)
+
+/*---------------------------------------------------------------------------
+ Private functions
+ ---------------------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------------*/
+/**
+ @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 Grow user data buffer if it is not large enough.
+ @param dict Dictionary to operate on
+ @param required_size Minimal expected size of user data buffer
+ @return This function returns non-zero in case of failure
+ */
+/*--------------------------------------------------------------------------*/
+int prepare_user_data_buf(dictionary *dict, size_t required_size)
+{
+ char *tmp;
+
+ if (dict->user_data_len < required_size) {
+ tmp = realloc(dict->user_data, required_size);
+ if (!tmp)
+ return -1;
+ dict->user_data = tmp;
+ dict->user_data_len = required_size;
+ }
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @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
+ ---------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Compute the hash key for a string.
+ @param key Character string to use for key.
+ @return 1 unsigned int on at least 32 bits.
+
+ This hash function has been taken from an Article in Dr Dobbs Journal.
+ This is normally a collision-free function, distributing keys evenly.
+ The key is stored anyway in the struct so that collision can be avoided
+ by comparing the key itself in last resort.
+ */
+/*--------------------------------------------------------------------------*/
+unsigned dictionary_hash(const char * key)
+{
+ size_t len ;
+ unsigned hash ;
+ size_t i ;
+
+ if (!key)
+ return 0 ;
+
+ len = strlen(key);
+ for (hash=0, i=0 ; i<len ; i++) {
+ hash += (unsigned)key[i] ;
+ hash += (hash<<10);
+ hash ^= (hash>>6) ;
+ }
+ hash += (hash <<3);
+ hash ^= (hash >>11);
+ hash += (hash <<15);
+ return hash ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Create a new dictionary object.
+ @param size Optional initial size of the dictionary.
+ @return 1 newly allocated dictionary objet.
+
+ This function allocates a new dictionary object of given size and returns
+ 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 ;
+
+ /* If no size was specified, allocate space for DICTMINSZ */
+ if (size<DICTMINSZ) size=DICTMINSZ ;
+
+ d = (dictionary*) calloc(1, sizeof *d) ;
+
+ if (d) {
+ d->size = size ;
+ d->val = (char**) calloc(size, sizeof *d->val);
+ d->key = (char**) calloc(size, sizeof *d->key);
+ d->hash = (unsigned*) calloc(size, sizeof *d->hash);
+ d->user_data = NULL;
+ d->user_data_len = 0;
+ }
+ return d ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Delete a dictionary object
+ @param d dictionary object to deallocate.
+ @return void
+
+ Deallocate a dictionary object and all memory associated to it.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_del(dictionary * d)
+{
+ ssize_t i ;
+
+ if (d==NULL) return ;
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]!=NULL)
+ free(d->key[i]);
+ if (d->val[i]!=NULL)
+ free(d->val[i]);
+ }
+ free(d->val);
+ free(d->key);
+ free(d->hash);
+ free(d->user_data);
+ free(d);
+ return ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get a value from a dictionary.
+ @param d dictionary object to search.
+ @param key Key to look for in the dictionary.
+ @param def Default value to return if key not found.
+ @return 1 pointer to internally allocated character string.
+
+ This function locates a key in a dictionary and returns a pointer to its
+ value, or the passed 'def' pointer if no such key can be found in
+ dictionary. The returned character pointer points to data internal to the
+ dictionary object, you should not try to free it or modify it.
+ */
+/*--------------------------------------------------------------------------*/
+const char * dictionary_get(const dictionary * d, const char * key, const char * def)
+{
+ unsigned hash ;
+ ssize_t i ;
+
+ hash = dictionary_hash(key);
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL)
+ continue ;
+ /* Compare hash */
+ if (hash==d->hash[i]) {
+ /* Compare string, to avoid hash collisions */
+ if (!strcmp(key, d->key[i])) {
+ return d->val[i] ;
+ }
+ }
+ }
+ return def ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Set a value in a dictionary.
+ @param d dictionary object to modify.
+ @param key Key to modify or add.
+ @param val Value to add.
+ @return int 0 if Ok, anything else otherwise
+
+ If the given key is found in the dictionary, the associated value is
+ replaced by the provided one. If the key cannot be found in the
+ dictionary, it is added to it.
+
+ It is Ok to provide a NULL value for val, but NULL values for the dictionary
+ or the key are considered as errors: the function will return immediately
+ in such a case.
+
+ Notice that if you dictionary_set a variable to NULL, a call to
+ dictionary_get will return a NULL value: the variable will be found, and
+ its value (NULL) is returned. In other words, setting the variable
+ content to NULL is equivalent to deleting the variable from the
+ dictionary. It is not possible (in this implementation) to have a key in
+ the dictionary without value.
+
+ This function returns non-zero in case of failure.
+ */
+/*--------------------------------------------------------------------------*/
+int dictionary_set(dictionary * d, const char * key, const char * val)
+{
+ ssize_t i ;
+ unsigned hash ;
+
+ if (d==NULL || key==NULL) return -1 ;
+
+ /* Compute hash for this key */
+ hash = dictionary_hash(key) ;
+ /* Find if value is already in dictionary */
+ if (d->n>0) {
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL)
+ continue ;
+ if (hash==d->hash[i]) { /* Same hash value */
+ if (!strcmp(key, d->key[i])) { /* Same key */
+ /* Found a value: modify and return */
+ if (d->val[i]!=NULL)
+ free(d->val[i]);
+ d->val[i] = (val ? xstrdup(val) : NULL);
+ /* Value has been modified: return */
+ return 0 ;
+ }
+ }
+ }
+ }
+ /* Add a new value */
+ /* See if dictionary needs to grow */
+ if (d->n==d->size) {
+ /* Reached maximum size: reallocate dictionary */
+ if (dictionary_grow(d) != 0)
+ return -1;
+ }
+
+ /* Insert key in the first empty slot. Start at d->n and wrap at
+ d->size. Because d->n < d->size this will necessarily
+ terminate. */
+ for (i=d->n ; d->key[i] ; ) {
+ if(++i == d->size) i = 0;
+ }
+ /* Copy key */
+ d->key[i] = xstrdup(key);
+ d->val[i] = (val ? xstrdup(val) : NULL) ;
+ d->hash[i] = hash;
+ d->n ++ ;
+ return 0 ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Delete a key in a dictionary
+ @param d dictionary object to modify.
+ @param key Key to remove.
+ @return void
+
+ This function deletes a key in a dictionary. Nothing is done if the
+ key cannot be found.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_unset(dictionary * d, const char * key)
+{
+ unsigned hash ;
+ ssize_t i ;
+
+ if (key == NULL || d == NULL) {
+ return;
+ }
+
+ hash = dictionary_hash(key);
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL)
+ continue ;
+ /* Compare hash */
+ if (hash==d->hash[i]) {
+ /* Compare string, to avoid hash collisions */
+ if (!strcmp(key, d->key[i])) {
+ /* Found key */
+ break ;
+ }
+ }
+ }
+ if (i>=d->size)
+ /* Key not found */
+ return ;
+
+ free(d->key[i]);
+ d->key[i] = NULL ;
+ if (d->val[i]!=NULL) {
+ free(d->val[i]);
+ d->val[i] = NULL ;
+ }
+ d->hash[i] = 0 ;
+ d->n -- ;
+ return ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Dump a dictionary to an opened file pointer.
+ @param d Dictionary to dump
+ @param f Opened file pointer.
+ @return void
+
+ Dumps a dictionary onto an opened file pointer. Key pairs are printed out
+ as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as
+ output file pointers.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_dump(const dictionary * d, FILE * out)
+{
+ ssize_t i ;
+
+ if (d==NULL || out==NULL) return ;
+ if (d->n<1) {
+ fprintf(out, "empty dictionary\n");
+ return ;
+ }
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]) {
+ fprintf(out, "%20s\t[%s]\n",
+ d->key[i],
+ d->val[i] ? d->val[i] : "UNDEF");
+ }
+ }
+ return ;
+}
diff --git a/iniparser-4.1/src/dictionary.h b/iniparser-4.1/src/dictionary.h
new file mode 100644
index 0000000..ddf1f1d
--- /dev/null
+++ b/iniparser-4.1/src/dictionary.h
@@ -0,0 +1,190 @@
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @file dictionary.h
+ @author N. Devillard
+ @brief Implements a dictionary for string variables.
+
+ This module implements a simple dictionary object, i.e. a list
+ of string/string associations. This object is useful to store e.g.
+ informations retrieved from a configuration file (ini files).
+*/
+/*--------------------------------------------------------------------------*/
+
+#ifndef _DICTIONARY_H_
+#define _DICTIONARY_H_
+
+/*---------------------------------------------------------------------------
+ Includes
+ ---------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*---------------------------------------------------------------------------
+ New types
+ ---------------------------------------------------------------------------*/
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Dictionary object
+
+ This object contains a list of string/string associations. Each
+ association is identified by a unique string key. Looking up values
+ in the dictionary is speeded up by the use of a (hopefully collision-free)
+ hash function.
+ */
+/*-------------------------------------------------------------------------*/
+typedef struct _dictionary_ {
+ char * user_data; /** Had to add this to make the program robust */
+ size_t user_data_len; /** user_data buffer size */
+ int n ; /** Number of entries in dictionary */
+ 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 */
+} dictionary ;
+
+
+/*---------------------------------------------------------------------------
+ Function prototypes
+ ---------------------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Grow user data buffer if it is not large enough.
+ @param dict Dictionary to operate on
+ @param required_size Minimal expected size of user data buffer
+ @return This function returns non-zero in case of failure
+
+ If dict->user_data is too small to contain required_size bytes,
+ this function attempts to reallocate it into a bigger buffer and
+ updates dict->user_data_len accordingly.
+ */
+/*--------------------------------------------------------------------------*/
+ int prepare_user_data_buf(dictionary *dict, size_t required_size);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Compute the hash key for a string.
+ @param key Character string to use for key.
+ @return 1 unsigned int on at least 32 bits.
+
+ This hash function has been taken from an Article in Dr Dobbs Journal.
+ This is normally a collision-free function, distributing keys evenly.
+ The key is stored anyway in the struct so that collision can be avoided
+ by comparing the key itself in last resort.
+ */
+/*--------------------------------------------------------------------------*/
+unsigned dictionary_hash(const char * key);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Create a new dictionary object.
+ @param size Optional initial size of the dictionary.
+ @return 1 newly allocated dictionary objet.
+
+ This function allocates a new dictionary object of given size and returns
+ 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);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Delete a dictionary object
+ @param d dictionary object to deallocate.
+ @return void
+
+ Deallocate a dictionary object and all memory associated to it.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_del(dictionary * vd);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get a value from a dictionary.
+ @param d dictionary object to search.
+ @param key Key to look for in the dictionary.
+ @param def Default value to return if key not found.
+ @return 1 pointer to internally allocated character string.
+
+ This function locates a key in a dictionary and returns a pointer to its
+ value, or the passed 'def' pointer if no such key can be found in
+ dictionary. The returned character pointer points to data internal to the
+ dictionary object, you should not try to free it or modify it.
+ */
+/*--------------------------------------------------------------------------*/
+const char * dictionary_get(const dictionary * d, const char * key, const char * def);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Set a value in a dictionary.
+ @param d dictionary object to modify.
+ @param key Key to modify or add.
+ @param val Value to add.
+ @return int 0 if Ok, anything else otherwise
+
+ If the given key is found in the dictionary, the associated value is
+ replaced by the provided one. If the key cannot be found in the
+ dictionary, it is added to it.
+
+ It is Ok to provide a NULL value for val, but NULL values for the dictionary
+ or the key are considered as errors: the function will return immediately
+ in such a case.
+
+ Notice that if you dictionary_set a variable to NULL, a call to
+ dictionary_get will return a NULL value: the variable will be found, and
+ its value (NULL) is returned. In other words, setting the variable
+ content to NULL is equivalent to deleting the variable from the
+ dictionary. It is not possible (in this implementation) to have a key in
+ the dictionary without value.
+
+ This function returns non-zero in case of failure.
+ */
+/*--------------------------------------------------------------------------*/
+int dictionary_set(dictionary * vd, const char * key, const char * val);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Delete a key in a dictionary
+ @param d dictionary object to modify.
+ @param key Key to remove.
+ @return void
+
+ This function deletes a key in a dictionary. Nothing is done if the
+ key cannot be found.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_unset(dictionary * d, const char * key);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Dump a dictionary to an opened file pointer.
+ @param d Dictionary to dump
+ @param f Opened file pointer.
+ @return void
+
+ Dumps a dictionary onto an opened file pointer. Key pairs are printed out
+ as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as
+ output file pointers.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_dump(const dictionary * d, FILE * out);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iniparser-4.1/src/getline.c b/iniparser-4.1/src/getline.c
new file mode 100644
index 0000000..4fde05b
--- /dev/null
+++ b/iniparser-4.1/src/getline.c
@@ -0,0 +1,58 @@
+/* The original code is public domain -- Will Hartung 4/9/09 */
+/* Modifications, public domain as well, by Antti Haapala, 11/10/17 */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdint.h>
+
+ssize_t _getline(char **lineptr, size_t *n, FILE *stream,
+ int (*fgetc_impl)(FILE*)) {
+ size_t pos;
+ int c;
+
+ if (lineptr == NULL || stream == NULL || n == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ c = fgetc_impl(stream);
+ if (c == EOF) {
+ return -1;
+ }
+
+ if (*lineptr == NULL) {
+ *lineptr = malloc(128);
+ if (*lineptr == NULL) {
+ return -1;
+ }
+ *n = 128;
+ }
+
+ pos = 0;
+ while(c != EOF) {
+ if (pos + 1 >= *n) {
+ char *new_ptr;
+ size_t new_size = *n + (*n >> 2);
+ if (new_size < 128) {
+ new_size = 128;
+ }
+ new_ptr = realloc(*lineptr, new_size);
+ if (new_ptr == NULL) {
+ return -1;
+ }
+ *n = new_size;
+ *lineptr = new_ptr;
+ }
+
+ ((unsigned char *)(*lineptr))[pos ++] = c;
+ if (c == '\n') {
+ break;
+ }
+ c = fgetc_impl(stream);
+ }
+
+ (*lineptr)[pos] = '\0';
+ return pos;
+}
diff --git a/iniparser-4.1/src/iniparser.c b/iniparser-4.1/src/iniparser.c
new file mode 100644
index 0000000..d3be382
--- /dev/null
+++ b/iniparser-4.1/src/iniparser.c
@@ -0,0 +1,938 @@
+
+/*-------------------------------------------------------------------------*/
+/**
+ @file iniparser.c
+ @author N. Devillard
+ @brief Parser for ini files.
+*/
+/*--------------------------------------------------------------------------*/
+/*---------------------------- Includes ------------------------------------*/
+#include <ctype.h>
+#include <stdarg.h>
+#include <errno.h>
+#include "iniparser.h"
+
+ssize_t _getline(char **lineptr, size_t *n, FILE *stream,
+ int (*fgetc_impl)(FILE*));
+
+/*---------------------------- Defines -------------------------------------*/
+#define INI_INVALID_KEY ((char*)-1)
+
+/*---------------------------------------------------------------------------
+ Private to this module
+ ---------------------------------------------------------------------------*/
+/**
+ * This enum stores the status for each parsed line (internal use only).
+ */
+typedef enum _line_status_ {
+ LINE_ERROR,
+ LINE_EMPTY,
+ LINE_COMMENT,
+ LINE_SECTION,
+ LINE_VALUE
+} line_status ;
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Convert a string to lowercase.
+ @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 convert a string into lowercase.
+ At most len - 1 elements of the input string will be converted.
+ */
+/*--------------------------------------------------------------------------*/
+static const char * strlwc(const char * in, char *out, unsigned len)
+{
+ unsigned i ;
+
+ if (in==NULL || out == NULL || len==0) return NULL ;
+ i=0 ;
+ while (in[i] != '\0' && i < len-1) {
+ out[i] = (char)tolower((int)in[i]);
+ i++ ;
+ }
+ out[i] = '\0';
+ return out ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Convert a string to lowercase in-place.
+ @param in String to convert.
+ @return value of in argument.
+
+ This function convert a string into lowercase.
+ */
+/*--------------------------------------------------------------------------*/
+static char *strlwc_in_place(char *in)
+{
+ unsigned i ;
+
+ if (in == NULL)
+ return NULL;
+
+ i = 0;
+ while (in[i] != '\0') {
+ in[i] = tolower(in[i]);
+ i++;
+ }
+
+ return in;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Find substrings without blanks at the beginning nor end.
+ @param s String to parse.
+ @param s_end End of string to parse.
+ @param begin Place to store pointer to the beginning of substring or NULL.
+ @param end Place to store pointer to the end of substring or NULL.
+ @return unsigned New size of the string.
+ */
+/*--------------------------------------------------------------------------*/
+static size_t strstrip(char *s, char *s_end,
+ char **begin, char **end)
+{
+ char *_begin, *_end;
+
+ _begin = s;
+ _end = s_end;
+
+ while (_begin < _end && isspace((int) *_begin))
+ _begin++;
+
+ while (_begin < _end && isspace((int) *(_end - 1)))
+ _end--;
+
+ if (begin)
+ *begin = _begin;
+ if (end)
+ *end = _end;
+ return _end - _begin;
+}
+
+/**
+ * This variable defines, whether multiline values should be parsed.
+ */
+static int process_multiline = 1;
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Configure whether to parse multiline values.
+ @param process_multiline Boolean (0 or 1) value.
+
+ By default, multiline values will be parsed. If someone puts into their .ini
+ file 2 lines like those:
+
+ outputdir=c:\temp\
+ save_subject=1
+
+ then we're screwed. All will be treated as if it was on one line.
+ This function makes it possible to disable this linebreak feature.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_set_process_multiline(int process)
+{
+ process_multiline = process;
+}
+
+/**
+ * This variable points to the function, that should be used for reading data.
+ */
+static int (*fgetc_impl)(FILE*) = fgetc;
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Configure a function to read file.
+ @param impl Function to call.
+
+ By default, fgetc() will be used for reading files. If a null pointer is passed
+ as impl the reading callback will be switched back to default.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_set_fgetc_impl(int (*impl)(FILE*))
+{
+ if (impl)
+ fgetc_impl = impl;
+ else
+ fgetc_impl = fgetc;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @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;
+ }
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get number of sections in a dictionary
+ @param d Dictionary to examine
+ @return int Number of sections found in dictionary
+
+ This function returns the number of sections found in a dictionary.
+ The test to recognize sections is done on the string stored in the
+ dictionary: a section name is given as "section" whereas a key is
+ stored as "section:key", thus the test looks for entries that do not
+ contain a colon.
+
+ This clearly fails in the case a section name contains a colon, but
+ this should simply be avoided.
+
+ This function returns -1 in case of error.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_getnsec(const dictionary * d)
+{
+ int i ;
+ int nsec ;
+
+ if (d==NULL) return -1 ;
+ nsec=0 ;
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL)
+ continue ;
+ if (strchr(d->key[i], ':')==NULL) {
+ nsec ++ ;
+ }
+ }
+ return nsec ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get name for section n in a dictionary.
+ @param d Dictionary to examine
+ @param n Section number (from 0 to nsec-1).
+ @return Pointer to char string
+
+ This function locates the n-th section in a dictionary and returns
+ its name as a pointer to a string statically allocated inside the
+ dictionary. Do not free or modify the returned string!
+
+ This function returns NULL in case of error.
+ */
+/*--------------------------------------------------------------------------*/
+const char * iniparser_getsecname(const dictionary * d, int n)
+{
+ int i ;
+ int foundsec ;
+
+ if (d==NULL || n<0) return NULL ;
+ foundsec=0 ;
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL)
+ continue ;
+ if (strchr(d->key[i], ':')==NULL) {
+ foundsec++ ;
+ if (foundsec>n)
+ break ;
+ }
+ }
+ if (foundsec<=n) {
+ return NULL ;
+ }
+ return d->key[i] ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Dump a dictionary to an opened file pointer.
+ @param d Dictionary to dump.
+ @param f Opened file pointer to dump to.
+ @return void
+
+ This function prints out the contents of a dictionary, one element by
+ line, onto the provided file pointer. It is OK to specify @c stderr
+ or @c stdout as output files. This function is meant for debugging
+ purposes mostly.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_dump(const dictionary * d, FILE * f)
+{
+ int i ;
+
+ if (d==NULL || f==NULL) return ;
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL)
+ continue ;
+ if (d->val[i]!=NULL) {
+ fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]);
+ } else {
+ fprintf(f, "[%s]=UNDEF\n", d->key[i]);
+ }
+ }
+ return ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Save a dictionary to a loadable ini file
+ @param d Dictionary to dump
+ @param f Opened file pointer to dump to
+ @return void
+
+ This function dumps a given dictionary into a loadable ini file.
+ It is Ok to specify @c stderr or @c stdout as output files.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_dump_ini(const dictionary * d, FILE * f)
+{
+ int i ;
+ int nsec ;
+ const char * secname ;
+
+ if (d==NULL || f==NULL) return ;
+
+ nsec = iniparser_getnsec(d);
+ if (nsec<1) {
+ /* No section in file: dump all keys as they are */
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL)
+ continue ;
+ fprintf(f, "%s = %s\n", d->key[i], d->val[i]);
+ }
+ return ;
+ }
+ for (i=0 ; i<nsec ; i++) {
+ secname = iniparser_getsecname(d, i) ;
+ iniparser_dumpsection_ini(d, secname, f);
+ }
+ fprintf(f, "\n");
+ return ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Save a dictionary section to a loadable ini file
+ @param d Dictionary to dump
+ @param s Section name of dictionary to dump
+ @param f Opened file pointer to dump to
+ @return void
+
+ This function dumps a given section of a given dictionary into a loadable ini
+ file. It is Ok to specify @c stderr or @c stdout as output files.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_dumpsection_ini(const dictionary * d, const char * s, FILE * f)
+{
+ size_t j, len;
+
+ if (d == NULL || f == NULL)
+ return;
+ if (!iniparser_find_entry(d, s))
+ return;
+
+ fprintf(f, "\n[%s]\n", s);
+
+ len = strlen(s) + 1;
+
+ strlwc(s, d->user_data, len);
+ d->user_data[len - 1] = ':';
+
+ for (j = 0 ; j < (size_t) d->size ; j++) {
+ if (d->key[j]==NULL)
+ continue;
+ if (!strncmp(d->key[j], d->user_data, len)) {
+ fprintf(f,
+ "%-30s = %s\n",
+ d->key[j]+len,
+ d->val[j] ? d->val[j] : "");
+ }
+ }
+
+ fprintf(f, "\n");
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @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 Number of keys in section
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_getsecnkeys(const dictionary * d, const char * s)
+{
+ size_t len, nkeys;
+ size_t j;
+
+ nkeys = 0;
+
+ if (d == NULL)
+ return nkeys;
+ if (! iniparser_find_entry(d, s))
+ return nkeys;
+
+ len = strlen(s) + 1;
+ if (len + 1 > d->user_data_len)
+ return nkeys;
+
+ strlwc(s, d->user_data, len);
+ d->user_data[len - 1] = ':';
+
+ for (j = 0 ; j < (size_t) d->size; j++) {
+ if (d->key[j] == NULL)
+ continue;
+ if (!strncmp(d->key[j], d->user_data, len))
+ nkeys++;
+ }
+
+ return nkeys;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @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
+ @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.
+ */
+/*--------------------------------------------------------------------------*/
+const char ** iniparser_getseckeys(const dictionary * d, const char * s, const char ** keys)
+{
+ size_t i, j, len;
+
+ if (d == NULL || keys == NULL)
+ return NULL;
+ if (! iniparser_find_entry(d, s))
+ return NULL;
+
+ len = strlen(s) + 1;
+ strlwc(s, d->user_data, len);
+ d->user_data[len - 1] = ':';
+
+ i = 0;
+
+ for (j = 0; j < (size_t) d->size; j++) {
+ if (d->key[j]==NULL)
+ continue ;
+ if (!strncmp(d->key[j], d->user_data, len)) {
+ keys[i] = d->key[j];
+ i++;
+ }
+ }
+
+ return keys;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get the string associated to a key
+ @param d Dictionary to search
+ @param key Key string to look for
+ @param def Default value to return if key not found.
+ @return pointer to statically allocated character string
+
+ 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 pointer passed as 'def' is returned.
+ The returned char pointer is pointing to a string allocated in
+ the dictionary, do not free or modify it.
+ */
+/*--------------------------------------------------------------------------*/
+const char * iniparser_getstring(const dictionary * d, const char * key,
+ const char * def)
+{
+ const char * sval;
+ size_t len = strlen(key) + 1;
+
+ if (d==NULL || key==NULL)
+ return def;
+
+ if (len > d->user_data_len)
+ return def;
+
+ strlwc(key, d->user_data, len);
+ sval = dictionary_get(d, d->user_data, def);
+ 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
+ @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.
+
+ Credits: Thanks to A. Becker for suggesting strtol()
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_getint(const dictionary * d, const char * key, int notfound)
+{
+ return (int)iniparser_getlongint(d, key, notfound);
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get the string associated to a key, convert to a double
+ @param d Dictionary to search
+ @param key Key string to look for
+ @param notfound Value to return in case of error
+ @return double
+
+ 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.
+ */
+/*--------------------------------------------------------------------------*/
+double iniparser_getdouble(const dictionary * d, const char * key, double notfound)
+{
+ const char * str ;
+
+ str = iniparser_getstring(d, key, INI_INVALID_KEY);
+ if (str==INI_INVALID_KEY) return notfound ;
+ return atof(str);
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get the string associated to a key, convert to a boolean
+ @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.
+
+ A true boolean is found if one of the following is matched:
+
+ - A string starting with 'y'
+ - A string starting with 'Y'
+ - A string starting with 't'
+ - A string starting with 'T'
+ - A string starting with '1'
+
+ A false boolean is found if one of the following is matched:
+
+ - A string starting with 'n'
+ - A string starting with 'N'
+ - A string starting with 'f'
+ - A string starting with 'F'
+ - A string starting with '0'
+
+ The notfound value returned if no boolean is identified, does not
+ necessarily have to be 0 or 1.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_getboolean(const dictionary * d, const char * key, int notfound)
+{
+ int ret ;
+ const char * c ;
+
+ c = iniparser_getstring(d, key, INI_INVALID_KEY);
+ if (c==INI_INVALID_KEY) return notfound ;
+ if (c[0]=='y' || c[0]=='Y' || c[0]=='1' || c[0]=='t' || c[0]=='T') {
+ ret = 1 ;
+ } else if (c[0]=='n' || c[0]=='N' || c[0]=='0' || c[0]=='f' || c[0]=='F') {
+ ret = 0 ;
+ } else {
+ ret = notfound ;
+ }
+ return ret;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Finds out if a given entry exists in a dictionary
+ @param ini Dictionary to search
+ @param entry Name of the entry to look for
+ @return integer 1 if entry exists, 0 otherwise
+
+ Finds out if a given entry exists in the dictionary. Since sections
+ are stored as keys with NULL associated values, this is the only way
+ of querying for the presence of sections in a dictionary.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_find_entry(const dictionary * ini, const char * entry)
+{
+ int found=0 ;
+ if (iniparser_getstring(ini, entry, INI_INVALID_KEY)!=INI_INVALID_KEY) {
+ found = 1 ;
+ }
+ return found ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Set an entry in a dictionary.
+ @param ini Dictionary to modify.
+ @param entry Entry to modify (entry name)
+ @param val New value to associate to the entry.
+ @return int 0 if Ok, -1 otherwise.
+
+ If the given entry can be found in the dictionary, it is modified to
+ 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)
+{
+ size_t len = strlen(entry) + 1;
+ int result;
+
+ if (prepare_user_data_buf(ini, len))
+ return -1;
+
+ result = dictionary_set(ini, strlwc(entry, ini->user_data, len), val);
+
+ return result;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Delete an entry in a dictionary
+ @param ini Dictionary to modify
+ @param entry Entry to delete (entry name)
+ @return void
+
+ If the given entry can be found, it is deleted from the dictionary.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_unset(dictionary * ini, const char * entry)
+{
+ size_t len = strlen(entry) + 1;
+ if (len <= ini->user_data_len)
+ dictionary_unset(ini, strlwc(entry, ini->user_data, len));
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Load a single line from an INI file
+ @param input_line Input line, may be concatenated multi-line input
+ @param section Output place to store section
+ @param key Output place to store key
+ @param value Output place to store value
+ @return line_status value
+ */
+/*--------------------------------------------------------------------------*/
+static line_status iniparser_line(
+ char * input_line,
+ char ** section,
+ char ** key,
+ char ** value)
+{
+ char *line, *line_end, *substr, *substr_end, *tmp;
+
+ strstrip(input_line, input_line + strlen(input_line), &line, &line_end);
+
+ if (*line == ';' || *line == '#') {
+ /* Comment line */
+ return LINE_COMMENT;
+ }
+ if (line == line_end) {
+ return LINE_EMPTY;
+ }
+ if (line[0] == '[' && line_end[-1] == ']') {
+ /* Section name */
+ strstrip(line + 1, line_end - 1, &substr, &substr_end);
+ *substr_end = '\0';
+ *section = strlwc_in_place(substr);
+ return LINE_SECTION;
+ }
+
+ /* Key and value */
+ substr = line;
+ substr_end = substr;
+ while (*substr_end != '=') {
+ if (++substr_end == line_end)
+ break;
+ }
+ if (substr_end == line_end)
+ return LINE_ERROR;
+ tmp = substr_end;
+
+ /* Get key */
+ strstrip(substr, substr_end, &substr, &substr_end);
+ *substr_end = '\0';
+ *key = strlwc_in_place(substr);
+
+ /* Get value */
+ substr = tmp + 1;
+ substr_end = line_end;
+ strstrip(substr, substr_end, &substr, &substr_end);
+ *substr_end = '\0';
+
+ if ((substr[0] == '\'' && (tmp = strchr(substr + 1, '\''))) ||
+ (substr[0] == '"' && (tmp = strchr(substr + 1, '"')))) {
+ /* Handle quoted values */
+ substr++;
+ substr_end = tmp;
+ } else {
+ /* Handle comments */
+ for (tmp = substr; *tmp; tmp++) {
+ if (*tmp == ';' || *tmp == '#')
+ break;
+ }
+ if (*tmp)
+ strstrip(substr, tmp, &substr, &substr_end);
+ }
+
+ *substr_end = '\0';
+ *value = substr;
+
+ return LINE_VALUE;
+}
+
+static char empty_string[] = "";
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Parse an ini file and return an allocated dictionary object
+ @param ininame Name of the ini file to read.
+ @return Pointer to newly allocated dictionary
+
+ This is the parser for ini files. This function is called, providing
+ the name of the file to be read. It returns a dictionary object that
+ should not be accessed directly, but through accessor functions
+ instead.
+
+ The returned dictionary must be freed using iniparser_freedict().
+ */
+/*--------------------------------------------------------------------------*/
+dictionary * iniparser_load(const char * ininame)
+{
+ FILE * in = NULL;
+
+ char *read_buf = NULL;
+ size_t read_buf_len = 0;
+ ssize_t read_len;
+
+ char *line = NULL, *tmp;
+ size_t line_len = 0;
+ int append_to_line = 0;
+
+ char *section;
+ char *key;
+ char *val;
+
+ const char *current_section = empty_string;
+
+ int lineno = 0;
+ int errs = 0;
+ int sections = 0;
+
+ dictionary * dict;
+
+ if ((in=fopen(ininame, "r"))==NULL) {
+ iniparser_error_callback("iniparser: cannot open %s\n", ininame);
+ return NULL;
+ }
+
+ dict = dictionary_new(0) ;
+ if (!dict)
+ goto fail;
+
+ while (1) {
+ errno = 0;
+ read_len = _getline(&read_buf, &read_buf_len, in, fgetc_impl);
+ if (read_len < 1) {
+ if (errno)
+ goto fail;
+ break;
+ }
+ /* printf("read buf: %s", read_buf); */
+ if (read_buf[read_len - 1] == '\n')
+ read_buf[--read_len] = '\0';
+
+ lineno++;
+
+ if (append_to_line) {
+ if (read_len > 0) {
+ tmp = realloc(line, line_len + read_len + 1);
+ if (!tmp)
+ goto fail;
+ line = tmp;
+ memcpy(line + line_len, read_buf, read_len + 1);
+ line_len += read_len;
+ }
+ } else {
+ line = malloc(read_len + 1);
+ if (!line)
+ goto fail;
+ memcpy(line, read_buf, read_len + 1);
+ line_len = read_len;
+ }
+
+ /* Detect multi-line */
+ append_to_line = 0;
+ if (process_multiline) {
+ tmp = strrchr(line, '\\');
+ if (tmp && !strstrip(tmp + 1, line + line_len, NULL, NULL)) {
+ /* Multi-line value */
+ line_len = tmp - line;
+ line[line_len] = '\0';
+ append_to_line = 1;
+ continue;
+ }
+ }
+
+ switch (iniparser_line(line, &section, &key, &val)) {
+ case LINE_EMPTY:
+ case LINE_COMMENT:
+ break;
+
+ case LINE_SECTION:
+ if (prepare_user_data_buf(dict, strlen(current_section) + 2))
+ goto fail;
+
+ if (dictionary_set(dict, section, NULL) < 0)
+ goto fail;
+ current_section = iniparser_getsecname(dict, sections++);
+ break;
+
+ case LINE_VALUE:
+ if (prepare_user_data_buf
+ (dict, strlen(current_section) + strlen(key) + 2))
+ goto fail;
+
+ sprintf(dict->user_data, "%s:%s", current_section, key);
+
+ if (dictionary_set(dict, dict->user_data, val))
+ goto fail;
+ break;
+
+ case LINE_ERROR:
+ iniparser_error_callback(
+ "iniparser: syntax error in %s (%d):\n-> %s\n",
+ ininame,
+ lineno,
+ line);
+ errs++;
+ break;
+
+ default:
+ break;
+ }
+
+ free(line);
+ }
+ if (errs) {
+ dictionary_del(dict);
+ dict = NULL;
+ }
+ free(read_buf);
+ fclose(in);
+ return dict;
+
+fail:
+ if (in)
+ fclose(in);
+ dictionary_del(dict);
+ free(read_buf);
+ free(line);
+ iniparser_error_callback("iniparser: memory allocation failure\n");
+ return NULL;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Free all memory associated to an ini dictionary
+ @param d Dictionary to free
+ @return void
+
+ Free all memory associated to an ini dictionary.
+ It is mandatory to call this function before the dictionary object
+ gets out of the current context.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_freedict(dictionary * d)
+{
+ dictionary_del(d);
+}
diff --git a/iniparser-4.1/src/iniparser.h b/iniparser-4.1/src/iniparser.h
new file mode 100644
index 0000000..e00530d
--- /dev/null
+++ b/iniparser-4.1/src/iniparser.h
@@ -0,0 +1,386 @@
+
+/*-------------------------------------------------------------------------*/
+/**
+ @file iniparser.h
+ @author N. Devillard
+ @brief Parser for ini files.
+*/
+/*--------------------------------------------------------------------------*/
+
+#ifndef _INIPARSER_H_
+#define _INIPARSER_H_
+
+/*---------------------------------------------------------------------------
+ Includes
+ ---------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * The following #include is necessary on many Unixes but not Linux.
+ * It is not needed for Windows platforms.
+ * Uncomment it if needed.
+ */
+/* #include <unistd.h> */
+
+#include "dictionary.h"
+
+#ifdef __cplusplus
+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 Configure whether to parse multiline values.
+ @param process_multiline Boolean (0 or 1) value.
+
+ By default, multiline values will be parsed. If someone puts into their .ini
+ file 2 lines like those:
+
+ outputdir=c:\temp\
+ save_subject=1
+
+ then we're screwed. All will be treated as if it was on one line.
+ This function makes it possible to disable this linebreak feature.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_set_process_multiline(int process);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Configure a function to read file.
+ @param impl Function to call.
+
+ By default, fgetc() will be used for reading files. If a null pointer is passed
+ as impl the reading callback will be switched back to default.
+ */
+/*--------------------------------------------------------------------------*/
+ void iniparser_set_fgetc_impl(int (*impl)(FILE*));
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get number of sections in a dictionary
+ @param d Dictionary to examine
+ @return int Number of sections found in dictionary
+
+ This function returns the number of sections found in a dictionary.
+ The test to recognize sections is done on the string stored in the
+ dictionary: a section name is given as "section" whereas a key is
+ stored as "section:key", thus the test looks for entries that do not
+ contain a colon.
+
+ This clearly fails in the case a section name contains a colon, but
+ this should simply be avoided.
+
+ This function returns -1 in case of error.
+ */
+/*--------------------------------------------------------------------------*/
+
+int iniparser_getnsec(const dictionary * d);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get name for section n in a dictionary.
+ @param d Dictionary to examine
+ @param n Section number (from 0 to nsec-1).
+ @return Pointer to char string
+
+ This function locates the n-th section in a dictionary and returns
+ its name as a pointer to a string statically allocated inside the
+ dictionary. Do not free or modify the returned string!
+
+ This function returns NULL in case of error.
+ */
+/*--------------------------------------------------------------------------*/
+
+const char * iniparser_getsecname(const dictionary * d, int n);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Save a dictionary to a loadable ini file
+ @param d Dictionary to dump
+ @param f Opened file pointer to dump to
+ @return void
+
+ This function dumps a given dictionary into a loadable ini file.
+ It is Ok to specify @c stderr or @c stdout as output files.
+ */
+/*--------------------------------------------------------------------------*/
+
+void iniparser_dump_ini(const dictionary * d, FILE * f);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Save a dictionary section to a loadable ini file
+ @param d Dictionary to dump
+ @param s Section name of dictionary to dump
+ @param f Opened file pointer to dump to
+ @return void
+
+ This function dumps a given section of a given dictionary into a loadable ini
+ file. It is Ok to specify @c stderr or @c stdout as output files.
+ */
+/*--------------------------------------------------------------------------*/
+
+void iniparser_dumpsection_ini(const dictionary * d, const char * s, FILE * f);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Dump a dictionary to an opened file pointer.
+ @param d Dictionary to dump.
+ @param f Opened file pointer to dump to.
+ @return void
+
+ This function prints out the contents of a dictionary, one element by
+ line, onto the provided file pointer. It is OK to specify @c stderr
+ or @c stdout as output files. This function is meant for debugging
+ purposes mostly.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_dump(const dictionary * d, FILE * f);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @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 Number of keys in section
+ */
+/*--------------------------------------------------------------------------*/
+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
+ @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.
+ */
+/*--------------------------------------------------------------------------*/
+const char ** iniparser_getseckeys(const dictionary * d, const char * s, const char ** keys);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get the string associated to a key
+ @param d Dictionary to search
+ @param key Key string to look for
+ @param def Default value to return if key not found.
+ @return pointer to statically allocated character string
+
+ 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 pointer passed as 'def' is returned.
+ The returned char pointer is pointing to a string allocated in
+ the dictionary, do not free or modify it.
+ */
+/*--------------------------------------------------------------------------*/
+const char * iniparser_getstring(const dictionary * d, const char * key, const char * def);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get the string associated to a key, convert to an 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.
+
+ Credits: Thanks to A. Becker for suggesting strtol()
+ */
+/*--------------------------------------------------------------------------*/
+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);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get the string associated to a key, convert to a double
+ @param d Dictionary to search
+ @param key Key string to look for
+ @param notfound Value to return in case of error
+ @return double
+
+ 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.
+ */
+/*--------------------------------------------------------------------------*/
+double iniparser_getdouble(const dictionary * d, const char * key, double notfound);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get the string associated to a key, convert to a boolean
+ @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.
+
+ A true boolean is found if one of the following is matched:
+
+ - A string starting with 'y'
+ - A string starting with 'Y'
+ - A string starting with 't'
+ - A string starting with 'T'
+ - A string starting with '1'
+
+ A false boolean is found if one of the following is matched:
+
+ - A string starting with 'n'
+ - A string starting with 'N'
+ - A string starting with 'f'
+ - A string starting with 'F'
+ - A string starting with '0'
+
+ The notfound value returned if no boolean is identified, does not
+ necessarily have to be 0 or 1.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_getboolean(const dictionary * d, const char * key, int notfound);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Set an entry in a dictionary.
+ @param ini Dictionary to modify.
+ @param entry Entry to modify (entry name)
+ @param val New value to associate to the entry.
+ @return int 0 if Ok, -1 otherwise.
+
+ If the given entry can be found in the dictionary, it is modified to
+ 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);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Delete an entry in a dictionary
+ @param ini Dictionary to modify
+ @param entry Entry to delete (entry name)
+ @return void
+
+ If the given entry can be found, it is deleted from the dictionary.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_unset(dictionary * ini, const char * entry);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Finds out if a given entry exists in a dictionary
+ @param ini Dictionary to search
+ @param entry Name of the entry to look for
+ @return integer 1 if entry exists, 0 otherwise
+
+ Finds out if a given entry exists in the dictionary. Since sections
+ are stored as keys with NULL associated values, this is the only way
+ of querying for the presence of sections in a dictionary.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_find_entry(const dictionary * ini, const char * entry) ;
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Parse an ini file and return an allocated dictionary object
+ @param ininame Name of the ini file to read.
+ @return Pointer to newly allocated dictionary
+
+ This is the parser for ini files. This function is called, providing
+ the name of the file to be read. It returns a dictionary object that
+ should not be accessed directly, but through accessor functions
+ instead.
+
+ The returned dictionary must be freed using iniparser_freedict().
+ */
+/*--------------------------------------------------------------------------*/
+dictionary * iniparser_load(const char * ininame);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Free all memory associated to an ini dictionary
+ @param d Dictionary to free
+ @return void
+
+ Free all memory associated to an ini dictionary.
+ It is mandatory to call this function before the dictionary object
+ gets out of the current context.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_freedict(dictionary * d);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iniparser-4.1/test/CuTest.c b/iniparser-4.1/test/CuTest.c
new file mode 100644
index 0000000..463f170
--- /dev/null
+++ b/iniparser-4.1/test/CuTest.c
@@ -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);
+ }
+}
diff --git a/iniparser-4.1/test/CuTest.h b/iniparser-4.1/test/CuTest.h
new file mode 100644
index 0000000..0f58592
--- /dev/null
+++ b/iniparser-4.1/test/CuTest.h
@@ -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 */
diff --git a/iniparser-4.1/test/CuTest_license.txt b/iniparser-4.1/test/CuTest_license.txt
new file mode 100644
index 0000000..5f053ba
--- /dev/null
+++ b/iniparser-4.1/test/CuTest_license.txt
@@ -0,0 +1,38 @@
+NOTE
+
+The license is based on the zlib/libpng license. For more details see
+http://www.opensource.org/licenses/zlib-license.html. The intent of the
+license is to:
+
+- keep the license as simple as possible
+- encourage the use of CuTest in both free and commercial applications
+ and libraries
+- keep the source code together
+- give credit to the CuTest contributors for their work
+
+If you ship CuTest in source form with your source distribution, the
+following license document must be included with it in unaltered form.
+If you find CuTest useful we would like to hear about it.
+
+LICENSE
+
+Copyright (c) 2003 Asim Jalis
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not
+claim that you wrote the original software. If you use this software in
+a product, an acknowledgment in the product documentation would be
+appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and must not
+be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source
+distribution.
diff --git a/iniparser-4.1/test/Makefile b/iniparser-4.1/test/Makefile
new file mode 100644
index 0000000..15a8d26
--- /dev/null
+++ b/iniparser-4.1/test/Makefile
@@ -0,0 +1,35 @@
+CC ?= gcc
+
+ifndef V
+QUIET_CC = @echo "CC $@";
+QUIET_MAKE_TESTS = @echo "GN Alltests.c";
+endif
+
+DEPS = $(shell ls ../src/*.[ch])
+
+SRC = $(shell ls *.c | sed 's/AllTests.c//')
+OBJ = $(SRC:.c=.o)
+
+INCLUDE = -I../src
+CFLAGS += -pipe -ansi -pedantic -Wall -Wextra -g
+LDFLAGS +=
+
+all: check
+
+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 -rf AllTests.c
+ rm -rf $(OBJ) AllTests.o
+ rm -rf testrun
diff --git a/iniparser-4.1/test/make-tests.sh b/iniparser-4.1/test/make-tests.sh
new file mode 100755
index 0000000..f2a3f2a
--- /dev/null
+++ b/iniparser-4.1/test/make-tests.sh
@@ -0,0 +1,56 @@
+#!/usr/bin/env bash
+
+# Auto generate single AllTests file for CuTest.
+# Searches through all *.c files in the current directory.
+# Prints to stdout.
+# Author: Asim Jalis
+# Date: 01/08/2003
+
+if test $# -eq 0 ; then FILES=*.c ; else FILES=$* ; fi
+
+echo '
+
+/* This is auto-generated code. Edit at your own peril. */
+#include <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;
+}
+'
diff --git a/iniparser-4.1/test/ressources/bad_ini/ends_well.ini b/iniparser-4.1/test/ressources/bad_ini/ends_well.ini
new file mode 100644
index 0000000..3f920c7
--- /dev/null
+++ b/iniparser-4.1/test/ressources/bad_ini/ends_well.ini
@@ -0,0 +1,6 @@
+#
+# This dict contains an error but ends up with a correct entry
+#
+[section]
+error is here
+a = b
diff --git a/iniparser-4.1/test/ressources/bad_ini/twisted-errors.ini b/iniparser-4.1/test/ressources/bad_ini/twisted-errors.ini
new file mode 100644
index 0000000..4dc3bbe
--- /dev/null
+++ b/iniparser-4.1/test/ressources/bad_ini/twisted-errors.ini
@@ -0,0 +1,9 @@
+#
+# All of these should trigger syntax errors
+#
+[section]
+hello
+world
+hello \
+world
+a + b ;
diff --git a/iniparser-4.1/test/ressources/bad_ini/twisted-ofkey.ini b/iniparser-4.1/test/ressources/bad_ini/twisted-ofkey.ini
new file mode 100644
index 0000000..4f2e72e
--- /dev/null
+++ b/iniparser-4.1/test/ressources/bad_ini/twisted-ofkey.ini
@@ -0,0 +1,66 @@
+# Stress testing buffers for overflows
+[long]
+# Shitload key size
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa=1
+
diff --git a/iniparser-4.1/test/ressources/bad_ini/twisted-ofval.ini b/iniparser-4.1/test/ressources/bad_ini/twisted-ofval.ini
new file mode 100644
index 0000000..2a3cedf
--- /dev/null
+++ b/iniparser-4.1/test/ressources/bad_ini/twisted-ofval.ini
@@ -0,0 +1,56 @@
+# Shitload data size
+[long]
+a=\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890;
+
diff --git a/iniparser-4.1/test/ressources/good_ini/empty.ini b/iniparser-4.1/test/ressources/good_ini/empty.ini
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/iniparser-4.1/test/ressources/good_ini/empty.ini
diff --git a/iniparser-4.1/test/ressources/good_ini/spaced.ini b/iniparser-4.1/test/ressources/good_ini/spaced.ini
new file mode 100644
index 0000000..8e78e3b
--- /dev/null
+++ b/iniparser-4.1/test/ressources/good_ini/spaced.ini
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/iniparser-4.1/test/ressources/good_ini/spaced2.ini b/iniparser-4.1/test/ressources/good_ini/spaced2.ini
new file mode 100644
index 0000000..2acbd74
--- /dev/null
+++ b/iniparser-4.1/test/ressources/good_ini/spaced2.ini
@@ -0,0 +1,20 @@
+
+# spaced2.ini
+
+[blanks]
+
+
+
+
+
+
+
+
+
+
+
+a=1
+b=1;
+c=1; comment
+d=1# comment
+ \ No newline at end of file
diff --git a/iniparser-4.1/test/ressources/good_ini/twisted.ini b/iniparser-4.1/test/ressources/good_ini/twisted.ini
new file mode 100644
index 0000000..86e549f
--- /dev/null
+++ b/iniparser-4.1/test/ressources/good_ini/twisted.ini
@@ -0,0 +1,131 @@
+#
+# Twisted.ini
+# This file is meant for regression tests
+
+# Different blank settings around the equal sign
+[blanks]
+a=1
+b=1;
+c=1; comment
+d=1# comment
+
+e =1
+f =1;
+g =1; comment
+h =1# comment
+
+i= 1
+j= 1;
+k= 1; comment
+l= 1# comment
+
+m = 1
+n = 1;
+o = 1; comment
+p = 1# comment
+
+q=1 ;
+r=1 ; comment
+s=1 ;comment
+t=1 #comment
+
+# Empty values
+[empty]
+a = ''
+b = ""
+
+c = '' ;
+d = "" ;
+
+e = '' ; comment
+f = "" ; comment
+
+g =
+h = ;
+i = ; comment
+j = # comment
+
+k=
+l=;
+m=;comment
+n=#
+
+# Peculiar values
+[peculiar]
+a=';';
+b='#'#
+c=';';comment
+d='#'#comment
+e=\;
+f=\#
+g=\;comment
+h=\#comment
+i=;;
+j=##
+k=;;;;;;;;;;
+l=##########
+
+# Quotes
+[quotes]
+s1='
+s2=''
+s3='''
+s4=''''
+
+d1="
+d2=""
+d3="""
+d4=""""
+
+m1='"'
+m2="'"
+
+h1=hello'world
+h2='hello'world
+h3='hello'world'
+
+h4=hello"world
+h5="hello"world
+h6="hello"world"
+
+# Section names
+[a]
+[ b]
+[c ]
+[ d ]
+[ begin end ]
+[ open[ ]
+
+# Multi-line inputs
+[multi]
+a = begin\
+end
+b = begin \
+end
+c = begin \
+ end
+d = 1\
+2\
+3\
+4
+e = 1 \
+ 2 \
+ 3 \
+ 4
+f = 1 ; \
+hidden = because of the preceding backslash multi-lining the comment ;
+visible = 1
+g = 1 #\
+and now this comment is hidden too \
+and this one too
+h = 1
+multi \
+line \
+key = 1
+multi \
+line \
+key = \
+multi \
+line \
+value ;
+# end of file
diff --git a/iniparser-4.1/test/test_dictionary.c b/iniparser-4.1/test/test_dictionary.c
new file mode 100644
index 0000000..f89f1c1
--- /dev/null
+++ b/iniparser-4.1/test/test_dictionary.c
@@ -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);
+}
diff --git a/iniparser-4.1/test/test_iniparser.c b/iniparser-4.1/test/test_iniparser.c
new file mode 100644
index 0000000..c76529c
--- /dev/null
+++ b/iniparser-4.1/test/test_iniparser.c
@@ -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[128];
+ unsigned i;
+
+ /* NULL ptr as input */
+ strstrip(NULL);
+
+ /* empty string */
+ for (i = 0 ; i < sizeof (strings_empty) / sizeof (char *) ; ++i) {
+ strcpy(stripped, strings_empty[i]);
+ strstrip(stripped);
+ sprintf(error_msg, "Bad stripping : strstrip(\"%s\") ==> \"%s\"",
+ strings_empty[i], stripped);
+ CuAssertStrEquals_Msg(tc, error_msg, stripped, strings_empty[0]);
+ }
+
+ /* test string */
+ for (i = 0 ; i < sizeof (strings_test) / sizeof (char *) ; ++i) {
+ strcpy(stripped, strings_test[i]);
+ strstrip(stripped);
+ sprintf(error_msg, "Bad stripping : strstrip(\"%s\") ==> \"%s\"",
+ strings_test[i], stripped);
+ CuAssertStrEquals_Msg(tc, error_msg, strings_test[0], stripped);
+ }
+ strcpy(stripped, ".");
+ strstrip(stripped);
+ CuAssertStrEquals(tc, ".", stripped);
+
+ /* string containing spaces */
+ strcpy(stripped, test_with_spaces);
+ strstrip(stripped);
+ CuAssertStrEquals(tc, test_with_spaces, stripped);
+}
+
+void Test_iniparser_getnsec(CuTest *tc)
+{
+ int i;
+ char sec_name[32];
+ dictionary *dic;
+
+ /* NULL test */
+ CuAssertIntEquals(tc, -1, iniparser_getnsec(NULL));
+
+ /* Empty dictionary */
+ dic = dictionary_new(10);
+ CuAssertIntEquals(tc, 0, iniparser_getnsec(dic));
+ dictionary_del(dic);
+
+ /* Regular dictionary */
+ dic = generate_dictionary(512, 0);
+ CuAssertIntEquals(tc, 512, iniparser_getnsec(dic));
+
+ /* Check after removing sections */
+ for (i = 1; i < 512; ++i) {
+ sprintf(sec_name, "sec%d", i);
+ dictionary_unset(dic, sec_name);
+ CuAssertIntEquals(tc, 512 - i, iniparser_getnsec(dic));
+ }
+ dictionary_del(dic);
+
+ /* Mix sections and regular keys */
+ dic = generate_dictionary(10, 512);
+ CuAssertIntEquals(tc, 10, iniparser_getnsec(dic));
+ dictionary_del(dic);
+}
+
+void Test_iniparser_getsecname(CuTest *tc)
+{
+ unsigned i;
+ char sec_name[32];
+ dictionary *dic;
+ /* NULL test */
+ CuAssertTrue(tc, iniparser_getsecname(NULL, 0) == NULL);
+
+ /* Empty dictionary */
+ dic = dictionary_new(10);
+ CuAssertPtrEquals(tc, NULL, iniparser_getsecname(dic, 0));
+ dictionary_del(dic);
+
+ /* Sections without entries dictionary */
+ dic = generate_dictionary(100, 0);
+ for (i = 0; i < 100; ++i) {
+ sprintf(sec_name, "sec%d", i);
+ CuAssertStrEquals(tc, sec_name, iniparser_getsecname(dic, i));
+ }
+ dictionary_del(dic);
+
+ /* Generic dictionary */
+ dic = generate_dictionary(10, 100);
+ for (i = 0; i < 10; ++i) {
+ sprintf(sec_name, "sec%d", i);
+ CuAssertStrEquals(tc, sec_name, iniparser_getsecname(dic, i));
+ }
+ dictionary_del(dic);
+}
+
+void Test_iniparser_getseckeys(CuTest *tc)
+{
+ unsigned i;
+ char key_name[64];
+ dictionary *dic;
+ 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[256];
+
+ /* Dummy tests */
+ dic = iniparser_load("/you/shall/not/path");
+ CuAssertPtrEquals(tc, NULL, dic);
+
+ /* Test all the good .ini files */
+ dir = opendir(GOOD_INI_PATH);
+ CuAssertPtrNotNullMsg(tc, "Cannot open good .ini conf directory", dir);
+ for (curr = readdir(dir); curr != NULL; curr = readdir(dir)) {
+ sprintf(ini_path, "%s/%s", GOOD_INI_PATH, curr->d_name);
+ stat(ini_path, &curr_stat);
+ if (S_ISREG(curr_stat.st_mode)) {
+ dic = iniparser_load(ini_path);
+ CuAssertPtrNotNullMsg(tc, ini_path, dic);
+ dictionary_del(dic);
+ }
+ }
+ closedir(dir);
+
+ /* Test all the bad .ini files */
+ dir = opendir(BAD_INI_PATH);
+ CuAssertPtrNotNullMsg(tc, "Cannot open bad .ini conf directory", dir);
+ for (curr = readdir(dir); curr != NULL; curr = readdir(dir)) {
+ sprintf(ini_path, "%s/%s", BAD_INI_PATH, curr->d_name);
+ stat(ini_path, &curr_stat);
+ if (S_ISREG(curr_stat.st_mode)) {
+ dic = iniparser_load(ini_path);
+ CuAssertPtrEquals_Msg(tc, ini_path, NULL, dic);
+ dictionary_del(dic);
+ }
+ }
+ closedir(dir);
+}
+
+void Test_dictionary_wrapper(CuTest *tc)
+{
+ dictionary *dic;
+
+ dic = dictionary_new(10);
+
+ CuAssertIntEquals(tc, -1, iniparser_set(dic, NULL, NULL));
+ CuAssertIntEquals(tc, -1, iniparser_set(NULL, "section", "value"));
+
+ CuAssertIntEquals(tc, 0, iniparser_set(dic, "section", NULL));
+ CuAssertIntEquals(tc, 0, iniparser_set(dic, "section:key", "value"));
+
+ CuAssertStrEquals(tc, "value", iniparser_getstring(dic, "section:key", NULL));
+ /* reset the key's value*/
+ CuAssertIntEquals(tc, 0, iniparser_set(dic, "section:key", NULL));
+ CuAssertStrEquals(tc, NULL, iniparser_getstring(dic, "section:key", "dummy"));
+ CuAssertIntEquals(tc, 0, iniparser_set(dic, "section:key", "value"));
+ CuAssertStrEquals(tc, "value", iniparser_getstring(dic, "section:key", NULL));
+
+ iniparser_unset(dic, "section:key");
+ CuAssertStrEquals(tc, "dummy", iniparser_getstring(dic, "section:key", "dummy"));
+ CuAssertStrEquals(tc, NULL, iniparser_getstring(dic, "section", "dummy"));
+
+ CuAssertIntEquals(tc, 0, iniparser_set(dic, "section:key", NULL));
+ CuAssertIntEquals(tc, 0, iniparser_set(dic, "section:key1", NULL));
+ CuAssertIntEquals(tc, 0, iniparser_set(dic, "section:key2", NULL));
+
+ iniparser_unset(dic, "section");
+ CuAssertStrEquals(tc, NULL, iniparser_getstring(dic, "section", NULL));
+
+ iniparser_freedict(dic);
+}
+
+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);
+}