mirror of
https://github.com/ToruNiina/toml11.git
synced 2025-01-10 01:20:06 +00:00
Merge branch 'master' into find-idx
This commit is contained in:
commit
827b433389
@ -12,7 +12,7 @@ jobs:
|
|||||||
command: |
|
command: |
|
||||||
g++ --version
|
g++ --version
|
||||||
cd tests/
|
cd tests/
|
||||||
g++ -std=c++11 -O2 -Wall -Wextra -Werror -I../ check_toml_test.cpp -o check_toml_test
|
g++ -std=c++11 -O2 -Wall -Wextra -Werror -DTOML11_COLORIZE_ERROR_MESSAGE -I../ check_toml_test.cpp -o check_toml_test
|
||||||
go get github.com/BurntSushi/toml-test
|
go get github.com/BurntSushi/toml-test
|
||||||
$GOPATH/bin/toml-test ./check_toml_test
|
$GOPATH/bin/toml-test ./check_toml_test
|
||||||
test_serialization:
|
test_serialization:
|
||||||
@ -24,7 +24,7 @@ jobs:
|
|||||||
command: |
|
command: |
|
||||||
g++ --version
|
g++ --version
|
||||||
cd tests/
|
cd tests/
|
||||||
g++ -std=c++11 -O2 -Wall -Wextra -Wpedantic -Werror -I../ check_serialization.cpp -o check_serialization
|
g++ -std=c++11 -O2 -Wall -Wextra -Wpedantic -Werror -DTOML11_COLORIZE_ERROR_MESSAGE -I../ check_serialization.cpp -o check_serialization
|
||||||
git clone https://github.com/BurntSushi/toml-test.git
|
git clone https://github.com/BurntSushi/toml-test.git
|
||||||
cp check_serialization toml-test/tests/valid
|
cp check_serialization toml-test/tests/valid
|
||||||
cd toml-test/tests/valid
|
cd toml-test/tests/valid
|
||||||
@ -47,7 +47,7 @@ jobs:
|
|||||||
command: |
|
command: |
|
||||||
g++ --version
|
g++ --version
|
||||||
cd tests/
|
cd tests/
|
||||||
g++ -std=c++11 -O2 -Wall -Wextra -Wpedantic -Werror -I../ check.cpp -o check
|
g++ -std=c++11 -O2 -Wall -Wextra -Wpedantic -Werror -DTOML11_COLORIZE_ERROR_MESSAGE -I../ check.cpp -o check
|
||||||
git clone https://github.com/BurntSushi/toml-test.git
|
git clone https://github.com/BurntSushi/toml-test.git
|
||||||
cp check toml-test/tests/invalid
|
cp check toml-test/tests/invalid
|
||||||
cp check toml-test/tests/valid
|
cp check toml-test/tests/valid
|
||||||
|
72
.travis.yml
72
.travis.yml
@ -9,7 +9,7 @@ matrix:
|
|||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
- ubuntu-toolchain-r-test
|
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||||
- sourceline: 'ppa:mhier/libboost-latest'
|
- sourceline: 'ppa:mhier/libboost-latest'
|
||||||
packages:
|
packages:
|
||||||
- g++-5
|
- g++-5
|
||||||
@ -21,7 +21,7 @@ matrix:
|
|||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
- ubuntu-toolchain-r-test
|
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||||
- sourceline: 'ppa:mhier/libboost-latest'
|
- sourceline: 'ppa:mhier/libboost-latest'
|
||||||
packages:
|
packages:
|
||||||
- g++-6
|
- g++-6
|
||||||
@ -33,7 +33,7 @@ matrix:
|
|||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
- ubuntu-toolchain-r-test
|
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||||
- sourceline: 'ppa:mhier/libboost-latest'
|
- sourceline: 'ppa:mhier/libboost-latest'
|
||||||
packages:
|
packages:
|
||||||
- g++-7
|
- g++-7
|
||||||
@ -45,7 +45,7 @@ matrix:
|
|||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
- ubuntu-toolchain-r-test
|
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||||
- sourceline: 'ppa:mhier/libboost-latest'
|
- sourceline: 'ppa:mhier/libboost-latest'
|
||||||
packages:
|
packages:
|
||||||
- g++-8
|
- g++-8
|
||||||
@ -57,7 +57,7 @@ matrix:
|
|||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
- ubuntu-toolchain-r-test
|
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||||
- sourceline: 'ppa:mhier/libboost-latest'
|
- sourceline: 'ppa:mhier/libboost-latest'
|
||||||
packages:
|
packages:
|
||||||
- g++-8
|
- g++-8
|
||||||
@ -69,7 +69,7 @@ matrix:
|
|||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
- ubuntu-toolchain-r-test
|
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||||
- sourceline: 'ppa:mhier/libboost-latest'
|
- sourceline: 'ppa:mhier/libboost-latest'
|
||||||
packages:
|
packages:
|
||||||
- g++-8
|
- g++-8
|
||||||
@ -81,7 +81,7 @@ matrix:
|
|||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
- ubuntu-toolchain-r-test
|
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||||
- sourceline: 'ppa:mhier/libboost-latest'
|
- sourceline: 'ppa:mhier/libboost-latest'
|
||||||
packages:
|
packages:
|
||||||
- g++-8
|
- g++-8
|
||||||
@ -89,16 +89,16 @@ matrix:
|
|||||||
- os: linux
|
- os: linux
|
||||||
language: cpp
|
language: cpp
|
||||||
compiler: clang
|
compiler: clang
|
||||||
env: COMPILER="clang++-3.7" CXX_STANDARD=11 TOML_HEAD=OFF
|
env: COMPILER="clang++-3.9" CXX_STANDARD=11 TOML_HEAD=OFF
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
- ubuntu-toolchain-r-test
|
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||||
- llvm-toolchain-precise-3.7
|
|
||||||
- sourceline: 'ppa:mhier/libboost-latest'
|
- sourceline: 'ppa:mhier/libboost-latest'
|
||||||
|
- llvm-toolchain-trusty-3.9
|
||||||
packages:
|
packages:
|
||||||
- g++-8
|
- g++-8
|
||||||
- clang-3.7
|
- clang-3.9
|
||||||
- boost1.70
|
- boost1.70
|
||||||
- os: linux
|
- os: linux
|
||||||
language: cpp
|
language: cpp
|
||||||
@ -107,9 +107,9 @@ matrix:
|
|||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
- ubuntu-toolchain-r-test
|
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||||
- llvm-toolchain-trusty-4.0
|
|
||||||
- sourceline: 'ppa:mhier/libboost-latest'
|
- sourceline: 'ppa:mhier/libboost-latest'
|
||||||
|
- llvm-toolchain-trusty-4.0
|
||||||
packages:
|
packages:
|
||||||
- g++-8
|
- g++-8
|
||||||
- clang-4.0
|
- clang-4.0
|
||||||
@ -121,9 +121,9 @@ matrix:
|
|||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
- ubuntu-toolchain-r-test
|
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||||
- llvm-toolchain-trusty-5.0
|
|
||||||
- sourceline: 'ppa:mhier/libboost-latest'
|
- sourceline: 'ppa:mhier/libboost-latest'
|
||||||
|
- llvm-toolchain-trusty-5.0
|
||||||
packages:
|
packages:
|
||||||
- g++-8
|
- g++-8
|
||||||
- clang-5.0
|
- clang-5.0
|
||||||
@ -135,9 +135,9 @@ matrix:
|
|||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
- ubuntu-toolchain-r-test
|
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||||
- llvm-toolchain-trusty-6.0
|
|
||||||
- sourceline: 'ppa:mhier/libboost-latest'
|
- sourceline: 'ppa:mhier/libboost-latest'
|
||||||
|
- llvm-toolchain-trusty-6.0
|
||||||
packages:
|
packages:
|
||||||
- g++-8
|
- g++-8
|
||||||
- clang-6.0
|
- clang-6.0
|
||||||
@ -149,9 +149,9 @@ matrix:
|
|||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
- ubuntu-toolchain-r-test
|
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||||
- llvm-toolchain-trusty-7
|
|
||||||
- sourceline: 'ppa:mhier/libboost-latest'
|
- sourceline: 'ppa:mhier/libboost-latest'
|
||||||
|
- llvm-toolchain-trusty-7
|
||||||
packages:
|
packages:
|
||||||
- g++-8
|
- g++-8
|
||||||
- clang-7
|
- clang-7
|
||||||
@ -163,9 +163,9 @@ matrix:
|
|||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
- ubuntu-toolchain-r-test
|
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||||
- llvm-toolchain-trusty-8
|
|
||||||
- sourceline: 'ppa:mhier/libboost-latest'
|
- sourceline: 'ppa:mhier/libboost-latest'
|
||||||
|
- llvm-toolchain-trusty-8
|
||||||
packages:
|
packages:
|
||||||
- g++-8
|
- g++-8
|
||||||
- clang-8
|
- clang-8
|
||||||
@ -177,9 +177,9 @@ matrix:
|
|||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
- ubuntu-toolchain-r-test
|
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||||
- llvm-toolchain-trusty-8
|
|
||||||
- sourceline: 'ppa:mhier/libboost-latest'
|
- sourceline: 'ppa:mhier/libboost-latest'
|
||||||
|
- llvm-toolchain-trusty-8
|
||||||
packages:
|
packages:
|
||||||
- g++-8
|
- g++-8
|
||||||
- clang-8
|
- clang-8
|
||||||
@ -191,9 +191,9 @@ matrix:
|
|||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
- ubuntu-toolchain-r-test
|
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||||
- llvm-toolchain-trusty-8
|
|
||||||
- sourceline: 'ppa:mhier/libboost-latest'
|
- sourceline: 'ppa:mhier/libboost-latest'
|
||||||
|
- llvm-toolchain-trusty-8
|
||||||
packages:
|
packages:
|
||||||
- clang-8
|
- clang-8
|
||||||
- g++-8
|
- g++-8
|
||||||
@ -205,9 +205,9 @@ matrix:
|
|||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
- ubuntu-toolchain-r-test
|
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||||
- llvm-toolchain-trusty-8
|
|
||||||
- sourceline: 'ppa:mhier/libboost-latest'
|
- sourceline: 'ppa:mhier/libboost-latest'
|
||||||
|
- llvm-toolchain-trusty-8
|
||||||
packages:
|
packages:
|
||||||
- clang-8
|
- clang-8
|
||||||
- g++-8
|
- g++-8
|
||||||
@ -216,6 +216,15 @@ matrix:
|
|||||||
language: cpp
|
language: cpp
|
||||||
compiler: clang
|
compiler: clang
|
||||||
env: CXX_STANDARD=11
|
env: CXX_STANDARD=11
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- $HOME/Library/Caches/Homebrew
|
||||||
|
addons:
|
||||||
|
homebrew:
|
||||||
|
update: true
|
||||||
|
packages:
|
||||||
|
- cmake
|
||||||
|
- boost
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- |
|
- |
|
||||||
@ -224,8 +233,6 @@ script:
|
|||||||
travis_retry wget "https://github.com/Kitware/CMake/releases/download/v3.14.5/cmake-3.14.5-Linux-x86_64.tar.gz"
|
travis_retry wget "https://github.com/Kitware/CMake/releases/download/v3.14.5/cmake-3.14.5-Linux-x86_64.tar.gz"
|
||||||
tar xf cmake-3.14.5-Linux-x86_64.tar.gz -C cmake --strip-components=1
|
tar xf cmake-3.14.5-Linux-x86_64.tar.gz -C cmake --strip-components=1
|
||||||
export PATH=${TRAVIS_BUILD_DIR}/cmake/bin:${PATH}
|
export PATH=${TRAVIS_BUILD_DIR}/cmake/bin:${PATH}
|
||||||
else
|
|
||||||
brew upgrade cmake boost
|
|
||||||
fi
|
fi
|
||||||
- cmake --version
|
- cmake --version
|
||||||
- mkdir build
|
- mkdir build
|
||||||
@ -234,3 +241,10 @@ script:
|
|||||||
- cmake -DCMAKE_CXX_COMPILER=$COMPILER -DCMAKE_CXX_STANDARD=$CXX_STANDARD -DTOML11_USE_UNRELEASED_TOML_FEATURES=${TOML_HEAD} ..
|
- cmake -DCMAKE_CXX_COMPILER=$COMPILER -DCMAKE_CXX_STANDARD=$CXX_STANDARD -DTOML11_USE_UNRELEASED_TOML_FEATURES=${TOML_HEAD} ..
|
||||||
- make
|
- make
|
||||||
- ctest --output-on-failure
|
- ctest --output-on-failure
|
||||||
|
|
||||||
|
# https://stackoverflow.com/a/53331571
|
||||||
|
before_cache:
|
||||||
|
- |
|
||||||
|
if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then
|
||||||
|
brew cleanup
|
||||||
|
fi
|
||||||
|
@ -4,8 +4,8 @@ enable_testing()
|
|||||||
project(toml11)
|
project(toml11)
|
||||||
|
|
||||||
set(toml11_VERSION_MAYOR 3)
|
set(toml11_VERSION_MAYOR 3)
|
||||||
set(toml11_VERSION_MINOR 0)
|
set(toml11_VERSION_MINOR 2)
|
||||||
set(toml11_VERSION_PATCH 1)
|
set(toml11_VERSION_PATCH 0)
|
||||||
set(toml11_VERSION
|
set(toml11_VERSION
|
||||||
"${toml11_VERSION_MAYOR}.${toml11_VERSION_MINOR}.${toml11_VERSION_PATCH}"
|
"${toml11_VERSION_MAYOR}.${toml11_VERSION_MINOR}.${toml11_VERSION_PATCH}"
|
||||||
)
|
)
|
||||||
|
235
README.md
235
README.md
@ -68,6 +68,9 @@ int main()
|
|||||||
- [TOML literal](#toml-literal)
|
- [TOML literal](#toml-literal)
|
||||||
- [Conversion between toml value and arbitrary types](#conversion-between-toml-value-and-arbitrary-types)
|
- [Conversion between toml value and arbitrary types](#conversion-between-toml-value-and-arbitrary-types)
|
||||||
- [Formatting user-defined error messages](#formatting-user-defined-error-messages)
|
- [Formatting user-defined error messages](#formatting-user-defined-error-messages)
|
||||||
|
- [Obtaining location information](#obtaining-location-information)
|
||||||
|
- [Exceptions](#exceptions)
|
||||||
|
- [Colorize Error Messages](#colorize-error-messages)
|
||||||
- [Serializing TOML data](#serializing-toml-data)
|
- [Serializing TOML data](#serializing-toml-data)
|
||||||
- [Underlying types](#underlying-types)
|
- [Underlying types](#underlying-types)
|
||||||
- [Unreleased TOML features](#unreleased-toml-features)
|
- [Unreleased TOML features](#unreleased-toml-features)
|
||||||
@ -351,6 +354,7 @@ The above code works with the following toml file.
|
|||||||
# NOT {"physical": {"color": "orange"}}.
|
# NOT {"physical": {"color": "orange"}}.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Casting a toml value
|
## Casting a toml value
|
||||||
|
|
||||||
### `toml::get`
|
### `toml::get`
|
||||||
@ -470,6 +474,44 @@ If an invalid key (integer for a table, string for an array), it throws
|
|||||||
`toml::type_error` for the conversion. If the provided key is out-of-range,
|
`toml::type_error` for the conversion. If the provided key is out-of-range,
|
||||||
it throws `std::out_of_range`.
|
it throws `std::out_of_range`.
|
||||||
|
|
||||||
|
Note that, although `std::string` has `at()` member function, `toml::value::at`
|
||||||
|
throws if the contained type is a string. Because `std::string` does not
|
||||||
|
contain `toml::value`.
|
||||||
|
|
||||||
|
### `operator[]`
|
||||||
|
|
||||||
|
You can also access to the element of a table and an array by
|
||||||
|
`toml::basic_value::operator[]`.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
const toml::value v{1,2,3,4,5};
|
||||||
|
std::cout << v[2].as_integer() << std::endl; // 3
|
||||||
|
|
||||||
|
const toml::value v{{"foo", 42}, {"bar", 3.14}};
|
||||||
|
std::cout << v["foo"].as_integer() << std::endl; // 42
|
||||||
|
```
|
||||||
|
|
||||||
|
When you access to a `toml::value` that is not initialized yet via
|
||||||
|
`operator[](const std::string&)`, the `toml::value` will be a table,
|
||||||
|
just like the `std::map`.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
toml::value v; // not initialized as a table.
|
||||||
|
v["foo"] = 42; // OK. `v` will be a table.
|
||||||
|
```
|
||||||
|
|
||||||
|
Contrary, if you access to a `toml::value` that contains an array via `operator[]`,
|
||||||
|
it does not check anything. It converts `toml::value` without type check and then
|
||||||
|
access to the n-th element without boundary check, just like the `std::vector::operator[]`.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
toml::value v; // not initialized as an array
|
||||||
|
v[2] = 42; // error! UB
|
||||||
|
```
|
||||||
|
|
||||||
|
Please make sure that the `toml::value` has an array inside when you access to
|
||||||
|
its element via `operator[]`.
|
||||||
|
|
||||||
## Checking value type
|
## Checking value type
|
||||||
|
|
||||||
You can check the type of a value by `is_xxx` function.
|
You can check the type of a value by `is_xxx` function.
|
||||||
@ -692,6 +734,7 @@ date information, but it can be converted to `std::chrono::duration` that
|
|||||||
represents a duration from the beginning of the day, `00:00:00.000`.
|
represents a duration from the beginning of the day, `00:00:00.000`.
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
|
# sample.toml
|
||||||
date = 2018-12-23
|
date = 2018-12-23
|
||||||
time = 12:30:00
|
time = 12:30:00
|
||||||
l_dt = 2018-12-23T12:30:00
|
l_dt = 2018-12-23T12:30:00
|
||||||
@ -708,8 +751,12 @@ const auto o_dt = toml::get<std::chrono::system_clock::time_point>(data.at("o_dt
|
|||||||
const auto time = toml::get<std::chrono::minutes>(data.at("time")); // 12 * 60 + 30 min
|
const auto time = toml::get<std::chrono::minutes>(data.at("time")); // 12 * 60 + 30 min
|
||||||
```
|
```
|
||||||
|
|
||||||
toml11 defines its own datetime classes.
|
`local_date` and `local_datetime` are assumed to be in the local timezone when
|
||||||
You can see the definitions in [toml/datetime.hpp](toml/datetime.hpp).
|
they are converted into `time_point`. On the other hand, `offset_datetime` only
|
||||||
|
uses the offset part of the data and it does not take local timezone into account.
|
||||||
|
|
||||||
|
To contain datetime data, toml11 defines its own datetime types.
|
||||||
|
For more detail, you can see the definitions in [toml/datetime.hpp](toml/datetime.hpp).
|
||||||
|
|
||||||
## Getting with a fallback
|
## Getting with a fallback
|
||||||
|
|
||||||
@ -1254,7 +1301,28 @@ you will get an error message like this.
|
|||||||
| ~~ maximum number here
|
| ~~ maximum number here
|
||||||
```
|
```
|
||||||
|
|
||||||
### Obtaining location information
|
You can print hints at the end of the message.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
std::vector<std::string> hints;
|
||||||
|
hints.push_back("positive number means n >= 0.");
|
||||||
|
hints.push_back("negative number is not positive.");
|
||||||
|
std::cerr << toml::format_error("[error] value should be positive",
|
||||||
|
data.at("num"), "positive number required", hints)
|
||||||
|
<< std::endl;
|
||||||
|
```
|
||||||
|
|
||||||
|
```console
|
||||||
|
[error] value should be positive
|
||||||
|
--> example.toml
|
||||||
|
2 | num = 42
|
||||||
|
| ~~ positive number required
|
||||||
|
|
|
||||||
|
Hint: positive number means n >= 0.
|
||||||
|
Hint: negative number is not positive.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Obtaining location information
|
||||||
|
|
||||||
You can also format error messages in your own way by using `source_location`.
|
You can also format error messages in your own way by using `source_location`.
|
||||||
|
|
||||||
@ -1279,6 +1347,92 @@ const toml::value v = /*...*/;
|
|||||||
const toml::source_location loc = v.location();
|
const toml::source_location loc = v.location();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Exceptions
|
||||||
|
|
||||||
|
All the exceptions thrown by toml11 inherits `toml::exception` that inherits
|
||||||
|
`std::exception`.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
namespace toml {
|
||||||
|
struct exception : public std::exception {/**/};
|
||||||
|
struct syntax_error : public toml::exception {/**/};
|
||||||
|
struct type_error : public toml::exception {/**/};
|
||||||
|
struct internal_error : public toml::exception {/**/};
|
||||||
|
} // toml
|
||||||
|
```
|
||||||
|
|
||||||
|
`toml::exception` has `toml::exception::location()` member function that returns
|
||||||
|
`toml::source_location`, in addition to `what()`.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
namespace toml {
|
||||||
|
struct exception : public std::exception
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
source_location const& location() const noexcept;
|
||||||
|
};
|
||||||
|
} // toml
|
||||||
|
```
|
||||||
|
|
||||||
|
It represents where the error occurs.
|
||||||
|
|
||||||
|
## Colorize Error Messages
|
||||||
|
|
||||||
|
By defining `TOML11_COLORIZE_ERROR_MESSAGE`, the error messages from
|
||||||
|
`toml::parse` and `toml::find|get` will be colorized. By default, this feature
|
||||||
|
is turned off.
|
||||||
|
|
||||||
|
With the following toml file taken from `toml-lang/toml/tests/hard_example.toml`,
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[error]
|
||||||
|
array = [
|
||||||
|
"This might most likely happen in multiline arrays",
|
||||||
|
Like here,
|
||||||
|
"or here,
|
||||||
|
and here"
|
||||||
|
] End of array comment, forgot the #
|
||||||
|
```
|
||||||
|
|
||||||
|
the error message would be like this.
|
||||||
|
|
||||||
|
![error-message-1](https://github.com/ToruNiina/toml11/blob/misc/misc/toml11-err-msg-1.png)
|
||||||
|
|
||||||
|
With the following,
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[error]
|
||||||
|
# array = [
|
||||||
|
# "This might most likely happen in multiline arrays",
|
||||||
|
# Like here,
|
||||||
|
# "or here,
|
||||||
|
# and here"
|
||||||
|
# ] End of array comment, forgot the #
|
||||||
|
number = 3.14 pi <--again forgot the #
|
||||||
|
```
|
||||||
|
|
||||||
|
the error message would be like this.
|
||||||
|
|
||||||
|
![error-message-2](https://github.com/ToruNiina/toml11/blob/misc/misc/toml11-err-msg-2.png)
|
||||||
|
|
||||||
|
The message would be messy when it is written to a file, not a terminal because
|
||||||
|
it uses [ANSI escape code](https://en.wikipedia.org/wiki/ANSI_escape_code).
|
||||||
|
|
||||||
|
Without `TOML11_COLORIZE_ERROR_MESSAGE`, you can still colorize user-defined
|
||||||
|
error message by passing `true` to the `toml::format_error` function.
|
||||||
|
If you define `TOML11_COLORIZE_ERROR_MESSAGE`, the value is `true` by default.
|
||||||
|
If not, the defalut value would be `false`.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
std::cerr << toml::format_error("[error] value should be positive",
|
||||||
|
data.at("num"), "positive number required",
|
||||||
|
hints, /*colorize = */ true) << std::endl;
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: It colorize `[error]` in red. That means that it detects `[error]` prefix
|
||||||
|
at the front of the error message. If there is no `[error]` prefix,
|
||||||
|
`format_error` adds it to the error message.
|
||||||
|
|
||||||
## Serializing TOML data
|
## Serializing TOML data
|
||||||
|
|
||||||
toml11 enables you to serialize data into toml format.
|
toml11 enables you to serialize data into toml format.
|
||||||
@ -1411,17 +1565,83 @@ This feature is introduced to make it easy to write a custom serializer.
|
|||||||
Because `std::chrono::system_clock::time_point` is a __time point__,
|
Because `std::chrono::system_clock::time_point` is a __time point__,
|
||||||
not capable of representing a Local Time independent from a specific day.
|
not capable of representing a Local Time independent from a specific day.
|
||||||
|
|
||||||
It is recommended to get `datetime`s as `std::chrono` classes through `toml::get`.
|
|
||||||
|
|
||||||
## Unreleased TOML features
|
## Unreleased TOML features
|
||||||
|
|
||||||
There are some unreleased features in toml-lang/toml:master.
|
There are some unreleased features in toml-lang/toml:master.
|
||||||
Currently, the following features are available after defining
|
Currently, the following features are available after defining
|
||||||
`TOML11_USE_UNRELEASED_TOML_FEATURES` macro flag.
|
`TOML11_USE_UNRELEASED_TOML_FEATURES` macro flag.
|
||||||
|
|
||||||
|
To use those features, `#define` `TOML11_USE_UNRELEASED_TOML_FEATURES` before
|
||||||
|
including `toml.hpp` or pass `-DTOML11_USE_UNRELEASED_TOML_FEATURES` to your
|
||||||
|
compiler.
|
||||||
|
|
||||||
- Leading zeroes in exponent parts of floats are permitted.
|
- Leading zeroes in exponent parts of floats are permitted.
|
||||||
- e.g. `1.0e+01`, `5e+05`
|
- e.g. `1.0e+01`, `5e+05`
|
||||||
|
- [toml-lang/toml/PR/656](https://github.com/toml-lang/toml/pull/656)
|
||||||
- Allow raw tab characters in basic strings and multi-line basic strings.
|
- Allow raw tab characters in basic strings and multi-line basic strings.
|
||||||
|
- [toml-lang/toml/PR/627](https://github.com/toml-lang/toml/pull/627)
|
||||||
|
- Allow heterogeneous arrays
|
||||||
|
- [toml-lang/toml/PR/676](https://github.com/toml-lang/toml/pull/676)
|
||||||
|
|
||||||
|
### Note about heterogeneous arrays
|
||||||
|
|
||||||
|
Although `toml::parse` allows heterogeneous arrays, constructor of `toml::value`
|
||||||
|
does not.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// this won't be compiled
|
||||||
|
toml::value v{
|
||||||
|
"foo", 3.14, 42, {1,2,3,4,5}, {{"key", "value"}}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
There is a workaround for this issue. By explicitly converting values into
|
||||||
|
`toml::value`, you can initialize `toml::value` with a heterogeneous array.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// OK!
|
||||||
|
toml::value v{
|
||||||
|
toml::value("foo"), toml::value(3.14), toml::value(42),
|
||||||
|
toml::value{1,2,3,4,5}, toml::value{{"key", "value"}}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The reason why the first example is not allowed is the following.
|
||||||
|
Let's assume that you are initializing a `toml::value` with a table.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// # expecting TOML table.
|
||||||
|
toml::value v{ // [v]
|
||||||
|
{"answer", 42}, // answer = 42
|
||||||
|
{"pi", 3.14}, // pi = 3.14
|
||||||
|
{"foo", "bar"} // foo = "bar"
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
This is indistinguishable from a (heterogeneous) TOML array definition.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
v = [
|
||||||
|
["answer", 42],
|
||||||
|
["pi", 3.14],
|
||||||
|
["foo", "bar"],
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
This means that the above C++ code makes constructor's overload resolution
|
||||||
|
ambiguous. So a constructor that allows both "table as an initializer-list" and
|
||||||
|
"heterogeneous array as an initializer-list" cannot be implemented.
|
||||||
|
|
||||||
|
Thus, although it is painful, you need to explicitly cast values into
|
||||||
|
`toml::value` when you initialize heterogeneous array in C++ code.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// You need to do this when you want to initialize hetero array.
|
||||||
|
toml::value v{
|
||||||
|
toml::value("foo"), toml::value(3.14), toml::value(42),
|
||||||
|
toml::value{1,2,3,4,5}, toml::value{{"key", "value"}}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Breaking Changes from v2
|
## Breaking Changes from v2
|
||||||
|
|
||||||
@ -1494,6 +1714,11 @@ I appreciate the help of the contributors who introduced the great feature to th
|
|||||||
- Added installation script to CMake
|
- Added installation script to CMake
|
||||||
- J.C. Moyer (@jcmoyer)
|
- J.C. Moyer (@jcmoyer)
|
||||||
- Fixed an example code in the documentation
|
- Fixed an example code in the documentation
|
||||||
|
- Jt Freeman (@blockparty-sh)
|
||||||
|
- Fixed feature test macro around `localtime_s`
|
||||||
|
- Suppress warnings in Debug mode
|
||||||
|
- OGAWA Kenichi (@kenichiice)
|
||||||
|
- Suppress warnings on intel compiler
|
||||||
|
|
||||||
## Licensing terms
|
## Licensing terms
|
||||||
|
|
||||||
|
@ -80,10 +80,14 @@ BOOST_AUTO_TEST_CASE(test_detect_conflicting_value)
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(test_detect_inhomogeneous_array)
|
BOOST_AUTO_TEST_CASE(test_detect_inhomogeneous_array)
|
||||||
{
|
{
|
||||||
|
#ifdef TOML11_USE_UNRELEASED_TOML_FEATURES
|
||||||
|
BOOST_TEST_MESSAGE("heterogeneous array will be allowed in the next release");
|
||||||
|
#else
|
||||||
std::istringstream stream(std::string(
|
std::istringstream stream(std::string(
|
||||||
"a = [1, 1.0]\n"
|
"a = [1, 1.0]\n"
|
||||||
));
|
));
|
||||||
BOOST_CHECK_THROW(toml::parse(stream), toml::syntax_error);
|
BOOST_CHECK_THROW(toml::parse(stream), toml::syntax_error);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(test_detect_appending_array_of_table)
|
BOOST_AUTO_TEST_CASE(test_detect_appending_array_of_table)
|
||||||
|
@ -128,3 +128,47 @@ BOOST_AUTO_TEST_CASE(test_multiline_array_value)
|
|||||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "[\"foo\",#comment\n\"b#r\",#comment\n\"b#z\"#comment\n]", toml::value(a));
|
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "[\"foo\",#comment\n\"b#r\",#comment\n\"b#z\"#comment\n]", toml::value(a));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_heterogeneous_array)
|
||||||
|
{
|
||||||
|
#ifndef TOML11_USE_UNRELEASED_TOML_FEATURES
|
||||||
|
BOOST_TEST_MESSAGE("In strict TOML v0.5.0, heterogeneous arrays are not allowed.");
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
array a(5);
|
||||||
|
a[0] = toml::value("foo");
|
||||||
|
a[1] = toml::value(3.14);
|
||||||
|
a[2] = toml::value(42);
|
||||||
|
a[3] = toml::value{toml::value("array"), toml::value("of"), toml::value("hetero-array"), toml::value(1)};
|
||||||
|
a[4] = toml::value{{"key", "value"}};
|
||||||
|
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "[\"foo\", 3.14, 42, [\"array\", \"of\", \"hetero-array\", 1], {key = \"value\"}]", toml::value(a));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
array a(5);
|
||||||
|
a[0] = toml::value("foo");
|
||||||
|
a[1] = toml::value(3.14);
|
||||||
|
a[2] = toml::value(42);
|
||||||
|
a[3] = toml::value{toml::value("array"), toml::value("of"), toml::value("hetero-array"), toml::value(1)};
|
||||||
|
a[4] = toml::value{{"key", "value"}};
|
||||||
|
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "[\"foo\",\n 3.14,\n 42,\n [\"array\", \"of\", \"hetero-array\", 1],\n {key = \"value\"},\n]", toml::value(a));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
array a(5);
|
||||||
|
a[0] = toml::value("foo");
|
||||||
|
a[1] = toml::value(3.14);
|
||||||
|
a[2] = toml::value(42);
|
||||||
|
a[3] = toml::value{toml::value("array"), toml::value("of"), toml::value("hetero-array"), toml::value(1)};
|
||||||
|
a[4] = toml::value{{"key", "value"}};
|
||||||
|
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "[\"foo\",#comment\n 3.14,#comment\n 42,#comment\n [\"array\", \"of\", \"hetero-array\", 1],#comment\n {key = \"value\"},#comment\n]#comment", toml::value(a));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
array a(5);
|
||||||
|
a[0] = toml::value("foo");
|
||||||
|
a[1] = toml::value(3.14);
|
||||||
|
a[2] = toml::value(42);
|
||||||
|
a[3] = toml::value{toml::value("array"), toml::value("of"), toml::value("hetero-array"), toml::value(1)};
|
||||||
|
a[4] = toml::value{{"key", "value"}};
|
||||||
|
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "[\"foo\",\n 3.14,\n 42,\n [\"array\",\n \"of\",\n \"hetero-array\",\n 1],\n {key = \"value\"},\n]", toml::value(a));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
@ -111,3 +111,44 @@ BOOST_AUTO_TEST_CASE(test_literal_ml_string)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_string_add_assign)
|
||||||
|
{
|
||||||
|
// string literal
|
||||||
|
{
|
||||||
|
toml::string str("foo");
|
||||||
|
str += "bar";
|
||||||
|
BOOST_TEST(str.str == "foobar");
|
||||||
|
}
|
||||||
|
// std::string
|
||||||
|
{
|
||||||
|
toml::string str("foo");
|
||||||
|
std::string str2("bar");
|
||||||
|
str += str2;
|
||||||
|
BOOST_TEST(str.str == "foobar");
|
||||||
|
}
|
||||||
|
// toml::string
|
||||||
|
{
|
||||||
|
toml::string str("foo");
|
||||||
|
toml::string str2("bar");
|
||||||
|
str += str2;
|
||||||
|
BOOST_TEST(str.str == "foobar");
|
||||||
|
}
|
||||||
|
#if __cplusplus >= 201703L
|
||||||
|
// std::string_view
|
||||||
|
{
|
||||||
|
toml::string str("foo");
|
||||||
|
str += std::string_view("bar");
|
||||||
|
BOOST_TEST(str == "foobar");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// std::string += toml::string
|
||||||
|
{
|
||||||
|
std::string str("foo");
|
||||||
|
toml::string str2("bar");
|
||||||
|
str += str2;
|
||||||
|
BOOST_TEST(str == "foobar");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -934,3 +934,35 @@ BOOST_AUTO_TEST_CASE(test_value_at)
|
|||||||
BOOST_CHECK_THROW(v1.at(5), std::out_of_range);
|
BOOST_CHECK_THROW(v1.at(5), std::out_of_range);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_value_bracket)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
toml::value v1{{"foo", 42}, {"bar", 3.14}, {"baz", "qux"}};
|
||||||
|
|
||||||
|
BOOST_TEST(v1["foo"].as_integer() == 42);
|
||||||
|
BOOST_TEST(v1["bar"].as_floating() == 3.14);
|
||||||
|
BOOST_TEST(v1["baz"].as_string() == "qux");
|
||||||
|
|
||||||
|
v1["qux"] = 54;
|
||||||
|
BOOST_TEST(v1["qux"].as_integer() == 54);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
toml::value v1;
|
||||||
|
v1["foo"] = 42;
|
||||||
|
|
||||||
|
BOOST_TEST(v1.is_table());
|
||||||
|
BOOST_TEST(v1["foo"].as_integer() == 42);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
toml::value v1{1,2,3,4,5};
|
||||||
|
|
||||||
|
BOOST_TEST(v1[0].as_integer() == 1);
|
||||||
|
BOOST_TEST(v1[1].as_integer() == 2);
|
||||||
|
BOOST_TEST(v1[2].as_integer() == 3);
|
||||||
|
BOOST_TEST(v1[3].as_integer() == 4);
|
||||||
|
BOOST_TEST(v1[4].as_integer() == 5);
|
||||||
|
|
||||||
|
BOOST_CHECK_THROW(v1["foo"], toml::type_error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
64
toml/color.hpp
Normal file
64
toml/color.hpp
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
#ifndef TOML11_COLOR_HPP
|
||||||
|
#define TOML11_COLOR_HPP
|
||||||
|
#include <ostream>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#ifdef TOML11_COLORIZE_ERROR_MESSAGE
|
||||||
|
#define TOML11_ERROR_MESSAGE_COLORIZED true
|
||||||
|
#else
|
||||||
|
#define TOML11_ERROR_MESSAGE_COLORIZED false
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace toml
|
||||||
|
{
|
||||||
|
|
||||||
|
// put ANSI escape sequence to ostream
|
||||||
|
namespace color_ansi
|
||||||
|
{
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
inline int colorize_index()
|
||||||
|
{
|
||||||
|
static const int index = std::ios_base::xalloc();
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
} // detail
|
||||||
|
|
||||||
|
inline std::ostream& colorize(std::ostream& os)
|
||||||
|
{
|
||||||
|
// by default, it is zero.
|
||||||
|
os.iword(detail::colorize_index()) = 1;
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
inline std::ostream& nocolorize(std::ostream& os)
|
||||||
|
{
|
||||||
|
os.iword(detail::colorize_index()) = 0;
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
inline std::ostream& reset (std::ostream& os)
|
||||||
|
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[00m";} return os;}
|
||||||
|
inline std::ostream& bold (std::ostream& os)
|
||||||
|
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[01m";} return os;}
|
||||||
|
inline std::ostream& grey (std::ostream& os)
|
||||||
|
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[30m";} return os;}
|
||||||
|
inline std::ostream& red (std::ostream& os)
|
||||||
|
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[31m";} return os;}
|
||||||
|
inline std::ostream& green (std::ostream& os)
|
||||||
|
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[32m";} return os;}
|
||||||
|
inline std::ostream& yellow (std::ostream& os)
|
||||||
|
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[33m";} return os;}
|
||||||
|
inline std::ostream& blue (std::ostream& os)
|
||||||
|
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[34m";} return os;}
|
||||||
|
inline std::ostream& magenta(std::ostream& os)
|
||||||
|
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[35m";} return os;}
|
||||||
|
inline std::ostream& cyan (std::ostream& os)
|
||||||
|
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[36m";} return os;}
|
||||||
|
inline std::ostream& white (std::ostream& os)
|
||||||
|
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[37m";} return os;}
|
||||||
|
} // color_ansi
|
||||||
|
|
||||||
|
// ANSI escape sequence is the only and default colorization method currently
|
||||||
|
namespace color = color_ansi;
|
||||||
|
|
||||||
|
} // toml
|
||||||
|
#endif// TOML11_COLOR_HPP
|
@ -45,6 +45,7 @@ inline std::string show_char(const char c)
|
|||||||
buf.fill('\0');
|
buf.fill('\0');
|
||||||
const auto r = std::snprintf(
|
const auto r = std::snprintf(
|
||||||
buf.data(), buf.size(), "0x%02x", static_cast<int>(c) & 0xFF);
|
buf.data(), buf.size(), "0x%02x", static_cast<int>(c) & 0xFF);
|
||||||
|
(void) r; // Unused variable warning
|
||||||
assert(r == static_cast<int>(buf.size()) - 1);
|
assert(r == static_cast<int>(buf.size()) - 1);
|
||||||
return std::string(buf.data());
|
return std::string(buf.data());
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ namespace toml
|
|||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
// TODO: find more sophisticated way to handle this
|
// TODO: find more sophisticated way to handle this
|
||||||
#if _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _BSD_SOURCE || _SVID_SOURCE || _POSIX_SOURCE
|
#if _POSIX_C_SOURCE >= 1 || defined(_XOPEN_SOURCE) || defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || defined(_POSIX_SOURCE)
|
||||||
inline std::tm localtime_s(const std::time_t* src)
|
inline std::tm localtime_s(const std::time_t* src)
|
||||||
{
|
{
|
||||||
std::tm dst;
|
std::tm dst;
|
||||||
@ -28,6 +28,13 @@ inline std::tm localtime_s(const std::time_t* src)
|
|||||||
if (!result) { throw std::runtime_error("localtime_r failed."); }
|
if (!result) { throw std::runtime_error("localtime_r failed."); }
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
inline std::tm gmtime_s(const std::time_t* src)
|
||||||
|
{
|
||||||
|
std::tm dst;
|
||||||
|
const auto result = ::gmtime_r(src, &dst);
|
||||||
|
if (!result) { throw std::runtime_error("gmtime_r failed."); }
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
#elif _MSC_VER
|
#elif _MSC_VER
|
||||||
inline std::tm localtime_s(const std::time_t* src)
|
inline std::tm localtime_s(const std::time_t* src)
|
||||||
{
|
{
|
||||||
@ -36,13 +43,26 @@ inline std::tm localtime_s(const std::time_t* src)
|
|||||||
if (result) { throw std::runtime_error("localtime_s failed."); }
|
if (result) { throw std::runtime_error("localtime_s failed."); }
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
#else
|
inline std::tm gmtime_s(const std::time_t* src)
|
||||||
|
{
|
||||||
|
std::tm dst;
|
||||||
|
const auto result = ::gmtime_s(&dst, src);
|
||||||
|
if (result) { throw std::runtime_error("gmtime_s failed."); }
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
#else // fallback. not threadsafe
|
||||||
inline std::tm localtime_s(const std::time_t* src)
|
inline std::tm localtime_s(const std::time_t* src)
|
||||||
{
|
{
|
||||||
const auto result = std::localtime(src);
|
const auto result = std::localtime(src);
|
||||||
if (!result) { throw std::runtime_error("localtime failed."); }
|
if (!result) { throw std::runtime_error("localtime failed."); }
|
||||||
return *result;
|
return *result;
|
||||||
}
|
}
|
||||||
|
inline std::tm gmtime_s(const std::time_t* src)
|
||||||
|
{
|
||||||
|
const auto result = std::gmtime(src);
|
||||||
|
if (!result) { throw std::runtime_error("gmtime failed."); }
|
||||||
|
return *result;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
} // detail
|
} // detail
|
||||||
|
|
||||||
@ -378,10 +398,31 @@ struct local_datetime
|
|||||||
{
|
{
|
||||||
using internal_duration =
|
using internal_duration =
|
||||||
typename std::chrono::system_clock::time_point::duration;
|
typename std::chrono::system_clock::time_point::duration;
|
||||||
|
|
||||||
|
// Normally DST begins at A.M. 3 or 4. If we re-use conversion operator
|
||||||
|
// of local_date and local_time independently, the conversion fails if
|
||||||
|
// it is the day when DST begins or ends. Since local_date considers the
|
||||||
|
// time is 00:00 A.M. and local_time does not consider DST because it
|
||||||
|
// does not have any date information. We need to consider both date and
|
||||||
|
// time information at the same time to convert it correctly.
|
||||||
|
|
||||||
|
std::tm t;
|
||||||
|
t.tm_sec = static_cast<int>(this->time.second);
|
||||||
|
t.tm_min = static_cast<int>(this->time.minute);
|
||||||
|
t.tm_hour = static_cast<int>(this->time.hour);
|
||||||
|
t.tm_mday = static_cast<int>(this->date.day);
|
||||||
|
t.tm_mon = static_cast<int>(this->date.month);
|
||||||
|
t.tm_year = static_cast<int>(this->date.year) - 1900;
|
||||||
|
t.tm_wday = 0; // the value will be ignored
|
||||||
|
t.tm_yday = 0; // the value will be ignored
|
||||||
|
t.tm_isdst = -1;
|
||||||
|
|
||||||
// std::mktime returns date as local time zone. no conversion needed
|
// std::mktime returns date as local time zone. no conversion needed
|
||||||
auto dt = std::chrono::system_clock::time_point(this->date);
|
auto dt = std::chrono::system_clock::from_time_t(std::mktime(&t));
|
||||||
dt += std::chrono::duration_cast<internal_duration>(
|
dt += std::chrono::duration_cast<internal_duration>(
|
||||||
std::chrono::nanoseconds(this->time));
|
std::chrono::milliseconds(this->time.millisecond) +
|
||||||
|
std::chrono::microseconds(this->time.microsecond) +
|
||||||
|
std::chrono::nanoseconds (this->time.nanosecond));
|
||||||
return dt;
|
return dt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -447,40 +488,71 @@ struct offset_datetime
|
|||||||
: date(dt.date), time(dt.time), offset(o)
|
: date(dt.date), time(dt.time), offset(o)
|
||||||
{}
|
{}
|
||||||
explicit offset_datetime(const local_datetime& ld)
|
explicit offset_datetime(const local_datetime& ld)
|
||||||
: date(ld.date), time(ld.time), offset(get_local_offset())
|
: date(ld.date), time(ld.time), offset(get_local_offset(nullptr))
|
||||||
|
// use the current local timezone offset
|
||||||
{}
|
{}
|
||||||
explicit offset_datetime(const std::chrono::system_clock::time_point& tp)
|
explicit offset_datetime(const std::chrono::system_clock::time_point& tp)
|
||||||
: offset_datetime(local_datetime(tp))
|
: offset(0, 0) // use gmtime
|
||||||
{}
|
{
|
||||||
|
const auto timet = std::chrono::system_clock::to_time_t(tp);
|
||||||
|
const auto tm = detail::gmtime_s(&timet);
|
||||||
|
this->date = local_date(tm);
|
||||||
|
this->time = local_time(tm);
|
||||||
|
}
|
||||||
explicit offset_datetime(const std::time_t& t)
|
explicit offset_datetime(const std::time_t& t)
|
||||||
: offset_datetime(local_datetime(t))
|
: offset(0, 0) // use gmtime
|
||||||
{}
|
{
|
||||||
|
const auto tm = detail::gmtime_s(&t);
|
||||||
|
this->date = local_date(tm);
|
||||||
|
this->time = local_time(tm);
|
||||||
|
}
|
||||||
explicit offset_datetime(const std::tm& t)
|
explicit offset_datetime(const std::tm& t)
|
||||||
: offset_datetime(local_datetime(t))
|
: offset(0, 0) // assume gmtime
|
||||||
{}
|
{
|
||||||
|
this->date = local_date(t);
|
||||||
|
this->time = local_time(t);
|
||||||
|
}
|
||||||
|
|
||||||
operator std::chrono::system_clock::time_point() const
|
operator std::chrono::system_clock::time_point() const
|
||||||
{
|
{
|
||||||
// get date-time
|
// get date-time
|
||||||
using internal_duration =
|
using internal_duration =
|
||||||
typename std::chrono::system_clock::time_point::duration;
|
typename std::chrono::system_clock::time_point::duration;
|
||||||
std::chrono::system_clock::time_point tp =
|
|
||||||
std::chrono::system_clock::time_point(this->date) +
|
|
||||||
std::chrono::duration_cast<internal_duration>(
|
|
||||||
std::chrono::nanoseconds(this->time));
|
|
||||||
|
|
||||||
// get date-time in UTC. let's say we are in +09:00 (JPN).
|
// first, convert it to local date-time information in the same way as
|
||||||
// writing 12:00:00 in +09:00 means 03:00:00Z. to represent
|
// local_datetime does. later we will use time_t to adjust time offset.
|
||||||
// 12:00:00Z, first we need to add +09:00.
|
std::tm t;
|
||||||
const auto ofs = get_local_offset();
|
t.tm_sec = static_cast<int>(this->time.second);
|
||||||
|
t.tm_min = static_cast<int>(this->time.minute);
|
||||||
|
t.tm_hour = static_cast<int>(this->time.hour);
|
||||||
|
t.tm_mday = static_cast<int>(this->date.day);
|
||||||
|
t.tm_mon = static_cast<int>(this->date.month);
|
||||||
|
t.tm_year = static_cast<int>(this->date.year) - 1900;
|
||||||
|
t.tm_wday = 0; // the value will be ignored
|
||||||
|
t.tm_yday = 0; // the value will be ignored
|
||||||
|
t.tm_isdst = -1;
|
||||||
|
const std::time_t tp_loc = std::mktime(std::addressof(t));
|
||||||
|
|
||||||
|
auto tp = std::chrono::system_clock::from_time_t(tp_loc);
|
||||||
|
tp += std::chrono::duration_cast<internal_duration>(
|
||||||
|
std::chrono::milliseconds(this->time.millisecond) +
|
||||||
|
std::chrono::microseconds(this->time.microsecond) +
|
||||||
|
std::chrono::nanoseconds (this->time.nanosecond));
|
||||||
|
|
||||||
|
// Since mktime uses local time zone, it should be corrected.
|
||||||
|
// `12:00:00+09:00` means `03:00:00Z`. So mktime returns `03:00:00Z` if
|
||||||
|
// we are in `+09:00` timezone. To represent `12:00:00Z` there, we need
|
||||||
|
// to add `+09:00` to `03:00:00Z`.
|
||||||
|
// Here, it uses the time_t converted from date-time info to handle
|
||||||
|
// daylight saving time.
|
||||||
|
const auto ofs = get_local_offset(std::addressof(tp_loc));
|
||||||
tp += std::chrono::hours (ofs.hour);
|
tp += std::chrono::hours (ofs.hour);
|
||||||
tp += std::chrono::minutes(ofs.minute);
|
tp += std::chrono::minutes(ofs.minute);
|
||||||
|
|
||||||
// here, tp represents 12:00:00 in UTC but we have offset information.
|
// We got `12:00:00Z` by correcting local timezone applied by mktime.
|
||||||
// we need to subtract it. For example, let's say the input is
|
// Then we will apply the offset. Let's say `12:00:00-08:00` is given.
|
||||||
// 12:00:00-08:00. now we have tp = 12:00:00Z as a result of the above
|
// And now, we have `12:00:00Z`. `12:00:00-08:00` means `20:00:00Z`.
|
||||||
// conversion. But the actual time we need to return is 20:00:00Z
|
// So we need to subtract the offset.
|
||||||
// because of -08:00.
|
|
||||||
tp -= std::chrono::minutes(this->offset);
|
tp -= std::chrono::minutes(this->offset);
|
||||||
return tp;
|
return tp;
|
||||||
}
|
}
|
||||||
@ -500,11 +572,10 @@ struct offset_datetime
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
static time_offset get_local_offset()
|
static time_offset get_local_offset(const std::time_t* tp)
|
||||||
{
|
{
|
||||||
// get current timezone
|
// get local timezone with the same date-time information as mktime
|
||||||
const auto tmp1 = std::time(nullptr);
|
const auto t = detail::localtime_s(tp);
|
||||||
const auto t = detail::localtime_s(&tmp1);
|
|
||||||
|
|
||||||
std::array<char, 6> buf;
|
std::array<char, 6> buf;
|
||||||
const auto result = std::strftime(buf.data(), 6, "%z", &t); // +hhmm\0
|
const auto result = std::strftime(buf.data(), 6, "%z", &t); // +hhmm\0
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// Distributed under the MIT License.
|
// Distributed under the MIT License.
|
||||||
#ifndef TOML11_EXCEPTION_HPP
|
#ifndef TOML11_EXCEPTION_HPP
|
||||||
#define TOML11_EXCEPTION_HPP
|
#define TOML11_EXCEPTION_HPP
|
||||||
|
#include "source_location.hpp"
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@ -11,15 +12,21 @@ namespace toml
|
|||||||
struct exception : public std::exception
|
struct exception : public std::exception
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
exception(const source_location& loc): loc_(loc) {}
|
||||||
virtual ~exception() noexcept override = default;
|
virtual ~exception() noexcept override = default;
|
||||||
virtual const char* what() const noexcept override {return "";}
|
virtual const char* what() const noexcept override {return "";}
|
||||||
|
virtual source_location const& location() const noexcept {return loc_;}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
source_location loc_;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct syntax_error : public toml::exception
|
struct syntax_error : public toml::exception
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit syntax_error(const std::string& what_arg) : what_(what_arg){}
|
explicit syntax_error(const std::string& what_arg, const source_location& loc)
|
||||||
explicit syntax_error(const char* what_arg) : what_(what_arg){}
|
: exception(loc), what_(what_arg)
|
||||||
|
{}
|
||||||
virtual ~syntax_error() noexcept override = default;
|
virtual ~syntax_error() noexcept override = default;
|
||||||
virtual const char* what() const noexcept override {return what_.c_str();}
|
virtual const char* what() const noexcept override {return what_.c_str();}
|
||||||
|
|
||||||
@ -30,8 +37,9 @@ struct syntax_error : public toml::exception
|
|||||||
struct type_error : public toml::exception
|
struct type_error : public toml::exception
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit type_error(const std::string& what_arg) : what_(what_arg){}
|
explicit type_error(const std::string& what_arg, const source_location& loc)
|
||||||
explicit type_error(const char* what_arg) : what_(what_arg){}
|
: exception(loc), what_(what_arg)
|
||||||
|
{}
|
||||||
virtual ~type_error() noexcept override = default;
|
virtual ~type_error() noexcept override = default;
|
||||||
virtual const char* what() const noexcept override {return what_.c_str();}
|
virtual const char* what() const noexcept override {return what_.c_str();}
|
||||||
|
|
||||||
@ -42,10 +50,12 @@ struct type_error : public toml::exception
|
|||||||
struct internal_error : public toml::exception
|
struct internal_error : public toml::exception
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit internal_error(const std::string& what_arg) : what_(what_arg){}
|
explicit internal_error(const std::string& what_arg, const source_location& loc)
|
||||||
explicit internal_error(const char* what_arg) : what_(what_arg){}
|
: exception(loc), what_(what_arg)
|
||||||
|
{}
|
||||||
virtual ~internal_error() noexcept override = default;
|
virtual ~internal_error() noexcept override = default;
|
||||||
virtual const char* what() const noexcept override {return what_.c_str();}
|
virtual const char* what() const noexcept override {return what_.c_str();}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string what_;
|
std::string what_;
|
||||||
};
|
};
|
||||||
|
24
toml/get.hpp
24
toml/get.hpp
@ -186,11 +186,11 @@ get(const basic_value<C, M, V>& v)
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
throw type_error(detail::format_underline("[error] toml::value "
|
throw type_error(detail::format_underline("toml::value: "
|
||||||
"bad_cast to std::chrono::system_clock::time_point", {
|
"bad_cast to std::chrono::system_clock::time_point", {
|
||||||
{std::addressof(detail::get_region(v)),
|
{std::addressof(detail::get_region(v)),
|
||||||
concat_to_string("the actual type is ", v.type())}
|
concat_to_string("the actual type is ", v.type())}
|
||||||
}));
|
}), v.location());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -301,7 +301,7 @@ get(const basic_value<C, M, V>& v)
|
|||||||
if(ar.size() != container.size())
|
if(ar.size() != container.size())
|
||||||
{
|
{
|
||||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||||
"[erorr] toml::get specified container size is ", container.size(),
|
"toml::get: specified container size is ", container.size(),
|
||||||
" but there are ", ar.size(), " elements in toml array."), {
|
" but there are ", ar.size(), " elements in toml array."), {
|
||||||
{std::addressof(detail::get_region(v)), "here"}
|
{std::addressof(detail::get_region(v)), "here"}
|
||||||
}));
|
}));
|
||||||
@ -326,7 +326,7 @@ get(const basic_value<C, M, V>& v)
|
|||||||
if(ar.size() != 2)
|
if(ar.size() != 2)
|
||||||
{
|
{
|
||||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||||
"[erorr] toml::get specified std::pair but there are ", ar.size(),
|
"toml::get: specified std::pair but there are ", ar.size(),
|
||||||
" elements in toml array."), {
|
" elements in toml array."), {
|
||||||
{std::addressof(detail::get_region(v)), "here"}
|
{std::addressof(detail::get_region(v)), "here"}
|
||||||
}));
|
}));
|
||||||
@ -357,8 +357,8 @@ get(const basic_value<C, M, V>& v)
|
|||||||
if(ar.size() != std::tuple_size<T>::value)
|
if(ar.size() != std::tuple_size<T>::value)
|
||||||
{
|
{
|
||||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||||
"[erorr] toml::get specified std::tuple with ",
|
"toml::get: specified std::tuple with ",
|
||||||
std::tuple_size<T>::value, "elements, but there are ", ar.size(),
|
std::tuple_size<T>::value, " elements, but there are ", ar.size(),
|
||||||
" elements in toml array."), {
|
" elements in toml array."), {
|
||||||
{std::addressof(detail::get_region(v)), "here"}
|
{std::addressof(detail::get_region(v)), "here"}
|
||||||
}));
|
}));
|
||||||
@ -430,7 +430,7 @@ basic_value<C, M, V> const& find(const basic_value<C, M, V>& v, const key& ky)
|
|||||||
if(tab.count(ky) == 0)
|
if(tab.count(ky) == 0)
|
||||||
{
|
{
|
||||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||||
"[error] key \"", ky, "\" not found"), {
|
"key \"", ky, "\" not found"), {
|
||||||
{std::addressof(detail::get_region(v)), "in this table"}
|
{std::addressof(detail::get_region(v)), "in this table"}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@ -444,7 +444,7 @@ basic_value<C, M, V>& find(basic_value<C, M, V>& v, const key& ky)
|
|||||||
if(tab.count(ky) == 0)
|
if(tab.count(ky) == 0)
|
||||||
{
|
{
|
||||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||||
"[error] key \"", ky, "\" not found"), {
|
"key \"", ky, "\" not found"), {
|
||||||
{std::addressof(detail::get_region(v)), "in this table"}
|
{std::addressof(detail::get_region(v)), "in this table"}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@ -458,7 +458,7 @@ basic_value<C, M, V> find(basic_value<C, M, V>&& v, const key& ky)
|
|||||||
if(tab.count(ky) == 0)
|
if(tab.count(ky) == 0)
|
||||||
{
|
{
|
||||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||||
"[error] key \"", ky, "\" not found"), {
|
"key \"", ky, "\" not found"), {
|
||||||
{std::addressof(detail::get_region(v)), "in this table"}
|
{std::addressof(detail::get_region(v)), "in this table"}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@ -523,7 +523,7 @@ find(const basic_value<C, M, V>& v, const key& ky)
|
|||||||
if(tab.count(ky) == 0)
|
if(tab.count(ky) == 0)
|
||||||
{
|
{
|
||||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||||
"[error] key \"", ky, "\" not found"), {
|
"key \"", ky, "\" not found"), {
|
||||||
{std::addressof(detail::get_region(v)), "in this table"}
|
{std::addressof(detail::get_region(v)), "in this table"}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@ -539,7 +539,7 @@ find(basic_value<C, M, V>& v, const key& ky)
|
|||||||
if(tab.count(ky) == 0)
|
if(tab.count(ky) == 0)
|
||||||
{
|
{
|
||||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||||
"[error] key \"", ky, "\" not found"), {
|
"key \"", ky, "\" not found"), {
|
||||||
{std::addressof(detail::get_region(v)), "in this table"}
|
{std::addressof(detail::get_region(v)), "in this table"}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@ -555,7 +555,7 @@ find(basic_value<C, M, V>&& v, const key& ky)
|
|||||||
if(tab.count(ky) == 0)
|
if(tab.count(ky) == 0)
|
||||||
{
|
{
|
||||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||||
"[error] key \"", ky, "\" not found"), {
|
"key \"", ky, "\" not found"), {
|
||||||
{std::addressof(detail::get_region(v)), "in this table"}
|
{std::addressof(detail::get_region(v)), "in this table"}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,8 @@ inline ::toml::value operator"" _toml(const char* str, std::size_t len)
|
|||||||
}
|
}
|
||||||
else // none of them.
|
else // none of them.
|
||||||
{
|
{
|
||||||
throw ::toml::syntax_error(data.unwrap_err());
|
throw ::toml::syntax_error(data.unwrap_err(),
|
||||||
|
source_location(std::addressof(loc)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
391
toml/parser.hpp
391
toml/parser.hpp
File diff suppressed because it is too large
Load Diff
@ -2,7 +2,6 @@
|
|||||||
// Distributed under the MIT License.
|
// Distributed under the MIT License.
|
||||||
#ifndef TOML11_REGION_HPP
|
#ifndef TOML11_REGION_HPP
|
||||||
#define TOML11_REGION_HPP
|
#define TOML11_REGION_HPP
|
||||||
#include "exception.hpp"
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@ -10,6 +9,7 @@
|
|||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include "color.hpp"
|
||||||
|
|
||||||
namespace toml
|
namespace toml
|
||||||
{
|
{
|
||||||
@ -231,11 +231,10 @@ struct region final : public region_base
|
|||||||
|
|
||||||
region& operator+=(const region& other)
|
region& operator+=(const region& other)
|
||||||
{
|
{
|
||||||
if(this->begin() != other.begin() || this->end() != other.end() ||
|
// different regions cannot be concatenated
|
||||||
this->last_ != other.first_)
|
assert(this->begin() == other.begin() && this->end() == other.end() &&
|
||||||
{
|
this->last_ == other.first_);
|
||||||
throw internal_error("invalid region concatenation");
|
|
||||||
}
|
|
||||||
this->last_ = other.last_;
|
this->last_ = other.last_;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@ -420,7 +419,8 @@ struct region final : public region_base
|
|||||||
// to show a better error message.
|
// to show a better error message.
|
||||||
inline std::string format_underline(const std::string& message,
|
inline std::string format_underline(const std::string& message,
|
||||||
const std::vector<std::pair<region_base const*, std::string>>& reg_com,
|
const std::vector<std::pair<region_base const*, std::string>>& reg_com,
|
||||||
const std::vector<std::string>& helps = {})
|
const std::vector<std::string>& helps = {},
|
||||||
|
const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED)
|
||||||
{
|
{
|
||||||
assert(!reg_com.empty());
|
assert(!reg_com.empty());
|
||||||
|
|
||||||
@ -434,7 +434,27 @@ inline std::string format_underline(const std::string& message,
|
|||||||
)->first->line_num().size());
|
)->first->line_num().size());
|
||||||
|
|
||||||
std::ostringstream retval;
|
std::ostringstream retval;
|
||||||
retval << message << '\n';
|
|
||||||
|
if(colorize)
|
||||||
|
{
|
||||||
|
retval << color::colorize; // turn on ANSI color
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXX
|
||||||
|
// Here, before `colorize` support, it does not output `[error]` prefix
|
||||||
|
// automatically. So some user may output it manually and this change may
|
||||||
|
// duplicate the prefix. To avoid it, check the first 7 characters and
|
||||||
|
// if it is "[error]", it removes that part from the message shown.
|
||||||
|
if(message.size() > 7 && message.substr(0, 7) == "[error]")
|
||||||
|
{
|
||||||
|
retval << color::bold << color::red << "[error]" << color::reset
|
||||||
|
<< color::bold << message.substr(7) << color::reset << '\n';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
retval << color::bold << color::red << "[error] " << color::reset
|
||||||
|
<< color::bold << message << color::reset << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
for(auto iter = reg_com.begin(); iter != reg_com.end(); ++iter)
|
for(auto iter = reg_com.begin(); iter != reg_com.end(); ++iter)
|
||||||
{
|
{
|
||||||
@ -442,34 +462,42 @@ inline std::string format_underline(const std::string& message,
|
|||||||
if(iter != reg_com.begin() &&
|
if(iter != reg_com.begin() &&
|
||||||
std::prev(iter)->first->name() == iter->first->name())
|
std::prev(iter)->first->name() == iter->first->name())
|
||||||
{
|
{
|
||||||
retval << "\n ...\n";
|
retval << color::bold << color::blue << "\n ...\n" << color::reset;
|
||||||
}
|
}
|
||||||
else // if filename differs, print " --> filename.toml"
|
else // if filename differs, print " --> filename.toml"
|
||||||
{
|
{
|
||||||
if(iter != reg_com.begin()) {retval << '\n';}
|
if(iter != reg_com.begin()) {retval << '\n';}
|
||||||
retval << " --> " << iter->first->name() << '\n';
|
retval << color::bold << color::blue << " --> " << color::reset
|
||||||
|
<< iter->first->name() << '\n';
|
||||||
|
// add one almost-empty line for readability
|
||||||
|
retval << make_string(static_cast<std::size_t>(line_num_width + 1), ' ')
|
||||||
|
<< color::bold << color::blue << " | " << color::reset << '\n';
|
||||||
}
|
}
|
||||||
const region_base* const reg = iter->first;
|
const region_base* const reg = iter->first;
|
||||||
const std::string& comment = iter->second;
|
const std::string& comment = iter->second;
|
||||||
|
|
||||||
retval << ' ' << std::setw(line_num_width) << reg->line_num();
|
retval << ' ' << color::bold << color::blue << std::setw(line_num_width)
|
||||||
retval << " | " << reg->line() << '\n';
|
<< std::right << reg->line_num() << " | " << color::reset
|
||||||
retval << make_string(static_cast<std::size_t>(line_num_width + 1), ' ');
|
<< reg->line() << '\n';
|
||||||
retval << " | " << make_string(reg->before(), ' ');
|
|
||||||
|
retval << make_string(static_cast<std::size_t>(line_num_width + 1), ' ')
|
||||||
|
<< color::bold << color::blue << " | " << color::reset
|
||||||
|
<< make_string(reg->before(), ' ');
|
||||||
|
|
||||||
if(reg->size() == 1)
|
if(reg->size() == 1)
|
||||||
{
|
{
|
||||||
// invalid
|
// invalid
|
||||||
// ^------
|
// ^------
|
||||||
retval << '^';
|
retval << color::bold << color::red
|
||||||
retval << make_string(reg->after(), '-');
|
<< '^' << make_string(reg->after(), '-') << color::reset;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// invalid
|
// invalid
|
||||||
// ~~~~~~~
|
// ~~~~~~~
|
||||||
const auto underline_len = std::min(reg->size(), reg->line().size());
|
const auto underline_len = std::min(reg->size(), reg->line().size());
|
||||||
retval << make_string(underline_len, '~');
|
retval << color::bold << color::red
|
||||||
|
<< make_string(underline_len, '~') << color::reset;
|
||||||
}
|
}
|
||||||
retval << ' ';
|
retval << ' ';
|
||||||
retval << comment;
|
retval << comment;
|
||||||
@ -479,10 +507,10 @@ inline std::string format_underline(const std::string& message,
|
|||||||
{
|
{
|
||||||
retval << '\n';
|
retval << '\n';
|
||||||
retval << make_string(static_cast<std::size_t>(line_num_width + 1), ' ');
|
retval << make_string(static_cast<std::size_t>(line_num_width + 1), ' ');
|
||||||
retval << " | ";
|
retval << color::bold << color::blue << " | " << color::reset;
|
||||||
for(const auto help : helps)
|
for(const auto help : helps)
|
||||||
{
|
{
|
||||||
retval << "\nHint: ";
|
retval << color::bold << "\nHint: " << color::reset;
|
||||||
retval << help;
|
retval << help;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -118,8 +118,14 @@ struct serializer
|
|||||||
{
|
{
|
||||||
return token; // there is no exponent part. just return it.
|
return token; // there is no exponent part. just return it.
|
||||||
}
|
}
|
||||||
|
#ifdef TOML11_USE_UNRELEASED_TOML_FEATURES
|
||||||
// zero-prefix in an exponent is NOT allowed in TOML.
|
// Although currently it is not released yet, TOML will allow
|
||||||
|
// zero-prefix in an exponent part such as 1.234e+01.
|
||||||
|
// The following code removes the zero prefixes.
|
||||||
|
// If the feature is activated, the following codes can be skipped.
|
||||||
|
return token;
|
||||||
|
#endif
|
||||||
|
// zero-prefix in an exponent is NOT allowed in TOML v0.5.0.
|
||||||
// remove it if it exists.
|
// remove it if it exists.
|
||||||
bool sign_exists = false;
|
bool sign_exists = false;
|
||||||
std::size_t zero_prefix = 0;
|
std::size_t zero_prefix = 0;
|
||||||
|
@ -48,7 +48,11 @@ struct source_location
|
|||||||
{
|
{
|
||||||
if(reg)
|
if(reg)
|
||||||
{
|
{
|
||||||
line_num_ = static_cast<std::uint_least32_t>(std::stoul(reg->line_num()));
|
if(reg->line_num() != detail::region_base().line_num())
|
||||||
|
{
|
||||||
|
line_num_ = static_cast<std::uint_least32_t>(
|
||||||
|
std::stoul(reg->line_num()));
|
||||||
|
}
|
||||||
column_num_ = static_cast<std::uint_least32_t>(reg->before() + 1);
|
column_num_ = static_cast<std::uint_least32_t>(reg->before() + 1);
|
||||||
region_size_ = static_cast<std::uint_least32_t>(reg->size());
|
region_size_ = static_cast<std::uint_least32_t>(reg->size());
|
||||||
file_name_ = reg->name();
|
file_name_ = reg->name();
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// Distributed under the MIT License.
|
// Distributed under the MIT License.
|
||||||
#ifndef TOML11_STRING_HPP
|
#ifndef TOML11_STRING_HPP
|
||||||
#define TOML11_STRING_HPP
|
#define TOML11_STRING_HPP
|
||||||
|
#include <algorithm>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#if __cplusplus >= 201703L
|
#if __cplusplus >= 201703L
|
||||||
@ -45,6 +46,11 @@ struct string
|
|||||||
operator std::string const& () const& noexcept {return str;}
|
operator std::string const& () const& noexcept {return str;}
|
||||||
operator std::string&& () && noexcept {return std::move(str);}
|
operator std::string&& () && noexcept {return std::move(str);}
|
||||||
|
|
||||||
|
string& operator+=(const char* rhs) {str += rhs; return *this;}
|
||||||
|
string& operator+=(const char rhs) {str += rhs; return *this;}
|
||||||
|
string& operator+=(const std::string& rhs) {str += rhs; return *this;}
|
||||||
|
string& operator+=(const string& rhs) {str += rhs.str; return *this;}
|
||||||
|
|
||||||
#if __cplusplus >= 201703L
|
#if __cplusplus >= 201703L
|
||||||
explicit string(std::string_view s): kind(string_t::basic), str(s){}
|
explicit string(std::string_view s): kind(string_t::basic), str(s){}
|
||||||
string(std::string_view s, string_t k): kind(k), str(s){}
|
string(std::string_view s, string_t k): kind(k), str(s){}
|
||||||
@ -54,6 +60,8 @@ struct string
|
|||||||
|
|
||||||
explicit operator std::string_view() const noexcept
|
explicit operator std::string_view() const noexcept
|
||||||
{return std::string_view(str);}
|
{return std::string_view(str);}
|
||||||
|
|
||||||
|
string& operator+=(const std::string_view& rhs) {str += rhs; return *this;}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
string_t kind;
|
string_t kind;
|
||||||
|
@ -105,7 +105,7 @@ struct has_into_toml_method
|
|||||||
: decltype(has_into_toml_method_impl::check<T>(nullptr)){};
|
: decltype(has_into_toml_method_impl::check<T>(nullptr)){};
|
||||||
|
|
||||||
#ifdef __INTEL_COMPILER
|
#ifdef __INTEL_COMPILER
|
||||||
#undef decltype(...)
|
#undef decltype
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
@ -32,10 +32,10 @@ template<value_t Expected,
|
|||||||
throw_bad_cast(value_t actual, const ::toml::basic_value<C, T, A>& v)
|
throw_bad_cast(value_t actual, const ::toml::basic_value<C, T, A>& v)
|
||||||
{
|
{
|
||||||
throw type_error(detail::format_underline(concat_to_string(
|
throw type_error(detail::format_underline(concat_to_string(
|
||||||
"[error] toml::value bad_cast to ", Expected), {
|
"toml::value: bad_cast to ", Expected), {
|
||||||
{std::addressof(get_region(v)),
|
{std::addressof(get_region(v)),
|
||||||
concat_to_string("the actual type is ", actual)}
|
concat_to_string("the actual type is ", actual)}
|
||||||
}));
|
}), v.location());
|
||||||
}
|
}
|
||||||
|
|
||||||
// switch by `value_t` and call the corresponding `value::as_xxx()`. {{{
|
// switch by `value_t` and call the corresponding `value::as_xxx()`. {{{
|
||||||
@ -1579,6 +1579,14 @@ class basic_value
|
|||||||
{
|
{
|
||||||
return this->as_table().at(k);
|
return this->as_table().at(k);
|
||||||
}
|
}
|
||||||
|
value_type& operator[](const key& k)
|
||||||
|
{
|
||||||
|
if(this->is_uninitialized())
|
||||||
|
{
|
||||||
|
*this = table_type{};
|
||||||
|
}
|
||||||
|
return this->as_table()[k];
|
||||||
|
}
|
||||||
|
|
||||||
value_type& at(const std::size_t idx)
|
value_type& at(const std::size_t idx)
|
||||||
{
|
{
|
||||||
@ -1589,6 +1597,15 @@ class basic_value
|
|||||||
return this->as_array().at(idx);
|
return this->as_array().at(idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
value_type& operator[](const std::size_t idx) noexcept
|
||||||
|
{
|
||||||
|
return this->as_array(std::nothrow)[idx];
|
||||||
|
}
|
||||||
|
value_type const& operator[](const std::size_t idx) const noexcept
|
||||||
|
{
|
||||||
|
return this->as_array(std::nothrow)[idx];
|
||||||
|
}
|
||||||
|
|
||||||
source_location location() const
|
source_location location() const
|
||||||
{
|
{
|
||||||
return source_location(this->region_info_.get());
|
return source_location(this->region_info_.get());
|
||||||
@ -1843,25 +1860,27 @@ operator>=(const basic_value<C, T, A>& lhs, const basic_value<C, T, A>& rhs)
|
|||||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||||
inline std::string format_error(const std::string& err_msg,
|
inline std::string format_error(const std::string& err_msg,
|
||||||
const basic_value<C, T, A>& v, const std::string& comment,
|
const basic_value<C, T, A>& v, const std::string& comment,
|
||||||
std::vector<std::string> hints = {})
|
std::vector<std::string> hints = {},
|
||||||
|
const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED)
|
||||||
{
|
{
|
||||||
return detail::format_underline(err_msg,
|
return detail::format_underline(err_msg,
|
||||||
std::vector<std::pair<detail::region_base const*, std::string>>{
|
std::vector<std::pair<detail::region_base const*, std::string>>{
|
||||||
{std::addressof(detail::get_region(v)), comment}
|
{std::addressof(detail::get_region(v)), comment}
|
||||||
}, std::move(hints));
|
}, std::move(hints), colorize);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||||
inline std::string format_error(const std::string& err_msg,
|
inline std::string format_error(const std::string& err_msg,
|
||||||
const toml::basic_value<C, T, A>& v1, const std::string& comment1,
|
const toml::basic_value<C, T, A>& v1, const std::string& comment1,
|
||||||
const toml::basic_value<C, T, A>& v2, const std::string& comment2,
|
const toml::basic_value<C, T, A>& v2, const std::string& comment2,
|
||||||
std::vector<std::string> hints = {})
|
std::vector<std::string> hints = {},
|
||||||
|
const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED)
|
||||||
{
|
{
|
||||||
return detail::format_underline(err_msg,
|
return detail::format_underline(err_msg,
|
||||||
std::vector<std::pair<detail::region_base const*, std::string>>{
|
std::vector<std::pair<detail::region_base const*, std::string>>{
|
||||||
{std::addressof(detail::get_region(v1)), comment1},
|
{std::addressof(detail::get_region(v1)), comment1},
|
||||||
{std::addressof(detail::get_region(v2)), comment2}
|
{std::addressof(detail::get_region(v2)), comment2}
|
||||||
}, std::move(hints));
|
}, std::move(hints), colorize);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||||
@ -1869,14 +1888,15 @@ inline std::string format_error(const std::string& err_msg,
|
|||||||
const toml::basic_value<C, T, A>& v1, const std::string& comment1,
|
const toml::basic_value<C, T, A>& v1, const std::string& comment1,
|
||||||
const toml::basic_value<C, T, A>& v2, const std::string& comment2,
|
const toml::basic_value<C, T, A>& v2, const std::string& comment2,
|
||||||
const toml::basic_value<C, T, A>& v3, const std::string& comment3,
|
const toml::basic_value<C, T, A>& v3, const std::string& comment3,
|
||||||
std::vector<std::string> hints = {})
|
std::vector<std::string> hints = {},
|
||||||
|
const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED)
|
||||||
{
|
{
|
||||||
return detail::format_underline(err_msg,
|
return detail::format_underline(err_msg,
|
||||||
std::vector<std::pair<detail::region_base const*, std::string>>{
|
std::vector<std::pair<detail::region_base const*, std::string>>{
|
||||||
{std::addressof(detail::get_region(v1)), comment1},
|
{std::addressof(detail::get_region(v1)), comment1},
|
||||||
{std::addressof(detail::get_region(v2)), comment2},
|
{std::addressof(detail::get_region(v2)), comment2},
|
||||||
{std::addressof(detail::get_region(v3)), comment3}
|
{std::addressof(detail::get_region(v3)), comment3}
|
||||||
}, std::move(hints));
|
}, std::move(hints), colorize);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Visitor, typename C,
|
template<typename Visitor, typename C,
|
||||||
|
Loading…
Reference in New Issue
Block a user