Parsing Files and Strings #
In toml11, you can parse files, strings, and byte arrays using toml::parse
or toml::try_parse
.
Upon success, these functions return a toml::value
.
Although the parsed file is always a table, the return type is not toml::table
.
This is because toml::value
contains metadata about the file, whereas toml::table
is merely an alias for std::unordered_map<std::string, toml::value>
.
To include metadata, a toml::value
is returned instead of a toml::table
.
The toml::value
corresponding to the root of the file will always hold a table_type
.
Parsing Files #
To parse files, use either
toml::parse
or
toml::try_parse
.
toml::parse
#
Specifying the Filename with std::string
#
toml::parse
accepts a filename as a string, opens the file, and parses it.
The following sample code parses a file named input.toml
, extracts the title
variable as a string, and prints it.
#include <toml.hpp>
#include <iostream>
int main()
{
const toml::value input = toml::parse("input.toml");
std::cout << input.at("title").as_string() << std::endl;
return 0;
}
Specifying a File with std::filesystem::path
#
toml::parse
can accept a std::filesystem::path
.
This requires C++17 or later, as it relies on the <filesystem>
support.
Specifying an Input Stream with std::istream
#
toml::parse
can also accept an std::istream
.
Open a stream in binary mode by passing std::ios::binary
to avoid inconsistency between the file size and the number of characters due to automatic conversion of newline characters by the standard library.
Without the filename information, error messages will display "unknown file"
. To avoid this, you can pass the filename as a std::string
in the second argument when using std::istream
.
You can use streams other than std::ifstream
, such as std::istringstream
. Note that the entire content is readable at the time of the call.
#include <toml.hpp>
#include <iostream>
int main()
{
std::string filename("input.toml");
std::ifstream ifs(filename);
const toml::value input = toml::parse(ifs, filename);
std::cout << input.at("title").as_string() << std::endl;
return 0;
}
Specifying a File with FILE*
#
toml::parse
can also accept a FILE*
.
Open a stream in binary mode by passing "rb"
to avoid inconsistency between the file size and the number of characters due to automatic conversion of newline characters by the standard library.
As with std::istream
, you need to provide the filename as a string in the second argument.
When passing a FILE*
, if the file read fails, errno
will be reported.
Error Handling #
toml::parse
throws a toml::syntax_error
if it encounters a syntax error.
toml::syntax_error
is derived from toml::exception
, which in turn is derived from std::exception
.
Therefore, you can use the what()
member function to retrieve the error message from a toml::syntax_error
.
Additionally, toml::syntax_error
contains a std::vector<toml::error_info>
, which can be accessed using the errors()
member function.
toml::parse
attempts to recover from minor errors and report multiple errors whenever possible. While it can often recover from simple errors like number format issues, errors within arrays or tables might not be recoverable and may lead to multiple similar error reports. If you find the error messages redundant, you can use only the front()
of the std::vector<toml::error_info>
to get a message about the most critical issue.
#include <toml.hpp>
int main()
{
try {
const toml::value input = toml::parse("input.toml");
std::cout << input.at("title").as_string() << std::endl;
} catch(const toml::syntax_error& err) {
// report all the errors
std::cerr << err.what() << std::endl;
// report the first error only
std::cerr << err.errors().front() << std::endl;
}
}
toml::try_parse
#
While toml::parse
throws an exception on failure, toml::try_parse
does not throw exceptions when it fails.
Instead, its return type is toml::result<toml::value, std::vector<toml::error_info>>
.
The result
type holds either a success value or a failure value, similar to Rust’s Result
or Haskell’s Either
.
#include <toml.hpp>
int main()
{
const auto parse_result = toml::try_parse("input.toml");
if(parse_result.is_ok())
{
std::cout << parse_result.unwrap().at("title").as_string() << std::endl;
}
else
{
std::cerr << parse_result.unwrap_err().at(0) << std::endl;
}
return 0;
}
To check which value the result
type holds, use the is_ok()
and is_err()
functions. The success or failure value can be retrieved using unwrap()
and unwrap_err()
, respectively. If unwrap
fails, it throws a bad_result_access
exception. Using the as_ok()
and as_err()
functions does not throw exceptions on failure, but results in undefined behavior.
Although
try_parse
does not throwsyntax_error
orfile_io_error
, it returns the sametoml::error_info
as the failure type in theresult
. However, it is not entirely exception-free.If an internal standard library error occurs, such as
std::bad_alloc
when avector
fails to allocate memory,toml::try_parse
does not catch this and will let it propagate. Thus, exceptions originating from the standard library may still be thrown.
Parsing Strings #
toml::parse_str
#
toml::parse_str
accepts the string to be parsed directly, instead of a filename.
For the part of the error message that corresponds to the TOML file’s name, if the std::source_location
equivalent compiler extension is available, the name and line number of the C++ file that called parse_str
will be used instead.
#include <toml.hpp>
#include <iostream>
int main()
{
const toml::value input = toml::parse_str("title = \"parse_str\"");
std::cout << input.at("title").as_string() << std::endl;
return 0;
}
toml::try_parse_str
#
toml::try_parse_str
also takes the string to be parsed directly, similar to parse_str
. Like try_parse
, it uses toml::result
to report errors.
#include <toml.hpp>
#include <iostream>
int main()
{
const auto parse_result = toml::try_parse_str("title = \"parse_str\"");
if(parse_result.is_ok())
{
std::cout << parse_result.unwrap().at("title").as_string() << std::endl;
}
else
{
std::cerr << parse_result.unwrap_err().at(0) << std::endl;
}
return 0;
}
Parsing Byte Arrays #
It is also possible to parse byte arrays instead of files.
Since the byte arrays must be encoded in UTF-8, unsigned char
is used.
toml::parse(std::vector<unsigned char>)
#
The behavior is the same as toml::parse
.
When parsing byte arrays, a filename
is required.
#include <toml.hpp>
#include <iostream>
int main()
{
std::vector<unsigned char> bytes{/* ... */};
const toml::value input = toml::parse(bytes, "internal bytes");
std::cout << input.at("title").as_string() << std::endl;
return 0;
}
toml::try_parse(std::vector<unsigned char>)
#
The behavior is the same as toml::try_parse
.
When parsing byte arrays, a filename
is required.
#include <toml.hpp>
#include <iostream>
int main()
{
std::vector<unsigned char> bytes{/* ... */};
const auto parse_result = toml::try_parse(bytes, "internal bytes");
if(parse_result.is_ok())
{
std::cout << parse_result.unwrap().at("title").as_string() << std::endl;
}
else
{
std::cerr << parse_result.unwrap_err().at(0) << std::endl;
}
return 0;
}