diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 08d2bd8..5115df0 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -10,13 +10,15 @@ stages: - doc - test - win + - prepare + - release build: stage: build script: - mkdir build - cd build - - cmake -DCMAKE_INSTALL_PREFIX=../install -DBUILD_TESTING=ON -DBUILD_EXAMPLES=ON .. + - cmake -DCMAKE_INSTALL_PREFIX=../install -DBUILD_TESTING=ON -DBUILD_EXAMPLES=ON -DBUILD_DOCS=ON .. - make install - tree -a . artifacts: @@ -98,14 +100,47 @@ win-build: - git clone https://github.com/tronkko/dirent.git - mkdir build - cd build - - cmake -DCMAKE_INCLUDE_PATH="../dirent/include" -DBUILD_DOCS=OFF -DBUILD_TESTING=ON -DBUILD_EXAMPLES=ON .. + - cmake -DCMAKE_INCLUDE_PATH="../dirent/include" -DBUILD_TESTING=ON -DBUILD_EXAMPLES=ON .. - cmake --build . + - Get-Location + - Get-ChildItem –Recurse # due to the long provisioning time of the Windows runner, tests are # executed in the same stage as the build - ctest -C Debug --verbose artifacts: paths: - - install/ - build/ dependencies: [] +prepare_job: + stage: prepare + image: alpine:latest + rules: + - if: '$CI_COMMIT_TAG =~ /^v?\d+\.\d+\.\d+$/' + script: + - apk add curl jq + - 'curl -H "PRIVATE-TOKEN: $CI_API_TOKEN" "$CI_API_V4_URL/projects/$CI_PROJECT_ID/repository/changelog?version=$CI_COMMIT_TAG" | jq -r .notes > release_notes.md' + - 'curl -H "PRIVATE-TOKEN: $CI_API_TOKEN" -X POST "$CI_API_V4_URL/projects/$CI_PROJECT_ID/repository/changelog?version=$CI_COMMIT_TAG"' + artifacts: + paths: + - release_notes.md + +release_job: + stage: release + image: registry.gitlab.com/gitlab-org/release-cli:latest + needs: + - job: prepare_job + artifacts: true + rules: + - if: '$CI_COMMIT_TAG =~ /^v?\d+\.\d+\.\d+$/' + script: + - echo "Creating release" + release: + name: 'Release $CI_COMMIT_TAG' + description: release_notes.md + tag_name: '$CI_COMMIT_TAG' + ref: '$CI_COMMIT_SHA' + #assets: + # links: + # - name: 'Container Image $CI_COMMIT_TAG' + # url: "https://$CI_REGISTRY_IMAGE/$CI_COMMIT_REF_SLUG:$CI_COMMIT_SHA" diff --git a/.gitmessage b/.gitmessage new file mode 100644 index 0000000..4750ed8 --- /dev/null +++ b/.gitmessage @@ -0,0 +1,4 @@ +# + + +Changelog: diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e695d7..40eca17 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,22 +1,30 @@ cmake_minimum_required(VERSION 3.18) -project(iniparser VERSION 4.2.4) +project( + iniparser + DESCRIPTION "C library for parsing INI-style files" + HOMEPAGE_URL https://gitlab.com/iniparser/iniparser/ + LANGUAGES C + VERSION 4.2.5) include(GNUInstallDirs) include(CMakePackageConfigHelpers) include(CMakeDependentOption) -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} - "${CMAKE_CURRENT_SOURCE_DIR}/cmake") +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake") option( BUILD_SHARED_LIBS "Build using shared libraries" ON) -# For packaging by tools like bitbake, shared and static libs should be build -# at once -CMAKE_DEPENDENT_OPTION(BUILD_STATIC_LIBS "Build static libs" ON - "BUILD_SHARED_LIBS" OFF) +# For packaging by tools like bitbake, shared and static libs should be build at +# once +cmake_dependent_option( + BUILD_STATIC_LIBS + "Build static libs" + ON + "BUILD_SHARED_LIBS" + OFF) if(BUILD_SHARED_LIBS) list( APPEND @@ -46,12 +54,47 @@ foreach(TARGET_TYPE ${TARGET_TYPES}) set(PUBLIC_HEADERS "src/iniparser.h" "src/dictionary.h") set_target_properties(${TARGET_NAME} PROPERTIES PUBLIC_HEADER "${PUBLIC_HEADERS}") - target_include_directories( ${TARGET_NAME} PUBLIC $ $) - set_target_properties(${TARGET_NAME} PROPERTIES OUTPUT_NAME ${PROJECT_NAME}) + # If both shared and static libs are build at once with MSVC it generates a + # shared library consisting of + # + # * a DLL (that contains the actual code) with filename suffix `.dll`, + # * a correspoding import library (against which users should link) with + # filename suffix `.lib`. + # + # and a static library with filename suffix `.lib` + # + # As both, the shared import library and the static library share the same + # basename and suffix one would overwrite the other. + # + # To solve this issue we set the PREFIX for *static* libs explicitely so MSVC + # will build: + # + # * shared: iniparser.dll + # * import: iniparser.lib + # * static: libiniparser.lib + # + # As all other platforms already set `PREFIX` for all lib types they remain + # unchanged. Therefore no `if(MSVC)` check is needed here. + # + if(TARGET_TYPE + MATCHES + "static") + set_target_properties(${TARGET_NAME} + PROPERTIES OUTPUT_NAME "${PROJECT_NAME}" PREFIX "lib") + else() + set_target_properties(${TARGET_NAME} PROPERTIES OUTPUT_NAME ${PROJECT_NAME}) + # automatically create a module definition (.def) file for MSVC so it will + # build an import library (.lib) + set_property(TARGET ${TARGET_NAME} PROPERTY WINDOWS_EXPORT_ALL_SYMBOLS 1) + if(WIN32) + # Let MinGW as MSVC not prefix the DLL + set_property(TARGET ${TARGET_NAME} PROPERTY PREFIX "") + endif() + endif() set_target_properties(${TARGET_NAME} PROPERTIES VERSION ${PROJECT_VERSION}) set_target_properties(${TARGET_NAME} PROPERTIES SOVERSION ${PROJECT_VERSION_MAJOR}) @@ -71,6 +114,7 @@ foreach(TARGET_TYPE ${TARGET_TYPES}) EXPORT ${TARGETS_EXPORT_NAME} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} # install DLLs on Windows PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}) # build directory package config @@ -112,8 +156,15 @@ file(COPY ${FIND_MODULES} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) export(PACKAGE ${PROJECT_NAME}) # generate pc-file include(JoinPaths) -join_paths(libdir_for_pc_file "\${exec_prefix}" "${CMAKE_INSTALL_LIBDIR}") -join_paths(includedir_for_pc_file "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}" "${PROJECT_NAME}") +join_paths( + libdir_for_pc_file + "\${exec_prefix}" + "${CMAKE_INSTALL_LIBDIR}") +join_paths( + includedir_for_pc_file + "\${prefix}" + "${CMAKE_INSTALL_INCLUDEDIR}" + "${PROJECT_NAME}") configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/pc.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc @@ -148,19 +199,16 @@ if(BUILD_EXAMPLES) DESTINATION ${CMAKE_INSTALL_DOCDIR}/examples/) endif() -option( - BUILD_DOCS - "Build and install docs" - ON) +option(BUILD_DOCS "Build and install docs") if(BUILD_DOCS) find_package(Doxygen REQUIRED) set(DOXYGEN_STRIP_FROM_PATH ${CMAKE_CURRENT_SOURCE_DIR}) + set(DOXYGEN_USE_MDFILE_AS_MAINPAGE README.md) doxygen_add_docs( docs - ${CMAKE_CURRENT_SOURCE_DIR}/doc/iniparser.txt + ${CMAKE_CURRENT_SOURCE_DIR}/README.md ${CMAKE_CURRENT_SOURCE_DIR}/src/iniparser.h - ALL - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/doc) + ALL) install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html DESTINATION ${CMAKE_INSTALL_DOCDIR}) endif() diff --git a/INSTALL b/INSTALL index a5b05d0..5e7bf99 100644 --- a/INSTALL +++ b/INSTALL @@ -1,15 +1 @@ - -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 +See [Building project](README.md#building-project) diff --git a/README.md b/README.md index 06d7f87..afe0546 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ [![pipeline status](https://gitlab.com/iniparser/iniparser/badges/main/pipeline.svg)](https://gitlab.com/iniparser/iniparser/-/commits/main) [![latest release](https://gitlab.com/iniparser/iniparser/-/badges/release.svg)](https://gitlab.com/iniparser/iniparser/-/releases) -# Iniparser 4 # +# iniParser 4 # Changes in May 2024: We moved to [iniparser/iniparser](https://gitlab.com/iniparser/iniparser)! @@ -24,7 +24,7 @@ library alive! Many thanks to @touilleman for his exceptional contributions and efforts for maintaining this project for a decade. Manu, you rock! -## I - Overview +## Overview This modules offers parsing of ini files from C. @@ -35,7 +35,13 @@ Key features: - Fully re-entrant : easy to make it thread-safe (just surround library calls by mutex) -## II - Building project +## MinGW + +In the instructions below, replace `make all` by `ninja` if you are using +MinGW as build system. Of course you will need to install +[ninja](https://ninja-build.org/) to use it. + +## Building project This project uses CMake as build system. Use these command at the root or the project to get the static (i.e. `libiniparser.a`) and shared (i.e. @@ -50,17 +56,24 @@ make all There are some CMake option which are `OFF` by default: -- `BUILD_TESTS` +- `BUILD_TESTING` - `BUILD_EXAMPLES` +- `BUILD_DOCS` + +These CMake options are `ON` by default: + +- `BUILD_SHARED_LIBS` +- `BUILD_STATIC_LIBS` From within build directory execute `ccmake ..` to see all. -## III - Tests + +## Tests ``` mkdir build cd build -cmake -DBUILD_TESTS .. +cmake -DBUILD_TESTING .. make all ``` @@ -68,7 +81,29 @@ While still in the build project you can run the tests by calling `ctest`. Test output can be found in build directory under `Testing/Temporary/LastTest.log`. -## IV - Examples +Each time `cmake` is executed in an empty build directory it will try to clone +the unit test framework [Unity](https://www.throwtheswitch.org/unity). +To avoid unnecessary downloads you may place a copy outside your build +directory and point cmake to it. + +To do so first clone Unity in a project of your choice: + +``` +git clone https://github.com/throwtheswitch/unity.git +``` +Now change into your build directory and pass `FETCHCONTENT_SOURCE_DIR_UNITY` +to `cmake` (adjust the path to unity to your local setup): +``` +mkdir build +cd build +cmake -DBUILD_TESTING -DFETCHCONTENT_SOURCE_DIR_UNITY=../../3rparty/unity .. +make all +``` +Now CMake will try to use the sources in this directory and fall back to +cloning if it cannot find them there. + + +## Examples To build the examples: @@ -85,22 +120,35 @@ From the build directory run the examples with: - `./iniwrite` - `./parse ../example/twisted.ini` -## V - Documentation -Documentation is build by default and can be found in build directory under -`html`. +## Documentation + +The library is completely documented in its header file. + +To build the documentation [doxygen](https://www.doxygen.org/index.html) has be +installed. Documentation can build and be found in build directory under +`html`: + +``` +mkdir build +cd build +cmake -DBUILD_DOCS .. +make all +``` Open the file `html/index.html` with any HTML-capable browser. Or see the [complete documentation](https://iniparser.gitlab.io/iniparser/) in online. -## VI - License + +## License This software is released under MIT License. See [LICENSE](LICENSE) for more details -## VII - Versions + +## Versions [![latest release](https://gitlab.com/iniparser/iniparser/-/badges/release.svg)](https://gitlab.com/iniparser/iniparser/-/releases) @@ -108,9 +156,183 @@ See [LICENSE](LICENSE) for more details - Version 4.0 introduced breaking changes in the api. - Older versions 3.1 and 3.2 with the legacy api are available as tags. -## VIII - FAQ + +## FAQ See [FAQ-en.md](FAQ-en.md) in this directory for answers to Frequently Asked Questions. 还有简化中国翻译在[FAQ-zhcn.md](FAQ-zhcn.md). + + +## Details + +### 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 C and +should compile on most platforms without difficulty. + + +### 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: + +```ini +[Section Name] +``` + +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: + +```ini +Key = value ; comment +``` + +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: + +```ini +Hello = "this is a long string value" ; comment +Hello = this is a long string value ; comment +``` + +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 (`\`). + +```ini +Multiple = Line 1 \ +Line 2 \ +Line 3 \ +Line 4 ; comment +``` + +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) + + +### Using the library + +To use the library in your programs, add the following line on top of your +module: + +```c +#include "iniparser.h" +``` + +And link your program with the iniParser library by adding `-liniparser` to the +compile line. + +See the file example/example.c for an example. + +iniParser is an C library. If you want to compile it with a C++ compiler have +to include the extern "C" hack to include the header: + +```c +#ifdef __cplusplus +extern "C" +{ +#endif +#include "iniparser.h" +#ifdef __cplusplus +} +#endif +``` +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: + +```c +[Section] +Keyword = value ; comment +``` + +is converted to the following key pair: + +```c +("section:keyword", "value") +``` + +This means that if you want to retrieve the value that was stored in the +section called `Pizza`, in the keyword `Cheese`, you would make a request to +the dictionary for `"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: + +```c +iniparser_set(ini, "section", NULL); +iniparser_set(ini, "section:key1", NULL); +iniparser_set(ini, "section:key2", NULL); +``` + + +### 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. + + +### 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. diff --git a/doc/iniparser.txt b/doc/iniparser.txt deleted file mode 100644 index 2975e9d..0000000 --- a/doc/iniparser.txt +++ /dev/null @@ -1,201 +0,0 @@ - -/** - - @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 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 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 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. - -*/ diff --git a/src/iniparser.c b/src/iniparser.c index 4cffb96..3e8a962 100644 --- a/src/iniparser.c +++ b/src/iniparser.c @@ -99,9 +99,9 @@ static unsigned strstrip(char * s) if (s==NULL) return 0; last = s + strlen(s); - while (isspace((int)*s) && *s) s++; + while (isspace((unsigned char)*s) && *s) s++; while (last > s) { - if (!isspace((int)*(last-1))) + if (!isspace((unsigned char)*(last-1))) break ; last -- ; } @@ -283,7 +283,7 @@ void iniparser_dump_ini(const dictionary * d, FILE * f) size_t i ; size_t nsec ; const char * secname ; - char escaped[ASCIILINESZ+1] = ""; + char escaped[(ASCIILINESZ * 2) + 2] = ""; if (d==NULL || f==NULL) return ; @@ -323,7 +323,7 @@ void iniparser_dumpsection_ini(const dictionary * d, const char * s, FILE * f) size_t j ; char keym[ASCIILINESZ+1]; int seclen ; - char escaped[ASCIILINESZ+1] = ""; + char escaped[(ASCIILINESZ * 2) + 2] = ""; if (d==NULL || f==NULL) return ; if (! iniparser_find_entry(d, s)) return ; @@ -643,8 +643,17 @@ int iniparser_find_entry(const dictionary * ini, const char * entry) /*--------------------------------------------------------------------------*/ int iniparser_set(dictionary * ini, const char * entry, const char * val) { - char tmp_str[ASCIILINESZ+1]; - return dictionary_set(ini, strlwc(entry, tmp_str, sizeof(tmp_str)), val) ; + char tmp_key[ASCIILINESZ+1] = {0}; + char tmp_val[ASCIILINESZ+1] = {0}; + size_t len; + + if(val) { + len = strlen(val); + len = len > ASCIILINESZ ? ASCIILINESZ : len; + memcpy(tmp_val, val, len) ; + val = tmp_val; + } + return dictionary_set(ini, strlwc(entry, tmp_key, sizeof(tmp_key)), val); } /*-------------------------------------------------------------------------*/ @@ -846,7 +855,7 @@ dictionary * iniparser_load_file(FILE * in, const char * ininame) } /* Get rid of \n and spaces at end of line */ while ((len>=0) && - ((line[len]=='\n') || (isspace(line[len])))) { + ((line[len]=='\n') || (isspace((unsigned char)line[len])))) { line[len]=0 ; len-- ; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b28d151..8e8505f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -55,16 +55,10 @@ function(create_test_runner) ${CMAKE_CURRENT_SOURCE_DIR}/test_${TEST_RUNNER_NAME}.c test_${TEST_RUNNER_NAME}_runner.c DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/test_${TEST_RUNNER_NAME}.c - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - BYPRODUCTS test_${TEST_RUNNER_NAME}_runner.c) + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) add_executable(test_${TEST_RUNNER_NAME} test_${TEST_RUNNER_NAME}.c test_${TEST_RUNNER_NAME}_runner.c) - # Prevent MSVC from creating Debug or Release subdirectories for test - # executables - set_target_properties( - test_${TEST_RUNNER_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY - ${CMAKE_CURRENT_BINARY_DIR}/$<0:>) foreach(TARGET_TYPE ${TARGET_TYPES}) # if BUILD_STATIC_LIBS=ON shared takes precedence target_link_libraries( @@ -82,6 +76,12 @@ add_test( NAME test_${PROJECT_NAME} COMMAND test_${PROJECT_NAME} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) +add_custom_command( + TARGET test_${PROJECT_NAME} + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy -t $ + $ + COMMAND_EXPAND_LISTS) create_test_runner(NAME dictionary) message(STATUS "Adding test test_dictionary") @@ -89,3 +89,9 @@ add_test( NAME test_dictionary COMMAND test_dictionary WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) +add_custom_command( + TARGET test_dictionary + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy -t $ + $ + COMMAND_EXPAND_LISTS) diff --git a/test/test_iniparser.c b/test/test_iniparser.c index 63a519e..a124374 100644 --- a/test/test_iniparser.c +++ b/test/test_iniparser.c @@ -993,6 +993,8 @@ void test_iniparser_dump(void) void test_iniparser_dump_ini(void) { const char *str; + char val[4096] = {}; + int ret; /*loading old.ini*/ dic = iniparser_load(OLD_INI_PATH); @@ -1021,6 +1023,20 @@ void test_iniparser_dump_ini(void) TEST_ASSERT_EQUAL_STRING("321abc", str); iniparser_freedict(dic); dic = NULL; + /*test extra large values*/ + dic = dictionary_new(0); + TEST_ASSERT_NOT_NULL(dic); + memset(val, '\\', sizeof(val)-1); + ret = iniparser_set(dic, ":key1", val); + TEST_ASSERT_GREATER_OR_EQUAL_MESSAGE(0, ret, "cannot set :key1" + " in: " TMP_INI_PATH); + ini = fopen(TMP_INI_PATH, "wt"); + TEST_ASSERT_NOT_NULL_MESSAGE(ini, "cannot open " TMP_INI_PATH); + iniparser_dump_ini(dic, ini); + fclose(ini); + ini = NULL; + iniparser_freedict(dic); + dic = NULL; } void test_iniparser_dumpsection_ini(void)