{"id":23802928,"url":"https://github.com/semaicze/inicpp","last_synced_at":"2025-09-06T15:33:29.901Z","repository":{"id":10391573,"uuid":"54846992","full_name":"SemaiCZE/inicpp","owner":"SemaiCZE","description":"C++ parser of INI files with schema validation.","archived":false,"fork":false,"pushed_at":"2024-04-23T19:35:29.000Z","size":776,"stargazers_count":56,"open_issues_count":0,"forks_count":13,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-04-24T20:00:49.488Z","etag":null,"topics":["cpp","ini","inicpp","modern","parser","schema","validation"],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SemaiCZE.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2016-03-27T20:35:52.000Z","updated_at":"2024-04-23T19:35:32.000Z","dependencies_parsed_at":"2024-04-23T18:26:01.276Z","dependency_job_id":"25222c2b-c066-423f-ba18-ef0100527c47","html_url":"https://github.com/SemaiCZE/inicpp","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SemaiCZE%2Finicpp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SemaiCZE%2Finicpp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SemaiCZE%2Finicpp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SemaiCZE%2Finicpp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SemaiCZE","download_url":"https://codeload.github.com/SemaiCZE/inicpp/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":232132363,"owners_count":18477130,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cpp","ini","inicpp","modern","parser","schema","validation"],"created_at":"2025-01-01T22:28:28.330Z","updated_at":"2025-01-01T22:28:30.026Z","avatar_url":"https://github.com/SemaiCZE.png","language":"C++","readme":"# inicpp\n\n[![Linux/MacOS Build](https://github.com/SemaiCZE/inicpp/actions/workflows/build.yml/badge.svg)](https://github.com/SemaiCZE/inicpp/actions/workflows/build.yml)\n[![Windows Build](https://github.com/SemaiCZE/inicpp/actions/workflows/windows-build.yml/badge.svg)](https://github.com/SemaiCZE/inicpp/actions/workflows/windows-build.yml)\n[![License](https://img.shields.io/badge/license-mit-blue.svg)](http://badges.mit-license.org)\n[![Wiki](https://img.shields.io/badge/docs-wiki-orange.svg)](https://github.com/SemaiCZE/inicpp/wiki)\n[![Docs](https://img.shields.io/badge/docs-latest-brightgreen.svg)](http://semaicze.github.io/inicpp)\n\nC++ parser of INI files with schema validation.\n\n## About\n\nThis project started as semestral work for _Recommended Programming Practices_ class at **MFF UK**, Prague, in 2016. After deadline the project was published at _GitHub_ under MIT license.\n\nGreat emphasis was put on qualities of object oriented design and clean implementation with modern C++ features.\n\nOriginally written by:\n\n- Petr Stefan (_[SemaiCZE](https://github.com/SemaiCZE/)_)\n- Martin Polanka (_[Neloop](https://github.com/Neloop/)_)\n\n## Versions\n\n`Master` branch contains source code using `std::variant` feature and it requires compiler with C++17 support. Older version with C++14 support is in `cpp14` branch and is still supported by us.\n\n## Build instructions\n\n**Inicpp** is build as shared and static library using `cmake`. There are two options to control which libraries are built, by default both are set to ON. Basic syntax is:\n\n```\ncmake [-G generator] [-DBUILD_STATIC=ON|OFF] [-DBUILD_SHARED=ON|OFF] source_dir\n```\n\nAlso C++ compiler with at least C++17 support is required.\n\n### Linux\n\nTo build the library run following commands from root of source code directory:\n\n```.sh\n$ mkdir -p build\n$ cd build\n$ cmake ..\n$ make\n```\n\nTo build and run unit tests using Google Test framework run additional commands:\n\n```.sh\n$ make -f tests/Makefile\n$ ./tests/run_tests\n```\n\n**Note:** For building tests you must have all the sources including git submodules. This could be done using `git clone --recursive https://github.com/SemaiCZE/inicpp.git` command when clonning or `git submodule update --init` when you already have the sources.\n\n### Windows\n\nFor Windows there are two ways of building `inicpp`. For both ways `cmake` has to be installed on machine.\n\nUsing **MS Visual Studio**:\n- As stated `Visual Studio 2017` (or later) should be installed on the machine.\n- If dependencies are successfully fulfilled then run `cmake` in root directory of repository using:\n```\n\u003e cmake -G \"Visual Studio 15 2017\"\n```\n- This command will generate solution files\n- Open solution file `inicpp.sln` using `Visual Studio`\n- Build `ALL_BUILD` project which will hopefully successfully build whole library\n- Distribute static or shared binaries which can be found in target build directories to your program/library\n\nUsing **MS Visual C++**:\n- Besides `Visual C++ 2017` (or later) `nmake` compilation tool is needed (both should be part of `Windows SDK`)\n- Run `cmake` in root directory of repository using:\n```\n\u003e cmake -G \"NMake Makefiles\"\n```\n- This will generate file `Makefile` which can be interpreted with `nmake`\n- Now enter following easy command:\n```\n\u003e nmake\n```\n- After this compiled library should appear in working directory\n- Depending on your needs use `inicpp` or `inicpp_static` in your library or program\n\n## Examples\n\nSome examples are located in `examples` directory. Compiling them requires additional steps after standard library compilation, for example on Linux (note that you must be in `build` directory):\n\n```.sh\n$ make -f examples/Makefile\n```\n\nCompiled examples can be run as follows:\n\n```.sh\n$ ./examples/schema_validation/inicpp_schema\n$ ./examples/basic/inicpp_basic\n```\n\nExpected outputs are also provided with examples sources.\n\n\n### Basic usage without schema\n\nSlightly modified version of basic example.\n\n```.cpp\nstd::cout \u003c\u003c \"Load and parse config from string\" \u003c\u003c std::endl;\nconfig example_conf = parser::load(get_config());\n\nstd::cout \u003c\u003c \"Iterate through whole config and print it\" \u003c\u003c std::endl;\nfor(auto \u0026sect : example_conf) {\n\tstd::cout \u003c\u003c \"  Section: '\" \u003c\u003c sect.get_name() \u003c\u003c \"'\" \u003c\u003c std::endl;\n\t// Iterate through options in a section\n\tfor(auto \u0026opt : sect) {\n\t\tstd::cout \u003c\u003c \"    Option: '\" \u003c\u003c opt.get_name() \u003c\u003c \"' with value(s): \";\n\t\tif (!opt.is_list()) {\n\t\t\tstd::cout \u003c\u003c \"'\" \u003c\u003c opt.get\u003cstring_ini_t\u003e() \u003c\u003c \"'\";\n\t\t} else {\n\t\t\tfor (auto \u0026list_item : opt.get_list\u003cstring_ini_t\u003e())\n\t\t\t\tstd::cout \u003c\u003c \"'\" \u003c\u003c list_item \u003c\u003c \"' \";\n\t\t}\n\t}\n}\n\nstd::cout \u003c\u003c \"Get number as signed_ini_t type\" \u003c\u003c std::endl;\ntry {\n\tsigned_ini_t number = example_conf[\"Numbers\"][\"num\"].get\u003csigned_ini_t\u003e();\n\tstd::cout \u003c\u003c \"  \" \u003c\u003c number \u003c\u003c std::endl;\n} catch (bad_cast_exception) {\n\tstd::cout \u003c\u003c \"  Item 'num' in 'Numbers' section cannot be casted to signed_ini_t type\" \u003c\u003c std::endl;\n}\n\nstd::cout \u003c\u003c \"Change some values - could be properly typed\" \u003c\u003c std::endl;\n// Make reference to the section\nsection \u0026number_sect = example_conf[\"Numbers\"];\n// Change some values\nnumber_sect[\"num\"].set\u003csigned_ini_t\u003e(42222);\nsigned_ini_t new_num = number_sect[\"num\"].get\u003csigned_ini_t\u003e();\nstd::cout \u003c\u003c \"  Option 'num' in 'Numbers' section is '\" \u003c\u003c new_num \u003c\u003c \"'\" \u003c\u003c std::endl;\n// Following two lines are equivalent\nnumber_sect[\"num_oct\"].set\u003cstring_ini_t\u003e(\"0756\");\nnumber_sect[\"num_oct\"] = \"0756\"s;\nstd::cout \u003c\u003c \"  set method and assingment operator on option are equivalent\" \u003c\u003c std::endl;\n\nstd::cout \u003c\u003c \"Change single value to list and vice versa\" \u003c\u003c std::endl;\noption \u0026num_opt = number_sect[\"num\"];\nnum_opt.add_to_list\u003csigned_ini_t\u003e(99);\nif (num_opt.is_list()) {\n\tstd::cout \u003c\u003c \"  'num' option in 'Numbers' section is list\" \u003c\u003c std::endl;\n} else {\n\tstd::cout \u003c\u003c \"  'num' option in 'Numbers' section is single value\" \u003c\u003c std::endl;\n}\n// Remove item from the list (specifying position)\nnum_opt.remove_from_list_pos(0); // remove first item\nstd::cout \u003c\u003c \"  first item from 'num' option list removed\" \u003c\u003c std::endl;\nif (num_opt.is_list()) {\n\tstd::cout \u003c\u003c \"  'num' option in 'Numbers' section is list\" \u003c\u003c std::endl;\n} else {\n\tstd::cout \u003c\u003c \"  'num' option in 'Numbers' section is single value\" \u003c\u003c std::endl;\n}\nstd::cout \u003c\u003c \"  'num' option value is '\" \u003c\u003c num_opt.get\u003csigned_ini_t\u003e() \u003c\u003c \"'\" \u003c\u003c std::endl;\n\nstd::cout \u003c\u003c \"Save changes to ostream and print the result\" \u003c\u003c std::endl;\nstd::ostringstream ofs;\nofs \u003c\u003c example_conf;\nstd::cout \u003c\u003c ofs.str();\n```\n\nWithout schema all items are treated as string type, but runtime conversion could be done to one of supported types if possible.\n\n### Schema validation support\n\nSchema validation can bring you ability to make sure, that a config file contain what you expect with type safety. In addition, this implies better performance on heavy reading of validated configuration. Slightly modified version of schema validation example.\n\n```.cpp\nstd::cout \u003c\u003c \"Create config schema\" \u003c\u003c std::endl;\nschema schm;\n\n// add section 'Section 1'\nsection_schema_params section_1_params;\nsection_1_params.name = \"Section 1\";\nsection_1_params.comment = \"comment\";\nsection_1_params.requirement = item_requirement::optional;\nschm.add_section(section_1_params);\n\n// add options to 'Section 1'\noption_schema_params\u003csigned_ini_t\u003e option_1_params;\noption_1_params.name = \"Option 1\";\noption_1_params.type = option_item::single;\noption_1_params.requirement = item_requirement::mandatory;\noption_1_params.validator = [](signed_ini_t i){ return i \u003c 0; }; // valid values are only negative ones\noption_1_params.comment = \"Important option\\nshould be negative\";\noption_1_params.default_value = \"-1\";\nschm.add_option(\"Section 1\", option_1_params);\n\noption_schema_params\u003cfloat_ini_t\u003e option_4_params;\noption_4_params.name = \"float1\";\noption_4_params.type = option_item::single;\noption_4_params.requirement = item_requirement::mandatory;\nschm.add_option(\"Section 1\", option_4_params);\n\n\nstd::cout \u003c\u003c \"Load and validate config in relaxed mode\" \u003c\u003c std::endl;\nconfig conf = parser::load(get_config(), schm, schema_mode::relaxed);\n\nstd::cout \u003c\u003c \"Check, if options are properly typed\" \u003c\u003c std::endl;\nstd::cout \u003c\u003c \"  'Option 1' is signed_ini_t type with value '\" \u003c\u003c\n\tconf[\"Section 1\"][\"Option 1\"].get\u003csigned_ini_t\u003e() \u003c\u003c \"'\" \u003c\u003c std::endl;\nstd::cout \u003c\u003c \"  'float1' option has value '\" \u003c\u003c conf[\"Section 1\"][\"float1\"].get\u003cfloat_ini_t\u003e() \u003c\u003c\n\tstd::endl;\nstd::cout \u003c\u003c \"  'unknown_option' was left as string with value '\" \u003c\u003c\n\tconf[\"Section 1\"][\"unknown_option\"].get\u003cstring_ini_t\u003e() \u003c\u003c std::endl;\n\nstd::cout \u003c\u003c \"Validation with strict mode fails due to 'unknown_option'\" \u003c\u003c std::endl;\ntry {\n\tparser::load(get_config(), schm, schema_mode::strict);\n} catch (validation_exception) {\n\tstd::cout \u003c\u003c \"  Strict mode validation failed\" \u003c\u003c std::endl;\n}\n\nstd::cout \u003c\u003c \"Write default configuration from schema to stream\" \u003c\u003c std::endl;\nstd::ostringstream str;\nstr \u003c\u003c schm;\nstd::cout \u003c\u003c str.str();\n\nstd::cout \u003c\u003c \"Write current configuration with comments from schema to stream\" \u003c\u003c std::endl;\nstr.str(\"\");\nparser::save(conf, schm, str);\nstd::cout \u003c\u003c str.str();\n```\n\n## Contribution\n\nThis project is open for all contributions, but please respect some rules:\n\n- write clean code\n- use modern C++ features when possible\n- write tests - no need to have 100% coverage, but some tests should be present\n- format code using our style in provided `.clang-format` file - `cmake` target `format` on unix handle this\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsemaicze%2Finicpp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsemaicze%2Finicpp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsemaicze%2Finicpp/lists"}