From 3d971541e3ad6334feb59652f500dd348bf01f6d Mon Sep 17 00:00:00 2001 From: abin Date: Sat, 28 Feb 2026 23:55:50 +0800 Subject: [PATCH 01/10] build: add `LANGUAGES CXX` --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 72ec0ba..0ec64fa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.15) -project(inifile-cpp) +project(inifile-cpp LANGUAGES CXX) include(CTest) From 607ad14c7a4d6f1b6c81c45aded645d45755d2c3 Mon Sep 17 00:00:00 2001 From: abin Date: Sat, 28 Feb 2026 23:57:56 +0800 Subject: [PATCH 02/10] build: Optimize C++ standard settings --- CMakeLists.txt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ec64fa..2aeaa11 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,14 +10,10 @@ project(inifile-cpp LANGUAGES CXX) include(CTest) -set(INICPP_CXX_STANDARD "11" CACHE STRING "C++ standard to use when building tests & examples.") option(GENERATE_COVERAGE "Enable generating code coverage" OFF) option(BUILD_TESTS "Enable building unit tests" OFF) option(BUILD_EXAMPLES "Enable building example applications" OFF) -set(CMAKE_CXX_STANDARD ${INICPP_CXX_STANDARD}) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - if(CMAKE_COMPILER_IS_GNUCXX) add_compile_options(-Wall -Wextra) endif(CMAKE_COMPILER_IS_GNUCXX) @@ -34,6 +30,7 @@ target_include_directories(inicpp INTERFACE $ $) add_library(inicpp::inicpp ALIAS inicpp) +target_compile_features(inicpp INTERFACE cxx_std_11) install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/inicpp.h TYPE INCLUDE) if(GENERATE_COVERAGE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") From 773c91bbc3734b579a4aaae5c58cd42405fdc587 Mon Sep 17 00:00:00 2001 From: abin Date: Sun, 1 Mar 2026 00:03:56 +0800 Subject: [PATCH 03/10] build: Optimize compiler warnings --- CMakeLists.txt | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2aeaa11..42ce624 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,15 +14,6 @@ option(GENERATE_COVERAGE "Enable generating code coverage" OFF) option(BUILD_TESTS "Enable building unit tests" OFF) option(BUILD_EXAMPLES "Enable building example applications" OFF) -if(CMAKE_COMPILER_IS_GNUCXX) - add_compile_options(-Wall -Wextra) -endif(CMAKE_COMPILER_IS_GNUCXX) - -if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC") - add_compile_options(/WX /wd4530) -endif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") - - add_subdirectory(dep) add_library(inicpp INTERFACE) @@ -31,6 +22,12 @@ target_include_directories(inicpp INTERFACE $) add_library(inicpp::inicpp ALIAS inicpp) target_compile_features(inicpp INTERFACE cxx_std_11) + +target_compile_options(inicpp INTERFACE + $<$:-Wall;-Wextra> + $<$:/WX;/wd4530> +) + install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/inicpp.h TYPE INCLUDE) if(GENERATE_COVERAGE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") From 5ca9f615cd679aa4959164b9ee86db3f91ccdb88 Mon Sep 17 00:00:00 2001 From: abin Date: Sun, 1 Mar 2026 00:08:06 +0800 Subject: [PATCH 04/10] build: Optimize BUILD_TESTS --- CMakeLists.txt | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 42ce624..c0feae0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,14 +8,10 @@ cmake_minimum_required(VERSION 3.15) project(inifile-cpp LANGUAGES CXX) -include(CTest) - option(GENERATE_COVERAGE "Enable generating code coverage" OFF) option(BUILD_TESTS "Enable building unit tests" OFF) option(BUILD_EXAMPLES "Enable building example applications" OFF) -add_subdirectory(dep) - add_library(inicpp INTERFACE) target_include_directories(inicpp INTERFACE $ @@ -36,10 +32,12 @@ if(GENERATE_COVERAGE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") target_link_options(inicpp INTERFACE --coverage) endif(GENERATE_COVERAGE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") -if(${BUILD_TESTS}) +if(BUILD_TESTS) + include(CTest) + add_subdirectory(dep) add_subdirectory(test) -endif(${BUILD_TESTS}) +endif() -if(${BUILD_EXAMPLES}) +if(BUILD_EXAMPLES) add_subdirectory(examples) -endif(${BUILD_EXAMPLES}) +endif() From b8c50739484929a37f1fb6a5a0fccd35c554178d Mon Sep 17 00:00:00 2001 From: abin Date: Sun, 1 Mar 2026 00:18:01 +0800 Subject: [PATCH 05/10] build: Optimize option --- CMakeLists.txt | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c0feae0..ae57b10 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,23 +7,32 @@ cmake_minimum_required(VERSION 3.15) project(inifile-cpp LANGUAGES CXX) - -option(GENERATE_COVERAGE "Enable generating code coverage" OFF) -option(BUILD_TESTS "Enable building unit tests" OFF) -option(BUILD_EXAMPLES "Enable building example applications" OFF) +include(GNUInstallDirs) add_library(inicpp INTERFACE) -target_include_directories(inicpp INTERFACE - $ - $) add_library(inicpp::inicpp ALIAS inicpp) target_compile_features(inicpp INTERFACE cxx_std_11) +target_include_directories(inicpp INTERFACE + $ + $) target_compile_options(inicpp INTERFACE $<$:-Wall;-Wextra> $<$:/WX;/wd4530> ) +if(NOT DEFINED INIFILE_CPP_MASTER_PROJECT) + if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) + set(INIFILE_CPP_MASTER_PROJECT ON) + else() + set(INIFILE_CPP_MASTER_PROJECT OFF) + endif() +endif() + +option(GENERATE_COVERAGE "Enable generating code coverage" ${INIFILE_CPP_MASTER_PROJECT}) +option(BUILD_TESTS "Enable building unit tests" ${INIFILE_CPP_MASTER_PROJECT}) +option(BUILD_EXAMPLES "Enable building example applications" ${INIFILE_CPP_MASTER_PROJECT}) + install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/inicpp.h TYPE INCLUDE) if(GENERATE_COVERAGE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") @@ -33,11 +42,13 @@ if(GENERATE_COVERAGE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") endif(GENERATE_COVERAGE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") if(BUILD_TESTS) + message(STATUS "[inicpp] Building unit tests") include(CTest) add_subdirectory(dep) add_subdirectory(test) endif() if(BUILD_EXAMPLES) + message(STATUS "[inicpp] Building examples") add_subdirectory(examples) endif() From 519066725211364d885a1407033971d953de8fe8 Mon Sep 17 00:00:00 2001 From: abin Date: Wed, 4 Mar 2026 00:06:07 +0800 Subject: [PATCH 06/10] chore: update `.gitignore` --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 13ac9b8..460d176 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ Testing/ .cproject .settings .vscode +.cache From 5ead0b711530b688a9f31e6d981f9d64aa47b2d5 Mon Sep 17 00:00:00 2001 From: abin Date: Wed, 4 Mar 2026 00:20:06 +0800 Subject: [PATCH 07/10] build: Avoid sending warnings to users --- CMakeLists.txt | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ae57b10..d44e94b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,11 +16,6 @@ target_include_directories(inicpp INTERFACE $ $) -target_compile_options(inicpp INTERFACE - $<$:-Wall;-Wextra> - $<$:/WX;/wd4530> -) - if(NOT DEFINED INIFILE_CPP_MASTER_PROJECT) if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) set(INIFILE_CPP_MASTER_PROJECT ON) @@ -29,17 +24,28 @@ if(NOT DEFINED INIFILE_CPP_MASTER_PROJECT) endif() endif() +if(INIFILE_CPP_MASTER_PROJECT) + target_compile_options(inicpp INTERFACE + $<$:-Wall;-Wextra> + $<$:/W4> + ) +endif() + option(GENERATE_COVERAGE "Enable generating code coverage" ${INIFILE_CPP_MASTER_PROJECT}) option(BUILD_TESTS "Enable building unit tests" ${INIFILE_CPP_MASTER_PROJECT}) option(BUILD_EXAMPLES "Enable building example applications" ${INIFILE_CPP_MASTER_PROJECT}) -install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/inicpp.h TYPE INCLUDE) +install(DIRECTORY include/ + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + FILES_MATCHING + PATTERN "*.h" +) if(GENERATE_COVERAGE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") # Add required flags (GCC & LLVM/Clang) target_compile_options(inicpp INTERFACE -O0 -g --coverage) target_link_options(inicpp INTERFACE --coverage) -endif(GENERATE_COVERAGE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") +endif() if(BUILD_TESTS) message(STATUS "[inicpp] Building unit tests") From 27e0df2bb5619b8871a6c0dd696544a4acce3464 Mon Sep 17 00:00:00 2001 From: abin Date: Wed, 4 Mar 2026 00:30:34 +0800 Subject: [PATCH 08/10] build: Optimize CMakeLists.txt --- CMakeLists.txt | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d44e94b..71a40be 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,9 +31,9 @@ if(INIFILE_CPP_MASTER_PROJECT) ) endif() -option(GENERATE_COVERAGE "Enable generating code coverage" ${INIFILE_CPP_MASTER_PROJECT}) -option(BUILD_TESTS "Enable building unit tests" ${INIFILE_CPP_MASTER_PROJECT}) -option(BUILD_EXAMPLES "Enable building example applications" ${INIFILE_CPP_MASTER_PROJECT}) +option(INIFILE_CPP_GENERATE_COVERAGE "Enable generating code coverage" ${INIFILE_CPP_MASTER_PROJECT}) +option(INIFILE_CPP_BUILD_TESTS "Enable building unit tests" ${INIFILE_CPP_MASTER_PROJECT}) +option(INIFILE_CPP_BUILD_EXAMPLES "Enable building example applications" ${INIFILE_CPP_MASTER_PROJECT}) install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} @@ -41,20 +41,21 @@ install(DIRECTORY include/ PATTERN "*.h" ) -if(GENERATE_COVERAGE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") +if(INIFILE_CPP_GENERATE_COVERAGE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") # Add required flags (GCC & LLVM/Clang) + message(STATUS "[inicpp] Enabling code coverage generation") target_compile_options(inicpp INTERFACE -O0 -g --coverage) target_link_options(inicpp INTERFACE --coverage) endif() -if(BUILD_TESTS) +if(INIFILE_CPP_BUILD_TESTS) message(STATUS "[inicpp] Building unit tests") include(CTest) add_subdirectory(dep) add_subdirectory(test) endif() -if(BUILD_EXAMPLES) +if(INIFILE_CPP_BUILD_EXAMPLES) message(STATUS "[inicpp] Building examples") add_subdirectory(examples) endif() From 5d2534268493bd518f91d69b29aad9ede101d485 Mon Sep 17 00:00:00 2001 From: abin Date: Sun, 8 Mar 2026 12:14:03 +0800 Subject: [PATCH 09/10] test: Tests hex numeric parsing --- test/test_inifile.cpp | 47 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/test/test_inifile.cpp b/test/test_inifile.cpp index f5b2ec6..b195ed4 100644 --- a/test/test_inifile.cpp +++ b/test/test_inifile.cpp @@ -903,3 +903,50 @@ TEST_CASE("parse section with duplicate field and overwriteDuplicateFields_ set inif.allowOverwriteDuplicateFields(false); REQUIRE_THROWS(inif.decode("[Foo]\nbar=hello\nbar=world")); } + +// Tests numeric parsing: hex (0x/0X, negative), decimal (with/without leading zeros), unsigned, and invalid conversions +TEST_CASE("numeric parsing", "IniFile") +{ + std::istringstream ss("[Foo]\n" + "hex=0x10\n" + "hex_upper=0X2A\n" + "hex_neg=-0x10\n" + "dec=42\n" + "dec_leading_zero=010\n" + "dec_neg=-15\n"); + ini::IniFile inif(ss); + + SECTION("hex numbers") + { + REQUIRE(inif["Foo"]["hex"].as() == 16); + REQUIRE(inif["Foo"]["hex_upper"].as() == 42); + REQUIRE(inif["Foo"]["hex_neg"].as() == -16); + } + + SECTION("decimal numbers") + { + REQUIRE(inif["Foo"]["dec"].as() == 42); + REQUIRE(inif["Foo"]["dec_leading_zero"].as() == 10); + REQUIRE(inif["Foo"]["dec_neg"].as() == -15); + } +} + +TEST_CASE("parse unsigned numbers", "IniFile") +{ + std::istringstream ss("[Foo]\n" + "uhex=0xFF\n" + "udec=100\n"); + ini::IniFile inif(ss); + + REQUIRE(inif["Foo"]["uhex"].as() == 255); + REQUIRE(inif["Foo"]["udec"].as() == 100); +} + +TEST_CASE("invalid numeric conversion", "IniFile") +{ + std::istringstream ss("[Foo]\n" + "bad=xyz\n"); + ini::IniFile inif(ss); + + REQUIRE_THROWS_AS(inif["Foo"]["bad"].as(), std::invalid_argument); +} \ No newline at end of file From 48612686b6fbb9bd50f8f9a5c55317b59822bf7b Mon Sep 17 00:00:00 2001 From: abin Date: Sun, 8 Mar 2026 12:47:42 +0800 Subject: [PATCH 10/10] test: add `setEscapeChar` test case --- test/test_inifile.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/test/test_inifile.cpp b/test/test_inifile.cpp index b195ed4..afa4879 100644 --- a/test/test_inifile.cpp +++ b/test/test_inifile.cpp @@ -949,4 +949,30 @@ TEST_CASE("invalid numeric conversion", "IniFile") ini::IniFile inif(ss); REQUIRE_THROWS_AS(inif["Foo"]["bad"].as(), std::invalid_argument); +} + +TEST_CASE("custom escape char", "IniFile") +{ + std::istringstream ss("[Foo]\nbar=hello !#world"); + ini::IniFile inif; + + inif.setEscapeChar('!'); + inif.decode(ss); + + REQUIRE(inif["Foo"]["bar"].as() == "hello #world"); +} + +TEST_CASE("escape char affects comment escaping", "IniFile") +{ + std::istringstream ss("[Foo]\nkey=val\\#notacomment\n"); + ini::IniFile inif(ss); + + inif.setEscapeChar('\\'); + std::string encoded = inif.encode(); + REQUIRE(encoded.find("\\#notacomment") != std::string::npos); + + inif.setEscapeChar('$'); + inif["Foo"]["key"] = "value$#comment"; + encoded = inif.encode(); + REQUIRE(encoded.find("$#comment") != std::string::npos); } \ No newline at end of file