All Projects → SemaiCZE → Inicpp

SemaiCZE / Inicpp

Licence: mit
C++ parser of INI files with schema validation.

Programming Languages

cpp
1120 projects

Projects that are alternatives of or similar to Inicpp

Strictyaml
Type-safe YAML parser and validator.
Stars: ✭ 836 (+1678.72%)
Mutual labels:  schema, parser, validation
Superstruct
A simple and composable way to validate data in JavaScript (and TypeScript).
Stars: ✭ 5,604 (+11823.4%)
Mutual labels:  schema, validation
Zaml
The Final Form of configuration files
Stars: ✭ 45 (-4.26%)
Mutual labels:  schema, validation
Marshmallow
A lightweight library for converting complex objects to and from simple Python datatypes.
Stars: ✭ 5,857 (+12361.7%)
Mutual labels:  schema, validation
Pyschemes
PySchemes is a library for validating data structures in python
Stars: ✭ 365 (+676.6%)
Mutual labels:  schema, validation
Specs
Technical specifications and guidelines for implementing Frictionless Data.
Stars: ✭ 403 (+757.45%)
Mutual labels:  schema, validation
Meteor Astronomy
Model layer for Meteor
Stars: ✭ 608 (+1193.62%)
Mutual labels:  schema, validation
Swagger Cli
Swagger 2.0 and OpenAPI 3.0 command-line tool
Stars: ✭ 321 (+582.98%)
Mutual labels:  parser, validation
Cafy
☕️ Simple, lightweight, flexible validator generator
Stars: ✭ 22 (-53.19%)
Mutual labels:  schema, validation
Valley
Extensible schema validations and declarative syntax helpers in Python.
Stars: ✭ 25 (-46.81%)
Mutual labels:  schema, validation
Schema
📐 Validating data structures against a given Schema.
Stars: ✭ 359 (+663.83%)
Mutual labels:  schema, validation
Mintype
🍵 minimal composable type abstraction
Stars: ✭ 12 (-74.47%)
Mutual labels:  schema, validation
Skema
🛰 Skema provides a handy & composable way to validate / transform / purify the input data.
Stars: ✭ 359 (+663.83%)
Mutual labels:  schema, validation
Pandera
A light-weight, flexible, and expressive pandas data validation library
Stars: ✭ 506 (+976.6%)
Mutual labels:  schema, validation
Joi
The most powerful data validation library for JS
Stars: ✭ 17,989 (+38174.47%)
Mutual labels:  schema, validation
Goconfig
Package goconfig is a fully functional and comments-support configuration file (.ini) parser.
Stars: ✭ 568 (+1108.51%)
Mutual labels:  ini, parser
Jsonschema
An implementation of the JSON Schema specification for Python
Stars: ✭ 3,474 (+7291.49%)
Mutual labels:  schema, validation
Fix8
Modern open source C++ FIX framework featuring complete schema customisation, high performance and fast development.
Stars: ✭ 319 (+578.72%)
Mutual labels:  schema, modern
Swagger Parser
Swagger 2.0 and OpenAPI 3.0 parser/validator
Stars: ✭ 710 (+1410.64%)
Mutual labels:  parser, validation
Structured Acceptance Test
An open format definition for static analysis tools
Stars: ✭ 10 (-78.72%)
Mutual labels:  schema, validation

inicpp

Linux Build Status Windows Build Status License Wiki Docs

C++ parser of INI files with schema validation.

About

This 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.

Great emphasis was put on qualities of object oriented design and clean implementation with modern C++ features.

Originally written by:

Versions

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.

Build instructions

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:

cmake [-G generator] [-DBUILD_STATIC=ON|OFF] [-DBUILD_SHARED=ON|OFF] source_dir

Also C++ compiler with at least C++17 support is required.

Linux

To build the library run following commands from root of source code directory:

$ mkdir -p build
$ cd build
$ cmake ..
$ make

To build and run unit tests using Google Test framework run additional commands:

$ make -f tests/Makefile
$ ./tests/run_tests

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.

Windows

For Windows there are two ways of building inicpp. For both ways cmake has to be installed on machine.

Using MS Visual Studio:

  • As stated Visual Studio 2017 (or later) should be installed on the machine.
  • If dependencies are successfully fulfilled then run cmake in root directory of repository using:
> cmake -G "Visual Studio 15 2017"
  • This command will generate solution files
  • Open solution file inicpp.sln using Visual Studio
  • Build ALL_BUILD project which will hopefully successfully build whole library
  • Distribute static or shared binaries which can be found in target build directories to your program/library

Using MS Visual C++:

  • Besides Visual C++ 2017 (or later) nmake compilation tool is needed (both should be part of Windows SDK)
  • Run cmake in root directory of repository using:
> cmake -G "NMake Makefiles"
  • This will generate file Makefile which can be interpreted with nmake
  • Now enter following easy command:
> nmake
  • After this compiled library should appear in working directory
  • Depending on your needs use inicpp or inicpp_static in your library or program

Examples

Some 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):

$ make -f examples/Makefile

Compiled examples can be run as follows:

$ ./examples/schema_validation/inicpp_schema
$ ./examples/basic/inicpp_basic

Expected outputs are also provided with examples sources.

