├── .gitmodules ├── examples ├── CMakeLists.txt ├── basic │ ├── CMakeLists.txt │ ├── output.txt │ └── main.cpp └── schema_validation │ ├── CMakeLists.txt │ ├── output.txt │ └── main.cpp ├── inicpp.pc.in ├── .gitignore ├── include └── inicpp │ ├── inicpp.h │ ├── dll.h │ ├── types.h │ ├── exception.h │ ├── string_utils.h │ ├── schema.h │ ├── option_schema.h │ ├── parser.h │ ├── section_schema.h │ ├── section.h │ ├── option.h │ └── config.h ├── tests ├── CMakeLists.txt ├── exception.cpp ├── config_iterator.cpp ├── section_iterator.cpp ├── section.cpp ├── config.cpp ├── schema.cpp ├── parser.cpp ├── section_schema.cpp ├── option_schema.cpp ├── option.cpp └── string_utils.cpp ├── LICENSE ├── rpm └── inicpp.spec ├── .github └── workflows │ ├── windows-build.yml │ └── build.yml ├── .clang-format ├── src ├── option_schema.cpp ├── string_utils.cpp ├── section.cpp ├── schema.cpp ├── option.cpp ├── config.cpp ├── section_schema.cpp └── parser.cpp ├── CMakeLists.txt └── README.md /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "vendor/googletest"] 2 | path = vendor/googletest 3 | url = https://github.com/google/googletest.git 4 | -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Basic example 2 | add_subdirectory(basic) 3 | 4 | # Schema validation example 5 | add_subdirectory(schema_validation) 6 | -------------------------------------------------------------------------------- /inicpp.pc.in: -------------------------------------------------------------------------------- 1 | includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@ 2 | libdir=@CMAKE_INSTALL_FULL_LIBDIR@ 3 | 4 | Name: inicpp 5 | Description: C++ parser of INI files with schema validation 6 | Version: @inicpp_VERSION@ 7 | Cflags: -I${includedir}/inicpp 8 | Libs: -L${libdir} -linicpp 9 | -------------------------------------------------------------------------------- /examples/basic/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | project(inicpp_basic) 3 | 4 | set(EXEC_NAME ${PROJECT_NAME}) 5 | set(${EXEC_NAME}_SOURCES 6 | main.cpp 7 | ) 8 | 9 | add_executable(${EXEC_NAME} ${${EXEC_NAME}_SOURCES}) 10 | target_link_libraries(${EXEC_NAME} inicpp) 11 | -------------------------------------------------------------------------------- /examples/schema_validation/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | project(inicpp_schema) 3 | 4 | set(EXEC_NAME ${PROJECT_NAME}) 5 | set(${EXEC_NAME}_SOURCES 6 | main.cpp 7 | ) 8 | 9 | add_executable(${EXEC_NAME} ${${EXEC_NAME}_SOURCES}) 10 | target_link_libraries(${EXEC_NAME} inicpp) 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | 30 | build/ 31 | doc/ 32 | .vscode/ 33 | CMakeLists.txt.user* 34 | 35 | -------------------------------------------------------------------------------- /include/inicpp/inicpp.h: -------------------------------------------------------------------------------- 1 | #ifndef INICPP_MAIN_H 2 | #define INICPP_MAIN_H 3 | 4 | /* 5 | * This file is for easy, single-include usage of inicpp 6 | * library from external projekt. 7 | */ 8 | 9 | #include "config.h" 10 | #include "exception.h" 11 | #include "option.h" 12 | #include "option_schema.h" 13 | #include "parser.h" 14 | #include "schema.h" 15 | #include "section.h" 16 | #include "section_schema.h" 17 | #include "types.h" 18 | 19 | #endif // INICPP_MAIN_H 20 | -------------------------------------------------------------------------------- /include/inicpp/dll.h: -------------------------------------------------------------------------------- 1 | #ifndef INICPP_DLL_H 2 | #define INICPP_DLL_H 3 | 4 | 5 | #ifdef INICPP_DLL 6 | #ifdef INICPP_EXPORT 7 | #define INICPP_API __declspec(dllexport) 8 | #else 9 | #define INICPP_API __declspec(dllimport) 10 | #endif 11 | #else 12 | #define INICPP_API 13 | #endif 14 | 15 | 16 | // Disable unwanted and not necessary MSVC++ warnings 17 | #ifdef _MSC_VER 18 | #pragma warning(disable : 4800) 19 | #pragma warning(disable : 4251) 20 | #endif 21 | 22 | 23 | #endif // INICPP_DLL_H 24 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(TESTS_NAME inicpp_tests) 2 | 3 | set(${TESTS_NAME}_SOURCES 4 | option.cpp 5 | section_iterator.cpp 6 | section.cpp 7 | config_iterator.cpp 8 | config.cpp 9 | exception.cpp 10 | parser.cpp 11 | option_schema.cpp 12 | section_schema.cpp 13 | string_utils.cpp 14 | schema.cpp) 15 | 16 | add_executable(${TESTS_NAME} ${${TESTS_NAME}_SOURCES}) 17 | 18 | target_link_libraries(${TESTS_NAME} gtest gtest_main) 19 | target_link_libraries(${TESTS_NAME} gmock gmock_main) 20 | 21 | target_link_libraries(${TESTS_NAME} inicpp) 22 | 23 | if(MSVC) 24 | set_target_properties(${TESTS_NAME} 25 | PROPERTIES 26 | RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" 27 | ) 28 | endif() 29 | 30 | add_test(NAME ${TESTS_NAME} COMMAND $) 31 | set_target_properties(${TESTS_NAME} PROPERTIES FOLDER inicpp_tests) 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Petr Stefan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /rpm/inicpp.spec: -------------------------------------------------------------------------------- 1 | Name: inicpp 2 | Version: 1.1.0 3 | Release: 1%{?dist} 4 | Summary: C++ parser of INI files. 5 | License: MIT 6 | BuildRequires: cmake, make, (gcc-c++ or clang) 7 | URL: https://github.com/SemaiCZE/%{name} 8 | Source0: https://github.com/SemaiCZE/%{name}/archive/v%{version}.tar.gz#/%{name}-%{version}.tar.gz 9 | 10 | %description 11 | Modern C++ library for parsing INI files with schema validation. 12 | 13 | %prep 14 | %autosetup 15 | 16 | %build 17 | mkdir build 18 | cd build 19 | %cmake -DNO_GOOGLE_TEST=ON .. 20 | %make_build 21 | 22 | %install 23 | cd build 24 | %make_install 25 | 26 | %files 27 | %license LICENSE 28 | %{_libdir}/libinicpp.so 29 | 30 | %package devel 31 | Summary: Header and static library for %{name}. 32 | Recommends: %{name} 33 | 34 | %description devel 35 | %{name} is a modern C++ library for parsing INI files with schema validation. This %{name}-devel package contains the headers and optional static library for compiling against the library. 36 | 37 | %files devel 38 | %{_libdir}/libinicpp_static.a 39 | %{_includedir}/inicpp/*.h 40 | 41 | %changelog 42 | * Sun Feb 16 2020 Petr Stefan - 1.1.0-1 43 | - Using std::variant instead of type switch 44 | * Thu Jun 27 2019 Petr Stefan - 1.0.2-1 45 | - GNU install dirs 46 | * Mon Jan 21 2019 Benjamin Kay - 1.0.1-1 47 | - Upstream version bump, cmake build system changes 48 | * Wed Jan 16 2019 Benjamin Kay - 1.0.0-1 49 | - First package of inicpp 50 | -------------------------------------------------------------------------------- /examples/schema_validation/output.txt: -------------------------------------------------------------------------------- 1 | Create config schema 2 | -------------------- 3 | done... 4 | 5 | Load and validate config in relaxed mode 6 | ---------------------------------------- 7 | done... 8 | 9 | Check, if options are properly typed 10 | ------------------------------------ 11 | 'Option 1' is signed_ini_t type with value '-1285' 12 | 'Option 2' is a list of unsigned_ini_t with 3 values 13 | 'Option 3' was added with default value '-42' and correct type 14 | 'float1' option has value '4.12346e+45 15 | 'unknown_option' was left as string with value 'haha' 16 | done... 17 | 18 | Validation with strict mode fails due to 'unknown_option' 19 | --------------------------------------------------------- 20 | Strict mode validation failed 21 | done... 22 | 23 | Write default configuration from schema to stream 24 | ------------------------------------------------- 25 | ;comment 26 | ; 27 | [Section 1] 28 | ;Important option 29 | ;should be negative 30 | ; 31 | ; 32 | Option 1 = -1 33 | ; 34 | ; 35 | Option 2 = 36 | ; 37 | ; 38 | Option 3 = -42 39 | ; 40 | ; 41 | float1 = 42 | done... 43 | 44 | Write current configuration with comments from schema to stream 45 | --------------------------------------------------------------- 46 | ;comment 47 | ; 48 | [Section 1] 49 | ;Important option 50 | ;should be negative 51 | ; 52 | ; 53 | Option 1 = -1285 54 | ; 55 | ; 56 | Option 2 = 5,25,856 57 | ; 58 | ; 59 | float1 = 4.12346e+45 60 | unknown_option = haha 61 | ; 62 | ; 63 | Option 3 = -42 64 | done... 65 | 66 | -------------------------------------------------------------------------------- /tests/exception.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "exception.h" 5 | 6 | // import literals 7 | // we use string operator "" s() - the 's' suffix 8 | // of const char * string makes it std::string. For example: 9 | // auto str = "hello"s; 10 | // str variable is std::string type. This needs C++14 support. 11 | using namespace std::literals; 12 | using namespace inicpp; 13 | 14 | 15 | TEST(exceptions, generic) 16 | { 17 | exception ex; 18 | EXPECT_EQ(ex.what(), "Generic inicpp exception"s); 19 | exception ex_init("text"); 20 | EXPECT_EQ(ex_init.what(), "text"s); 21 | } 22 | 23 | TEST(exceptions, parser) 24 | { 25 | parser_exception ex("message"); 26 | EXPECT_EQ(ex.what(), "message"s); 27 | } 28 | 29 | TEST(exceptions, bad_cast) 30 | { 31 | bad_cast_exception ex_init("text"); 32 | EXPECT_EQ(ex_init.what(), "text"s); 33 | bad_cast_exception ex_from_to("integer", "boolean"); 34 | EXPECT_EQ(ex_from_to.what(), "Bad conversion from: integer to: boolean"s); 35 | } 36 | 37 | TEST(exceptions, not_found) 38 | { 39 | not_found_exception ex(5); 40 | EXPECT_EQ(ex.what(), "Element on index: 5 was not found"s); 41 | not_found_exception ex_name("name"); 42 | EXPECT_EQ(ex_name.what(), "Element: name not found in container"s); 43 | } 44 | 45 | TEST(exceptions, ambiguity) 46 | { 47 | ambiguity_exception ex("elname"); 48 | EXPECT_EQ(ex.what(), "Ambiguous element with name: elname"s); 49 | } 50 | 51 | TEST(exceptions, validation) 52 | { 53 | validation_exception ex("message"); 54 | EXPECT_EQ(ex.what(), "message"s); 55 | } 56 | 57 | TEST(exceptions, invalid_type) 58 | { 59 | invalid_type_exception ex("message"); 60 | EXPECT_EQ(ex.what(), "message"s); 61 | } 62 | 63 | TEST(exceptions, not_implemented) 64 | { 65 | not_implemented_exception ex; 66 | EXPECT_EQ(ex.what(), "Not implemented"s); 67 | } 68 | -------------------------------------------------------------------------------- /tests/config_iterator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "config.h" 5 | #include "section.h" 6 | #include 7 | 8 | using namespace inicpp; 9 | 10 | 11 | TEST(config_iterator, construction_and_copying) 12 | { 13 | config conf; 14 | conf.add_section("sect1"); 15 | conf.add_section("sect2"); 16 | conf.add_section("sect3"); 17 | 18 | // basic constructor 19 | config_iterator
it(conf, 0); 20 | config_iterator
it_beg(conf); 21 | EXPECT_EQ(it, it_beg); 22 | 23 | // copy constructor + assignment 24 | config_iterator
copy_it(it); 25 | config_iterator
copy_it_assignment = it; 26 | EXPECT_EQ(copy_it, copy_it_assignment); 27 | 28 | // move constructor + assignment 29 | config_iterator
move_it(std::move(copy_it)); 30 | config_iterator
move_it_assignment = std::move(copy_it_assignment); 31 | EXPECT_EQ(move_it, move_it_assignment); 32 | } 33 | 34 | TEST(config_iterator, incrementation) 35 | { 36 | config conf; 37 | conf.add_section("sect1"); 38 | conf.add_section("sect2"); 39 | conf.add_section("sect3"); 40 | config_iterator
it(conf, 0); 41 | 42 | EXPECT_EQ(it->get_name(), "sect1"); 43 | EXPECT_EQ((*it).get_name(), "sect1"); 44 | auto postinc_value = it++; 45 | EXPECT_EQ(postinc_value->get_name(), "sect1"); 46 | EXPECT_EQ(it->get_name(), "sect2"); 47 | auto preinc_value = ++it; 48 | EXPECT_EQ(preinc_value->get_name(), "sect3"); 49 | } 50 | 51 | TEST(config_iterator, equality_operator) 52 | { 53 | config conf; 54 | conf.add_section("sect1"); 55 | conf.add_section("sect2"); 56 | conf.add_section("sect3"); 57 | config_iterator
it1(conf, 0); 58 | config_iterator
it2(conf, 0); 59 | EXPECT_EQ(it1, it1); 60 | EXPECT_EQ(it1, it2); 61 | ++it1; 62 | ++it2; 63 | EXPECT_EQ(it1, it2); 64 | ++it2; 65 | EXPECT_NE(it1, it2); 66 | } 67 | -------------------------------------------------------------------------------- /.github/workflows/windows-build.yml: -------------------------------------------------------------------------------- 1 | name: Windows Build 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | tests: 7 | name: Windows ${{ matrix.compiler }} ${{ matrix.build_type }} - ${{ matrix.lib_type }} 8 | runs-on: windows-2022 9 | 10 | strategy: 11 | fail-fast: false 12 | matrix: 13 | compiler: [Clang, MSVC] 14 | build_type: [Debug, Release] 15 | build_shared: [ON, OFF] 16 | include: 17 | - compiler: clang 18 | generator: "Visual Studio 17 2022" 19 | msvc_toolset: ClangCL 20 | - compiler: msvc 21 | generator: "Visual Studio 17 2022" 22 | msvc_toolset: v143 23 | - build_shared: ON 24 | lib_type: Shared 25 | - build_shared: OFF 26 | lib_type: Static 27 | 28 | steps: 29 | - uses: lukka/get-cmake@v3.23.0 30 | - uses: seanmiddleditch/gha-setup-ninja@v3 31 | - uses: ilammy/msvc-dev-cmd@v1 32 | 33 | - name: Checkout 34 | uses: actions/checkout@v2 35 | with: 36 | submodules: true 37 | 38 | - name: Buildtools Version 39 | run: | 40 | if [ "${{ matrix.compiler }}" == "Clang" ]; then 41 | clang-cl.exe --version 42 | else 43 | cl.exe 44 | fi 45 | shell: bash 46 | 47 | - name: Configure 48 | run: | 49 | mkdir build 50 | cd build 51 | cmake .. -G "${{matrix.generator}}" -DINICPP_BUILD_TESTS=ON -DINICPP_BUILD_EXAMPLES=ON -DINICPP_BUILD_SHARED=${{matrix.build_shared}} -T${{matrix.msvc_toolset}} -A x64 52 | shell: bash 53 | 54 | - name: Build 55 | run: | 56 | cmake --build . --config ${{matrix.build_type}} 57 | shell: bash 58 | working-directory: build 59 | 60 | - name: Tests 61 | run: ctest . -C ${{matrix.build_type}} --output-on-failure 62 | shell: bash 63 | working-directory: build 64 | -------------------------------------------------------------------------------- /tests/section_iterator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "option.h" 5 | #include "section.h" 6 | #include 7 | 8 | using namespace inicpp; 9 | using namespace std::literals; 10 | 11 | 12 | TEST(section_iterator, construction_and_copying) 13 | { 14 | section sec("section name"); 15 | sec.add_option("opt1", "value1"); 16 | sec.add_option("opt2", "value2"); 17 | sec.add_option("opt3", "value3"); 18 | 19 | // basic constructor 20 | section_iterator