From aa4d426b4d3527d7e166df1a05058c9a4a0f6683 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Fri, 30 Apr 2021 00:33:56 +0200 Subject: initial/final commit --- iniparser-4.1/.gitignore | 11 + iniparser-4.1/.travis.yml | 9 + iniparser-4.1/AUTHORS | 6 + iniparser-4.1/FAQ-en.md | 37 + iniparser-4.1/FAQ-zhcn.md | 27 + iniparser-4.1/INSTALL | 15 + iniparser-4.1/LICENSE | 40 + iniparser-4.1/Makefile | 86 ++ iniparser-4.1/README.md | 44 + iniparser-4.1/doc/Makefile | 16 + iniparser-4.1/doc/iniparser.dox | 81 ++ iniparser-4.1/doc/iniparser.main | 207 +++++ iniparser-4.1/example/Makefile | 27 + iniparser-4.1/example/iniexample.c | 104 +++ iniparser-4.1/example/parse.c | 24 + iniparser-4.1/example/twisted-errors.ini | 9 + iniparser-4.1/example/twisted-genhuge.py | 12 + iniparser-4.1/example/twisted-ofkey.ini | 66 ++ iniparser-4.1/example/twisted-ofval.ini | 56 ++ iniparser-4.1/example/twisted.ini | 131 +++ iniparser-4.1/src/dictionary.c | 406 +++++++++ iniparser-4.1/src/dictionary.h | 190 +++++ iniparser-4.1/src/getline.c | 58 ++ iniparser-4.1/src/iniparser.c | 938 +++++++++++++++++++++ iniparser-4.1/src/iniparser.h | 386 +++++++++ iniparser-4.1/test/CuTest.c | 348 ++++++++ iniparser-4.1/test/CuTest.h | 121 +++ iniparser-4.1/test/CuTest_license.txt | 38 + iniparser-4.1/test/Makefile | 35 + iniparser-4.1/test/make-tests.sh | 56 ++ .../test/ressources/bad_ini/ends_well.ini | 6 + .../test/ressources/bad_ini/twisted-errors.ini | 9 + .../test/ressources/bad_ini/twisted-ofkey.ini | 66 ++ .../test/ressources/bad_ini/twisted-ofval.ini | 56 ++ iniparser-4.1/test/ressources/good_ini/empty.ini | 0 iniparser-4.1/test/ressources/good_ini/spaced.ini | 16 + iniparser-4.1/test/ressources/good_ini/spaced2.ini | 20 + iniparser-4.1/test/ressources/good_ini/twisted.ini | 131 +++ iniparser-4.1/test/test_dictionary.c | 237 ++++++ iniparser-4.1/test/test_iniparser.c | 698 +++++++++++++++ 40 files changed, 4823 insertions(+) create mode 100644 iniparser-4.1/.gitignore create mode 100644 iniparser-4.1/.travis.yml create mode 100644 iniparser-4.1/AUTHORS create mode 100644 iniparser-4.1/FAQ-en.md create mode 100644 iniparser-4.1/FAQ-zhcn.md create mode 100644 iniparser-4.1/INSTALL create mode 100644 iniparser-4.1/LICENSE create mode 100644 iniparser-4.1/Makefile create mode 100644 iniparser-4.1/README.md create mode 100644 iniparser-4.1/doc/Makefile create mode 100644 iniparser-4.1/doc/iniparser.dox create mode 100644 iniparser-4.1/doc/iniparser.main create mode 100644 iniparser-4.1/example/Makefile create mode 100644 iniparser-4.1/example/iniexample.c create mode 100644 iniparser-4.1/example/parse.c create mode 100644 iniparser-4.1/example/twisted-errors.ini create mode 100644 iniparser-4.1/example/twisted-genhuge.py create mode 100644 iniparser-4.1/example/twisted-ofkey.ini create mode 100644 iniparser-4.1/example/twisted-ofval.ini create mode 100644 iniparser-4.1/example/twisted.ini create mode 100644 iniparser-4.1/src/dictionary.c create mode 100644 iniparser-4.1/src/dictionary.h create mode 100644 iniparser-4.1/src/getline.c create mode 100644 iniparser-4.1/src/iniparser.c create mode 100644 iniparser-4.1/src/iniparser.h create mode 100644 iniparser-4.1/test/CuTest.c create mode 100644 iniparser-4.1/test/CuTest.h create mode 100644 iniparser-4.1/test/CuTest_license.txt create mode 100644 iniparser-4.1/test/Makefile create mode 100755 iniparser-4.1/test/make-tests.sh create mode 100644 iniparser-4.1/test/ressources/bad_ini/ends_well.ini create mode 100644 iniparser-4.1/test/ressources/bad_ini/twisted-errors.ini create mode 100644 iniparser-4.1/test/ressources/bad_ini/twisted-ofkey.ini create mode 100644 iniparser-4.1/test/ressources/bad_ini/twisted-ofval.ini create mode 100644 iniparser-4.1/test/ressources/good_ini/empty.ini create mode 100644 iniparser-4.1/test/ressources/good_ini/spaced.ini create mode 100644 iniparser-4.1/test/ressources/good_ini/spaced2.ini create mode 100644 iniparser-4.1/test/ressources/good_ini/twisted.ini create mode 100644 iniparser-4.1/test/test_dictionary.c create mode 100644 iniparser-4.1/test/test_iniparser.c (limited to 'iniparser-4.1') 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 + +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 +#include +#include +#include + +#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 +#include +#include +#include + +#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 +#include +#include +#include + +/** 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>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 (sizesize = 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 ; isize ; 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 ; isize ; 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 ; isize ; 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 ; isize ; 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 ; isize ; 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 +#include +#include +#include + +#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 +#include +#include +#include +#include + +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 +#include +#include +#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 ; isize ; 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 ; isize ; 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 ; isize ; 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 ; isize ; i++) { + if (d->key[i]==NULL) + continue ; + fprintf(f, "%s = %s\n", d->key[i], d->val[i]); + } + return ; + } + for (i=0 ; iuser_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, §ion, &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 +#include +#include + +/* + * The following #include is necessary on many Unixes but not Linux. + * It is not needed for Windows platforms. + * Uncomment it if needed. + */ +/* #include */ + +#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 +#include +#include +#include +#include +#include + +#include "CuTest.h" + +/*-------------------------------------------------------------------------* + * CuStr + *-------------------------------------------------------------------------*/ + +char* CuStrAlloc(int size) +{ + char* newStr = (char*) malloc( sizeof(char) * (size) ); + return newStr; +} + +char* CuStrCopy(const char* old) +{ + int len = strlen(old); + char* newStr = CuStrAlloc(len + 1); + strcpy(newStr, old); + return newStr; +} + +/*-------------------------------------------------------------------------* + * CuString + *-------------------------------------------------------------------------*/ + +void CuStringInit(CuString* str) +{ + str->length = 0; + str->size = STRING_MAX; + str->buffer = (char*) malloc(sizeof(char) * str->size); + str->buffer[0] = '\0'; +} + +CuString* CuStringNew(void) +{ + CuString* str = (CuString*) malloc(sizeof(CuString)); + str->length = 0; + str->size = STRING_MAX; + str->buffer = (char*) malloc(sizeof(char) * str->size); + str->buffer[0] = '\0'; + return str; +} + +void CuStringDelete(CuString *str) +{ + if (!str) return; + free(str->buffer); + free(str); +} + +void CuStringResize(CuString* str, int newSize) +{ + str->buffer = (char*) realloc(str->buffer, sizeof(char) * newSize); + str->size = newSize; +} + +void CuStringAppend(CuString* str, const char* text) +{ + int length; + + if (text == NULL) { + text = "NULL"; + } + + length = strlen(text); + if (str->length + length + 1 >= str->size) + CuStringResize(str, str->length + length + 1 + STRING_INC); + str->length += length; + strcat(str->buffer, text); +} + +void CuStringAppendChar(CuString* str, char ch) +{ + char text[2]; + text[0] = ch; + text[1] = '\0'; + CuStringAppend(str, text); +} + +void CuStringAppendFormat(CuString* str, const char* format, ...) +{ + va_list argp; + char buf[HUGE_STRING_LEN]; + va_start(argp, format); + vsprintf(buf, format, argp); + va_end(argp); + CuStringAppend(str, buf); +} + +void CuStringInsert(CuString* str, const char* text, int pos) +{ + int length = strlen(text); + if (pos > str->length) + pos = str->length; + if (str->length + length + 1 >= str->size) + CuStringResize(str, str->length + length + 1 + STRING_INC); + memmove(str->buffer + pos + length, str->buffer + pos, (str->length - pos) + 1); + str->length += length; + memcpy(str->buffer + pos, text, length); +} + +/*-------------------------------------------------------------------------* + * CuTest + *-------------------------------------------------------------------------*/ + +void CuTestInit(CuTest* t, const char* name, TestFunction function) +{ + t->name = CuStrCopy(name); + t->failed = 0; + t->ran = 0; + t->message = NULL; + t->function = function; + t->jumpBuf = NULL; +} + +CuTest* CuTestNew(const char* name, TestFunction function) +{ + CuTest* tc = CU_ALLOC(CuTest); + CuTestInit(tc, name, function); + return tc; +} + +void CuTestDelete(CuTest *t) +{ + if (!t) return; + free(t->name); + free(t); +} + +void CuTestRun(CuTest* tc) +{ + jmp_buf buf; + tc->jumpBuf = &buf; + if (setjmp(buf) == 0) + { + tc->ran = 1; + (tc->function)(tc); + } + tc->jumpBuf = 0; +} + +static void CuFailInternal(CuTest* tc, const char* file, int line, CuString* string) +{ + char buf[HUGE_STRING_LEN]; + + sprintf(buf, "%s:%d: ", file, line); + CuStringInsert(string, buf, 0); + + tc->failed = 1; + tc->message = string->buffer; + if (tc->jumpBuf != 0) longjmp(*(tc->jumpBuf), 0); +} + +void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message) +{ + CuString string; + + CuStringInit(&string); + if (message2 != NULL) + { + CuStringAppend(&string, message2); + CuStringAppend(&string, ": "); + } + CuStringAppend(&string, message); + CuFailInternal(tc, file, line, &string); +} + +void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition) +{ + if (condition) return; + CuFail_Line(tc, file, line, NULL, message); +} + +void CuAssertStrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, + const char* expected, const char* actual) +{ + CuString string; + if ((expected == NULL && actual == NULL) || + (expected != NULL && actual != NULL && + strcmp(expected, actual) == 0)) + { + return; + } + + CuStringInit(&string); + if (message != NULL) + { + CuStringAppend(&string, message); + CuStringAppend(&string, ": "); + } + CuStringAppend(&string, "expected <"); + CuStringAppend(&string, expected); + CuStringAppend(&string, "> but was <"); + CuStringAppend(&string, actual); + CuStringAppend(&string, ">"); + CuFailInternal(tc, file, line, &string); +} + +void CuAssertIntEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, + int expected, int actual) +{ + char buf[STRING_MAX]; + if (expected == actual) return; + sprintf(buf, "expected <%d> but was <%d>", expected, actual); + CuFail_Line(tc, file, line, message, buf); +} + +void 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 +#include + +#define CUTEST_VERSION "CuTest 1.5" + +/* CuString */ + +char* CuStrAlloc(int size); +char* CuStrCopy(const char* old); + +#define CU_ALLOC(TYPE) ((TYPE*) malloc(sizeof(TYPE))) + +#define HUGE_STRING_LEN 8192 +#define STRING_MAX 256 +#define STRING_INC 256 + +typedef struct +{ + int length; + int size; + char* buffer; +} CuString; + +void CuStringInit(CuString* str); +CuString* CuStringNew(void); +void CuStringRead(CuString* str, const char* path); +void CuStringAppend(CuString* str, const char* text); +void CuStringAppendChar(CuString* str, char ch); +void CuStringAppendFormat(CuString* str, const char* format, ...); +void CuStringInsert(CuString* str, const char* text, int pos); +void CuStringResize(CuString* str, int newSize); +void CuStringDelete(CuString* str); + +/* CuTest */ + +typedef struct CuTest CuTest; + +typedef void (*TestFunction)(CuTest *); + +struct CuTest +{ + char* name; + TestFunction function; + int failed; + int ran; + const char* message; + jmp_buf *jumpBuf; +}; + +void CuTestInit(CuTest* t, const char* name, TestFunction function); +CuTest* CuTestNew(const char* name, TestFunction function); +void CuTestRun(CuTest* tc); +void CuTestDelete(CuTest *t); + +/* Internal versions of assert functions -- use the public versions */ +void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message); +void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition); +void CuAssertStrEquals_LineMsg(CuTest* tc, + const char* file, int line, const char* message, + const char* expected, const char* actual); +void CuAssertIntEquals_LineMsg(CuTest* tc, + const char* file, int line, const char* message, + int expected, int actual); +void 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 +#include + +#include "CuTest.h" + +' + +cat $FILES | grep '^void Test' | + sed -e 's/(.*$//' \ + -e 's/$/(CuTest*);/' \ + -e 's/^/extern /' + +echo \ +' + +void RunAllTests(void) +{ + CuString *output = CuStringNew(); + CuSuite* suite = CuSuiteNew(); + +' +cat $FILES | grep '^void Test' | + sed -e 's/^void //' \ + -e 's/(.*$//' \ + -e 's/^/ SUITE_ADD_TEST(suite, /' \ + -e 's/$/);/' + +echo \ +' + CuSuiteRun(suite); + CuSuiteSummary(suite, output); + CuSuiteDetails(suite, output); + printf("%s\n", output->buffer); + CuStringDelete(output); + CuSuiteDelete(suite); +} + +int main(void) +{ + RunAllTests(); + return 0; +} +' diff --git a/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 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 +#include + +#include "CuTest.h" + +/* We need to directly insert the .c file in order to test the */ +/* static functions as well */ +#include "dictionary.c" + +void Test_xstrdup(CuTest *tc) +{ + size_t i; + char *dup_str; + const char *strings[] = { + "", + "test", + " " + }; + char *string_very_long; + + /* NULL test */ + CuAssertPtrEquals(tc, NULL, xstrdup(NULL)); + + for (i = 0 ; i < sizeof(strings) / sizeof(char *) ; ++i) { + dup_str = xstrdup(strings[i]); + CuAssertStrEquals(tc, strings[i], dup_str); + free(dup_str); + } + + /* test a overflowing string */ + string_very_long = (char*) malloc(10 * 1024); + memset(string_very_long, '#', 10 * 1024); + string_very_long[10 * 1024 - 1] = '\0'; + dup_str = xstrdup(string_very_long); + CuAssertStrEquals(tc, string_very_long, dup_str); + + free(string_very_long); + free(dup_str); +} + +void Test_dictionary_grow(CuTest *tc) +{ + unsigned i; + dictionary *dic; + + dic = dictionary_new(DICTMINSZ); + CuAssertPtrNotNull(tc, dic); + CuAssertIntEquals(tc, 0, dic->n); + CuAssertIntEquals(tc, DICTMINSZ, dic->size); + + for (i = 1 ; i < 10 ; ++i) { + CuAssertIntEquals(tc, 0, dictionary_grow(dic)); + CuAssertIntEquals(tc, 0, dic->n); + CuAssertIntEquals(tc, (1 << i) * DICTMINSZ, dic->size); + } +} + +void Test_dictionary_hash(CuTest *tc) +{ + /* NULL test */ + CuAssertIntEquals(tc, 0, dictionary_hash(NULL)); +} + +void Test_dictionary_growing(CuTest *tc) +{ + int i, j; + char sec_name[32]; + char key_name[64]; + dictionary *dic; + + dic = dictionary_new(DICTMINSZ); + CuAssertPtrNotNull(tc, dic); + CuAssertIntEquals(tc, 0, dic->n); + + /* Makes the dictionary grow */ + for (i = 1 ; i < 101; ++i) { + sprintf(sec_name, "sec%d", i); + CuAssertIntEquals(tc, 0, dictionary_set(dic, sec_name, "")); + for (j = 1 ; j < 11; ++j) { + sprintf(key_name, "%s:key%d", sec_name, j); + CuAssertIntEquals(tc, 0, dictionary_set(dic, key_name, "dummy_value")); + CuAssertIntEquals(tc, i + (i - 1) * 10 + j, dic->n); + } + } + + /* Shrink the dictionary */ + for (i = 100 ; i > 0; --i) { + sprintf(sec_name, "sec%d", i); + for (j = 10 ; j > 0; --j) { + sprintf(key_name, "%s:key%d", sec_name, j); + dictionary_unset(dic, key_name); + } + dictionary_unset(dic, sec_name); + CuAssertIntEquals(tc, (i - 1) * (11), dic->n); + } + + dictionary_del(dic); +} + +static char *get_dump(dictionary *d) +{ + FILE *fd; + char *dump_buff; + int dump_size; + + /* Dump the dictionary in temporary file */ + fd = tmpfile(); + if (fd == NULL) + return NULL; + dictionary_dump(d, fd); + + /* Retrieve the dump file */ + dump_size = ftell(fd); + if (dump_size == -1) { + fclose(fd); + return NULL; + } + rewind(fd); + + dump_buff = (char*) calloc(1, dump_size + 1); + if (dump_buff == NULL) { + fclose(fd); + return NULL; + } + 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 +#include +#include +#include +#include +#include + +#include "CuTest.h" +#include "dictionary.h" + +/* We need to directly insert the .c file in order to test the */ +/* static functions as well */ +#include "iniparser.c" + +#define GOOD_INI_PATH "ressources/good_ini" +#define BAD_INI_PATH "ressources/bad_ini" + + +/* Tool function to create and populate a generic non-empty dictionary */ +static dictionary * generate_dictionary(unsigned sections, unsigned entries_per_section) +{ + unsigned i, j ; + dictionary * dic; + char sec_name[32]; + char key_name[64]; + char key_value[32]; + + dic = dictionary_new(sections + sections * entries_per_section); + if (dic == NULL) + return NULL; + + /* Insert the sections */ + for (i = 0; i < sections; ++i) { + sprintf(sec_name, "sec%d", i); + dictionary_set(dic, sec_name, ""); + for (j = 0; j < entries_per_section; ++j) { + /* Populate the section with the entries */ + sprintf(key_name, "%s:key%d", sec_name, j); + sprintf(key_value, "value-%d/%d", i, j); + dictionary_set(dic, key_name, key_value); + } + } + + return dic; +} + +void Test_iniparser_strlwc(CuTest *tc) +{ + char out_buffer[128]; + + /* NULL ptr as input */ + CuAssertPtrEquals(tc, NULL, strlwc(NULL, NULL, 0)); + CuAssertPtrEquals(tc, NULL, strlwc(NULL, out_buffer, sizeof (out_buffer))); + CuAssertPtrEquals(tc, NULL, strlwc("", NULL, sizeof (out_buffer))); + CuAssertPtrEquals(tc, NULL, strlwc("", out_buffer, 0)); + CuAssertPtrEquals(tc, NULL, strlwc(NULL, NULL, 0)); + + /* empty string */ + CuAssertStrEquals(tc, "", strlwc("", out_buffer, sizeof (out_buffer))); + + CuAssertStrEquals(tc, " ", strlwc(" ", out_buffer, sizeof (out_buffer))); + CuAssertStrEquals(tc, "test", strlwc("test", out_buffer, sizeof (out_buffer))); + CuAssertStrEquals(tc, "test", strlwc("TEST", out_buffer, sizeof (out_buffer))); + CuAssertStrEquals(tc, "test", strlwc("TeSt", out_buffer, sizeof (out_buffer))); + CuAssertStrEquals(tc, "test test", + strlwc("TEST TEST", out_buffer, sizeof (out_buffer))); + CuAssertStrEquals(tc, "very long string !!!!!!!", + strlwc("very long string !!!!!!!", out_buffer, sizeof (out_buffer))); + CuAssertStrEquals(tc, "cutted string", strlwc("cutted string<---here", out_buffer, 14)); + + /* test using same buffer as input and output */ + strcpy(out_buffer, "OVERWRITE ME !"); + CuAssertPtrNotNull(tc, strlwc(out_buffer, out_buffer, sizeof(out_buffer))); + CuAssertStrEquals(tc, "overwrite me !", out_buffer); +} + +void Test_iniparser_strstrip(CuTest *tc) +{ + /* First element in the array is the expected stripping result */ + const char *strings_empty[] = { + "", + " ", + "\n\n\n\n", + "\t\t\t\t", + "\n \t\n\t\n " + }; + const char *strings_test[] = { + "test", + "test ", + "test ", + " test", + " test ", + "\ttest\t", + "\ttest\n" + + }; + const char *test_with_spaces = "I am a test with\tspaces."; + char stripped[ASCIILINESZ+1]; + char error_msg[128]; + unsigned i; + + /* NULL ptr as input */ + strstrip(NULL); + + /* empty string */ + for (i = 0 ; i < sizeof (strings_empty) / sizeof (char *) ; ++i) { + strcpy(stripped, strings_empty[i]); + strstrip(stripped); + sprintf(error_msg, "Bad stripping : strstrip(\"%s\") ==> \"%s\"", + strings_empty[i], stripped); + CuAssertStrEquals_Msg(tc, error_msg, stripped, strings_empty[0]); + } + + /* test string */ + for (i = 0 ; i < sizeof (strings_test) / sizeof (char *) ; ++i) { + strcpy(stripped, strings_test[i]); + strstrip(stripped); + sprintf(error_msg, "Bad stripping : strstrip(\"%s\") ==> \"%s\"", + strings_test[i], stripped); + CuAssertStrEquals_Msg(tc, error_msg, strings_test[0], stripped); + } + strcpy(stripped, "."); + strstrip(stripped); + CuAssertStrEquals(tc, ".", stripped); + + /* string containing spaces */ + strcpy(stripped, test_with_spaces); + strstrip(stripped); + CuAssertStrEquals(tc, test_with_spaces, stripped); +} + +void Test_iniparser_getnsec(CuTest *tc) +{ + int i; + char sec_name[32]; + dictionary *dic; + + /* NULL test */ + CuAssertIntEquals(tc, -1, iniparser_getnsec(NULL)); + + /* Empty dictionary */ + dic = dictionary_new(10); + CuAssertIntEquals(tc, 0, iniparser_getnsec(dic)); + dictionary_del(dic); + + /* Regular dictionary */ + dic = generate_dictionary(512, 0); + CuAssertIntEquals(tc, 512, iniparser_getnsec(dic)); + + /* Check after removing sections */ + for (i = 1; i < 512; ++i) { + sprintf(sec_name, "sec%d", i); + dictionary_unset(dic, sec_name); + CuAssertIntEquals(tc, 512 - i, iniparser_getnsec(dic)); + } + dictionary_del(dic); + + /* Mix sections and regular keys */ + dic = generate_dictionary(10, 512); + CuAssertIntEquals(tc, 10, iniparser_getnsec(dic)); + dictionary_del(dic); +} + +void Test_iniparser_getsecname(CuTest *tc) +{ + unsigned i; + char sec_name[32]; + dictionary *dic; + /* NULL test */ + CuAssertTrue(tc, iniparser_getsecname(NULL, 0) == NULL); + + /* Empty dictionary */ + dic = dictionary_new(10); + CuAssertPtrEquals(tc, NULL, iniparser_getsecname(dic, 0)); + dictionary_del(dic); + + /* Sections without entries dictionary */ + dic = generate_dictionary(100, 0); + for (i = 0; i < 100; ++i) { + sprintf(sec_name, "sec%d", i); + CuAssertStrEquals(tc, sec_name, iniparser_getsecname(dic, i)); + } + dictionary_del(dic); + + /* Generic dictionary */ + dic = generate_dictionary(10, 100); + for (i = 0; i < 10; ++i) { + sprintf(sec_name, "sec%d", i); + CuAssertStrEquals(tc, sec_name, iniparser_getsecname(dic, i)); + } + dictionary_del(dic); +} + +void Test_iniparser_getseckeys(CuTest *tc) +{ + unsigned i; + char key_name[64]; + dictionary *dic; + 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); +} -- cgit v1.2.3