Basic usage without schema

Slightly modified version of basic example.

std::cout << "Load and parse config from string" << std::endl;
config example_conf = parser::load(get_config());

std::cout << "Iterate through whole config and print it" << std::endl;
for(auto &sect : example_conf) {
	std::cout << "  Section: '" << sect.get_name() << "'" << std::endl;
	// Iterate through options in a section
	for(auto &opt : sect) {
		std::cout << "    Option: '" << opt.get_name() << "' with value(s): ";
		if (!opt.is_list()) {
			std::cout << "'" << opt.get<string_ini_t>() << "'";
		} else {
			for (auto &list_item : opt.get_list<string_ini_t>())
				std::cout << "'" << list_item << "' ";
		}
	}
}

std::cout << "Get number as signed_ini_t type" << std::endl;
try {
	signed_ini_t number = example_conf["Numbers"]["num"].get<signed_ini_t>();
	std::cout << "  " << number << std::endl;
} catch (bad_cast_exception) {
	std::cout << "  Item 'num' in 'Numbers' section cannot be casted to signed_ini_t type" << std::endl;
}

std::cout << "Change some values - could be properly typed" << std::endl;
// Make reference to the section
section &number_sect = example_conf["Numbers"];
// Change some values
number_sect["num"].set<signed_ini_t>(42222);
signed_ini_t new_num = number_sect["num"].get<signed_ini_t>();
std::cout << "  Option 'num' in 'Numbers' section is '" << new_num << "'" << std::endl;
// Following two lines are equivalent
number_sect["num_oct"].set<string_ini_t>("0756");
number_sect["num_oct"] = "0756"s;
std::cout << "  set method and assingment operator on option are equivalent" << std::endl;

std::cout << "Change single value to list and vice versa" << std::endl;
option &num_opt = number_sect["num"];
num_opt.add_to_list<signed_ini_t>(99);
if (num_opt.is_list()) {
	std::cout << "  'num' option in 'Numbers' section is list" << std::endl;
} else {
	std::cout << "  'num' option in 'Numbers' section is single value" << std::endl;
}
// Remove item from the list (specifying position)
num_opt.remove_from_list_pos(0); // remove first item
std::cout << "  first item from 'num' option list removed" << std::endl;
if (num_opt.is_list()) {
	std::cout << "  'num' option in 'Numbers' section is list" << std::endl;
} else {
	std::cout << "  'num' option in 'Numbers' section is single value" << std::endl;
}
std::cout << "  'num' option value is '" << num_opt.get<signed_ini_t>() << "'" << std::endl;

std::cout << "Save changes to ostream and print the result" << std::endl;
std::ostringstream ofs;
ofs << example_conf;
std::cout << ofs.str();

Without schema all items are treated as string type, but runtime conversion could be done to one of supported types if possible.

Schema validation support

Schema 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.

std::cout << "Create config schema" << std::endl;
schema schm;

// add section 'Section 1'
section_schema_params section_1_params;
section_1_params.name = "Section 1";
section_1_params.comment = "comment";
section_1_params.requirement = item_requirement::optional;
schm.add_section(section_1_params);

// add options to 'Section 1'
option_schema_params<signed_ini_t> option_1_params;
option_1_params.name = "Option 1";
option_1_params.type = option_item::single;
option_1_params.requirement = item_requirement::mandatory;
option_1_params.validator = [](signed_ini_t i){ return i < 0; }; // valid values are only negative ones
option_1_params.comment = "Important option\nshould be negative";
option_1_params.default_value = "-1";
schm.add_option("Section 1", option_1_params);

option_schema_params<float_ini_t> option_4_params;
option_4_params.name = "float1";
option_4_params.type = option_item::single;
option_4_params.requirement = item_requirement::mandatory;
schm.add_option("Section 1", option_4_params);


std::cout << "Load and validate config in relaxed mode" << std::endl;
config conf = parser::load(get_config(), schm, schema_mode::relaxed);

std::cout << "Check, if options are properly typed" << std::endl;
std::cout << "  'Option 1' is signed_ini_t type with value '" <<
	conf["Section 1"]["Option 1"].get<signed_ini_t>() << "'" << std::endl;
std::cout << "  'float1' option has value '" << conf["Section 1"]["float1"].get<float_ini_t>() <<
	std::endl;
std::cout << "  'unknown_option' was left as string with value '" <<
	conf["Section 1"]["unknown_option"].get<string_ini_t>() << std::endl;

std::cout << "Validation with strict mode fails due to 'unknown_option'" << std::endl;
try {
	parser::load(get_config(), schm, schema_mode::strict);
} catch (validation_exception) {
	std::cout << "  Strict mode validation failed" << std::endl;
}

std::cout << "Write default configuration from schema to stream" << std::endl;
std::ostringstream str;
str << schm;
std::cout << str.str();

std::cout << "Write current configuration with comments from schema to stream" << std::endl;
str.str("");
parser::save(conf, schm, str);
std::cout << str.str();

Contribution

This project is open for all contributions, but please respect some rules:

  • write clean code
  • use modern C++ features when possible
  • write tests - no need to have 100% coverage, but some tests should be present
  • format code using our style in provided .clang-format file - cmake target format on unix handle this
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].