A header-only library for parsing TOML configuration files.
Targets: TOML v0.4.0 as of February 2015.
It is reasonably conforming, with the exception of unicode escape characters in strings. This includes support for the new DateTime format, inline tables, multi-line basic and raw strings, and digit separators.
Alternatives:
- ctoml is a C++11 implementation of a TOML parser, but only supports v0.2.0.
- libtoml is a C implementation of a TOML parser, which can be linked to from your C++ programs easily. As of April 2016, it supports v0.4.0.
- tinytoml is a C++11 implementation of a TOML parser, which also supports v0.4.0 as of November 2015.
The following two tests are the only failing tests from the toml-test suite.
Test: string-escapes (valid)
Parsing failed: Invalid escape sequence at line 9
-------------------------------------------------------------------------------
Test: unicode-escape (valid)
Parsing failed: Invalid escape sequence at line 1
76 passed, 2 failed
Requires a well conforming C++11 compiler. On OSX this means clang++ with libc++ and libc++abi (the default clang installed with XCode's command line tools is sufficient).
On Linux, you should be able to use g++ >= 4.8.x, or clang++ with libc++ and libc++abi (if your package manager supplies this; most don't).
Compiling the examples can be done with cmake:
mkdir build
cd build
cmake ../
make
To parse a configuration file from a file, you can do the following:
auto config = cpptoml::parse_file("config.toml");
parse_file()
returns a (shared pointer to a) cpptoml::table
, which you
can then query. It will throw an instance of cpptoml::parse_exception
in
the event that the file failed to parse, and the exception message should
contain the line number the error occurred as well as a description of the
error.
You can find basic values like so:
auto val = config->get_as<int64_t>("my-int");
// val is a cpptoml::option<int64_t>
if (val)
{
// *val is the integer value for the key "my-int"
}
else
{
// "my-int" either did not exist or was not an integer
}
To simplify things, you can specify default a default value using the
value_or
function on the option
:
auto baz = config->get_as<double>("baz").value_or(0.5);
// baz is now the double value for key "baz", if it exists, or 0.5 otherwise
TOML DateTimes are represented as cpptoml::datetime
objects, which are
very simple structs containing the following fields:
- year
- month
- day
- hour
- minute
- second
- microsecond
- hour_offset
- minute_offset
There are convenience functions cpptoml::datetime::from_local()
and
cpptoml::datetime::from_utc()
to convert struct tm
s to
cpptoml::datetime
s.
If you want to look up things in nested tables, there are two ways of doing this. Suppose you have the following structure:
[first-table]
key1 = 0.1
key2 = 1284
[first-table.inner]
key3 = "hello world"
Here's an idiomatic way of obtaining all three keys' values:
auto config = cpptoml::parse_file("config.toml");
auto key1 = config->get_qualified_as<double>("first-table.key1");
auto key2 = config->get_qualified_as<int>("first-table.key2");
auto key3 = config->get_qualified_as<std::string>("first-table.inner.key3");
(Note that, because the TOML spec allows for "." to occur in a table name, you won't always be able to do this for any nested key, but in practice you should be fine.)
A slightly more verbose way of getting them would be to first obtain the individual tables, and then query those individual tables for their keys like so:
auto config = cpptoml::parse_file("config.toml");
auto first = config->get_table("first-table");
auto key1 = first->get_as<double>("key1");
auto key2 = first->get_as<int>("key2");
auto inner = first->get_table("inner");
auto key3 = inner->get_as<std::string>("key3");
The function get_table_qualified
also exists, so obtaining the inner
table could be written as
auto inner2 = config->get_table_qualified("first-table.inner");
Suppose you had a configuration file like the following:
arr = [1, 2, 3, 4, 5]
mixed-arr = [[1, 2, 3, 4, 5], ["hello", "world"], [0.1, 1.1, 2.1]]
To obtain an array of values, you can do the following:
auto config = cpptoml::parse_file("config.toml");
auto vals = config->get_array_of<int64_t>("arr");
// vals is a cpptoml::option<std::vector<int64_t>>
for (const auto& val : *vals)
{
// val is an int64_t
}
get_array_of
will return an option<vector<T>>
, which will be empty if
the key does not exist, is not of the array type, or contains values that
are not of type T
.
For nested arrays, it looks like the following:
auto nested = config->get_array_of<cpptoml::array>("mixed-arr");
auto ints = (*nested)[0]->get_array_of<int64_t>();
// ints is a cpptoml::option<std::vector<int64_t>>
auto strings = (*nested)[1]->get_array_of<std::string>();
auto doubles = (*nested)[2]->get_array_of<double>();
There is also a get_qualified_array_of
for simplifying arrays located
inside nested tables.
Suppose you had a configuration file like the following:
[[table-array]]
key1 = "hello"
[[table-array]]
key1 = "can you hear me"
Arrays of tables are represented as a separate type in cpptoml
. They can
be obtained like so:
auto config = cpptoml::parse_file("config.toml");
auto tarr = config->get_table_array("table-array");
for (const auto& table : *tarr)
{
// *table is a cpptoml::table
auto key1 = table->get_as<std::string>("key1");
}
You can look at the files files parse.cpp
, parse_stdin.cpp
, and
build_toml.cpp
in the root directory for some more examples.
parse_stdin.cpp
shows how to use the visitor pattern to traverse an
entire cpptoml::table
for serialization.
build_toml.cpp
shows how to construct a TOML representation in-memory and
then serialize it to a stream.