mirror of
https://gitlab.freedesktop.org/monado/monado.git
synced 2024-12-28 18:46:18 +00:00
external/valve-file-vdf: update to 1.0.0
https://github.com/TinyTinni/ValveFileVDF/releases/tag/v1.0.0 Part-of: <https://gitlab.freedesktop.org/monado/monado/-/merge_requests/2266>
This commit is contained in:
parent
f29275ced2
commit
a628e14dd0
|
@ -19,7 +19,7 @@
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
# Comma-delimited list of words for codespell to not try to correct.
|
# Comma-delimited list of words for codespell to not try to correct.
|
||||||
IGNORE_WORDS_LIST="ang,sinc,sie,stoll,wil,daa,localy,od,ser,unknwn,parm,inflight,marge,devault,errorprone"
|
IGNORE_WORDS_LIST="ang,sinc,sie,stoll,wil,daa,localy,od,ser,unknwn,parm,inflight,marge,devault,errorprone,childs"
|
||||||
IGNORE_REGEX="\b(pEvent|inout|Kimera)\b"
|
IGNORE_REGEX="\b(pEvent|inout|Kimera)\b"
|
||||||
|
|
||||||
SCRIPTDIR=$(cd "$(dirname "$0")" && pwd)
|
SCRIPTDIR=$(cd "$(dirname "$0")" && pwd)
|
||||||
|
|
21
src/external/valve-file-vdf/LICENSE
vendored
Normal file
21
src/external/valve-file-vdf/LICENSE
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) Matthias Moeller 2016 m_moeller@live.de
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
280
src/external/valve-file-vdf/Readme.md
vendored
280
src/external/valve-file-vdf/Readme.md
vendored
|
@ -1,280 +0,0 @@
|
||||||
Upstream source - https://github.com/TinyTinni/ValveFileVDF
|
|
||||||
|
|
||||||
# Valve Data Format (.vdf) Reader and Writer in C++
|
|
||||||
|
|
||||||
[![CMake](https://github.com/TinyTinni/ValveFileVDF/actions/workflows/cmake.yml/badge.svg)](https://github.com/TinyTinni/ValveFileVDF/actions/workflows/cmake.yml)
|
|
||||||
|
|
||||||
Valve uses its own JSON-like data format: [KeyValue, also known as vdf.](https://developer.valvesoftware.com/wiki/KeyValues)
|
|
||||||
e.g. in game manifest files or as SteamCMD output.
|
|
||||||
This header-only file provides a parser and writer to load and save the given data.
|
|
||||||
|
|
||||||
## Features:
|
|
||||||
- read and write vdf data in C++
|
|
||||||
- build-in encodings: `char` and `wchar_t`
|
|
||||||
- supports custom character sets
|
|
||||||
- support for C++ (//) and C (/**/) comments
|
|
||||||
- `#include`/`#base` keyword (note: searches for files in the current working directory)
|
|
||||||
- platform independent
|
|
||||||
- header-only
|
|
||||||
|
|
||||||
## Requirements
|
|
||||||
- C++11
|
|
||||||
|
|
||||||
## Test Requirements
|
|
||||||
- C++14 (uses [catch2](https://github.com/catchorg/Catch2))
|
|
||||||
|
|
||||||
(works with the C++11 features of vs120/"Visual Studio 2013" and newer)
|
|
||||||
|
|
||||||
## How-To Use
|
|
||||||
First, you have to include the main file `vdf-Parser.h`.
|
|
||||||
This file provides several functions and data-structures which are
|
|
||||||
in the namespace `tyti::vdf`.
|
|
||||||
|
|
||||||
All functions and data structures supports wide characters.
|
|
||||||
The wide character data structure is indicated by the commonly known `w`-prefix.
|
|
||||||
Functions are templates and don't need a prefix.
|
|
||||||
|
|
||||||
To read an file, create a stream e.g. `std::ifsteam` or `std::wifstream`
|
|
||||||
and call the `tyti::vdf::read` function.
|
|
||||||
```c++
|
|
||||||
std::ifstream file("PathToMyFile");
|
|
||||||
auto root = tyti::vdf::read(file);
|
|
||||||
```
|
|
||||||
You can also define a sequence of character defined by a range.
|
|
||||||
```c++
|
|
||||||
std::string blob;
|
|
||||||
...
|
|
||||||
auto root = tyti::vdf::read(std::cbegin(blob), std::cend(blob));
|
|
||||||
|
|
||||||
//given .vdf below, following holds
|
|
||||||
assert(root.name == "name");
|
|
||||||
const std::shared_ptr<tyti::vdf::object> child = root.childs["child0"];
|
|
||||||
assert(child->name == "child0");
|
|
||||||
const std::string& k = root[0].attribs["attrib0"];
|
|
||||||
assert(k == "value");
|
|
||||||
```
|
|
||||||
|
|
||||||
The `tyti::vdf::object` is a tree like data structure.
|
|
||||||
It has its name, some attributes as a pair of `key` and `value`
|
|
||||||
and its object childs. Below you can see a vdf data structure and how it is stored by naming:
|
|
||||||
```javascript
|
|
||||||
"name"
|
|
||||||
{
|
|
||||||
"attrib0" "value" // saved as a pair, first -> key, second -> value
|
|
||||||
"#base" "includeFile.vdf" // appends object defined in the file to childs
|
|
||||||
"child0"
|
|
||||||
{
|
|
||||||
...
|
|
||||||
}
|
|
||||||
...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Given such an object, you can also write it into vdf files via:
|
|
||||||
```c++
|
|
||||||
tyti::vdf::write(file, object);
|
|
||||||
```
|
|
||||||
|
|
||||||
## Multi-Key and Custom Output Type
|
|
||||||
|
|
||||||
It is also possible to customize your output dataformat.
|
|
||||||
Per default, the parser stores all items in a std::unordered_map, which, per definition,
|
|
||||||
doesn't allow different entries with the same key.
|
|
||||||
|
|
||||||
However, the Valve vdf format supports multiple keys. Therefore, the output data format
|
|
||||||
has to store all items in e.g. a std::unordered_multimap.
|
|
||||||
|
|
||||||
You can change the output format by passing the output type via template argument to
|
|
||||||
the read function
|
|
||||||
```c++
|
|
||||||
namespace tyti;
|
|
||||||
vdf::object no_multi_key = vdf::read(file);
|
|
||||||
vdf::multikey_object multi_key = vdf::read<vdf::multikey_object>(file);
|
|
||||||
```
|
|
||||||
|
|
||||||
__Note__: The interface of [std::unordered_map](http://en.cppreference.com/w/cpp/container/unordered_map) and [std::unordered_multimap](http://en.cppreference.com/w/cpp/container/unordered_multimap)
|
|
||||||
are different when you access the elements.
|
|
||||||
|
|
||||||
It is also possible to create your own data structure which is used by the parser.
|
|
||||||
Your output class needs to define 3 functions with the following signature:
|
|
||||||
|
|
||||||
```c++
|
|
||||||
void add_attribute(std::basic_string<CHAR> key, std::basic_string<CHAR> value);
|
|
||||||
void add_child(std::unique_ptr< MYCLASS > child);
|
|
||||||
void set_name(std::basic_string<CHAR> n);
|
|
||||||
```
|
|
||||||
where ```MYCLASS``` is the tpe of your class and ```CHAR``` the type of your character set.
|
|
||||||
Also, the type has to be [default constructible](http://en.cppreference.com/w/cpp/types/is_default_constructible)
|
|
||||||
and [move constructible](http://en.cppreference.com/w/cpp/types/is_move_constructible).
|
|
||||||
|
|
||||||
This also allows you, to inspect the file without storing it in a data structure.
|
|
||||||
Lets say, for example, you want to count all attributes of a file without storing it.
|
|
||||||
You can do this by using this class
|
|
||||||
|
|
||||||
```c++
|
|
||||||
struct counter
|
|
||||||
{
|
|
||||||
size_t num_attributes = 0;
|
|
||||||
void add_attribute(std::string key, std::string value)
|
|
||||||
{
|
|
||||||
++num_attributes;
|
|
||||||
}
|
|
||||||
void add_child(std::unique_ptr< counter > child)
|
|
||||||
{
|
|
||||||
num_attributes += child->num_attributes;
|
|
||||||
}
|
|
||||||
void set_name(std::string n)
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
and then call the read function
|
|
||||||
```c++
|
|
||||||
std::vector<counter> num = tyti::vdf::read<counter>(file);
|
|
||||||
```
|
|
||||||
|
|
||||||
## Options (experimental)
|
|
||||||
|
|
||||||
You can configure the parser, the non default options are not well tested yet.
|
|
||||||
|
|
||||||
```c++
|
|
||||||
struct Options
|
|
||||||
{
|
|
||||||
bool strip_escape_symbols; //default true
|
|
||||||
bool ignore_all_platform_conditionals; // default false
|
|
||||||
bool ignore_includes; //default false
|
|
||||||
};
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
## Reference
|
|
||||||
```c++
|
|
||||||
/////////////////////////////////////////////////////////////
|
|
||||||
// pre-defined output classes
|
|
||||||
/////////////////////////////////////////////////////////////
|
|
||||||
// default output object
|
|
||||||
template<typename T>
|
|
||||||
basic_object<T>
|
|
||||||
{
|
|
||||||
std::basic_string<char_type> name;
|
|
||||||
std::unordered_map<std::basic_string<char_type>, std::basic_string<char_type> > attribs;
|
|
||||||
std::unordered_map<std::basic_string<char_type>, std::shared_ptr< basic_object<char_type> > > childs;
|
|
||||||
};
|
|
||||||
typedef basic_object<char> object;
|
|
||||||
typedef basic_object<wchar_t> wobject
|
|
||||||
|
|
||||||
// output object with multikey support
|
|
||||||
template<typename T>
|
|
||||||
basic_multikey_object<T>
|
|
||||||
{
|
|
||||||
std::basic_string<char_type> name;
|
|
||||||
std::unordered_multimap<std::basic_string<char_type>, std::basic_string<char_type> > attribs;
|
|
||||||
std::unordered_multimap<std::basic_string<char_type>, std::shared_ptr< basic_object<char_type> > > childs;
|
|
||||||
};
|
|
||||||
typedef basic_multikey_object<char> multikey_object;
|
|
||||||
typedef basic_multikey_object<wchar_t> wmultikey_object
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////
|
|
||||||
// error codes
|
|
||||||
/////////////////////////////////////////////////////////////
|
|
||||||
/*
|
|
||||||
Possible error codes:
|
|
||||||
std::errc::protocol_error: file is mailformatted
|
|
||||||
std::errc::not_enough_memory: not enough space
|
|
||||||
std::errc::invalid_argument: iterators throws e.g. out of range
|
|
||||||
*/
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////
|
|
||||||
// read from stream
|
|
||||||
/////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
/** \brief Loads a stream (e.g. filestream) into the memory and parses the vdf formatted data.
|
|
||||||
throws "std::bad_alloc" if file buffer could not be allocated
|
|
||||||
throws "std::runtime_error" if a parsing error occured
|
|
||||||
*/
|
|
||||||
template<ytpename OutputT, typename iStreamT>
|
|
||||||
std::vector<OutputT> read(iStreamT& inStream, const Options &opt = Options{});
|
|
||||||
|
|
||||||
template<typename iStreamT>
|
|
||||||
std::vector<basic_object<typename iStreamT::char_type>> read(iStreamT& inStream, const Options &opt = Options{});
|
|
||||||
|
|
||||||
/** \brief Loads a stream (e.g. filestream) into the memory and parses the vdf formatted data.
|
|
||||||
throws "std::bad_alloc" if file buffer could not be allocated
|
|
||||||
ok == false, if a parsing error occured
|
|
||||||
*/
|
|
||||||
template<typename OutputT, typename iStreamT>
|
|
||||||
std::vector<OutputT> read(iStreamT& inStream, bool* ok, const Options &opt = Options{});
|
|
||||||
|
|
||||||
template<typename iStreamT>
|
|
||||||
std::vector<basic_object<typename iStreamT::char_type>> read(iStreamT& inStream, bool* ok, const Options &opt = Options{});
|
|
||||||
|
|
||||||
/** \brief Loads a stream (e.g. filestream) into the memory and parses the vdf formatted data.
|
|
||||||
throws "std::bad_alloc" if file buffer could not be allocated
|
|
||||||
*/
|
|
||||||
template<typename OutputT, typename iStreamT>
|
|
||||||
std::vector<OutputT> read(iStreamT& inStream, std::error_code& ec, const Options &opt = Options{});
|
|
||||||
|
|
||||||
template<typename iStreamT>
|
|
||||||
std::vector<basic_object<iStreamT::char_type>> read(iStreamT& inStream, std::error_code& ec, const Options &opt = Options{});
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////
|
|
||||||
// read from memory
|
|
||||||
/////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
/** \brief Read VDF formatted sequences defined by the range [first, last).
|
|
||||||
If the file is mailformatted, parser will try to read it until it can.
|
|
||||||
@param first begin iterator
|
|
||||||
@param end end iterator
|
|
||||||
|
|
||||||
throws "std::runtime_error" if a parsing error occured
|
|
||||||
throws "std::bad_alloc" if not enough memory could be allocated
|
|
||||||
*/
|
|
||||||
template<typename OutputT, typename IterT>
|
|
||||||
std::vector<OutputT> read(IterT first, IterT last, const Options &opt = Options{});
|
|
||||||
|
|
||||||
template<typename IterT>
|
|
||||||
std::vector<basic_object<typename std::iterator_traits<IterT>::value_type>> read(IterT first, IterT last, const Options &opt = Options{});
|
|
||||||
|
|
||||||
/** \brief Read VDF formatted sequences defined by the range [first, last).
|
|
||||||
If the file is mailformatted, parser will try to read it until it can.
|
|
||||||
@param first begin iterator
|
|
||||||
@param end end iterator
|
|
||||||
@param ok output bool. true, if parser successed, false, if parser failed
|
|
||||||
*/
|
|
||||||
template<typename OutputT, typename IterT>
|
|
||||||
std::vector<OutputT> read(IterT first, IterT last, bool* ok, const Options &opt = Options{}) noexcept;
|
|
||||||
|
|
||||||
template<typename IterT>
|
|
||||||
std::vector<basic_object<typename std::iterator_traits<IterT>::value_type>> read(IterT first, IterT last, bool* ok, const Options &opt = Options{}) noexcept;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Read VDF formatted sequences defined by the range [first, last).
|
|
||||||
If the file is mailformatted, parser will try to read it until it can.
|
|
||||||
@param first begin iterator
|
|
||||||
@param end end iterator
|
|
||||||
@param ec output bool. 0 if ok, otherwise, holds an system error code
|
|
||||||
*/
|
|
||||||
template<typename OutputT, typename IterT>
|
|
||||||
std::vector<OutputT> read(IterT first, IterT last, std::error_code& ec, const Options &opt = Options{}) noexcept;
|
|
||||||
|
|
||||||
template<typename IterT>
|
|
||||||
std::vector<basic_object<typename std::iterator_traits<IterT>::value_type>> read(IterT first, IterT last, std::error_code& ec, const Options &opt = Options{}) noexcept;
|
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Writer functions
|
|
||||||
/// writes given obj into out in vdf style
|
|
||||||
/// Output is prettyfied, using tabs
|
|
||||||
template<typename oStreamT, typename T>
|
|
||||||
void write(oStreamT& out, const T& obj, const Options &opt = Options{});
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
## Remarks for Errors
|
|
||||||
The current version is a greedy implementation and jumps over unrecognized fields.
|
|
||||||
Therefore, the error detection is very imprecise an does not give the line, where the error occurs.
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
[MIT License](./LICENSE) © Matthias Möller. Made with ♥ in Germany.
|
|
326
src/external/valve-file-vdf/vdf_parser.hpp
vendored
326
src/external/valve-file-vdf/vdf_parser.hpp
vendored
|
@ -9,8 +9,8 @@
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
// furnished to do so, subject to the following conditions :
|
// furnished to do so, subject to the following conditions :
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
@ -23,19 +23,19 @@
|
||||||
#ifndef __TYTI_STEAM_VDF_PARSER_H__
|
#ifndef __TYTI_STEAM_VDF_PARSER_H__
|
||||||
#define __TYTI_STEAM_VDF_PARSER_H__
|
#define __TYTI_STEAM_VDF_PARSER_H__
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <vector>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <utility>
|
|
||||||
#include <fstream>
|
|
||||||
#include <memory>
|
|
||||||
#include <unordered_set>
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iterator>
|
#include <fstream>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <iterator>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <system_error>
|
|
||||||
#include <exception>
|
#include <exception>
|
||||||
|
#include <system_error>
|
||||||
|
|
||||||
// for wstring support
|
// for wstring support
|
||||||
#include <locale>
|
#include <locale>
|
||||||
|
@ -76,8 +76,7 @@ namespace tyti
|
||||||
// Helper functions selecting the right encoding (char/wchar_T)
|
// Helper functions selecting the right encoding (char/wchar_T)
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
template <typename T>
|
template <typename T> struct literal_macro_help
|
||||||
struct literal_macro_help
|
|
||||||
{
|
{
|
||||||
static CONSTEXPR const char *result(const char *c, const wchar_t *) NOEXCEPT
|
static CONSTEXPR const char *result(const char *c, const wchar_t *) NOEXCEPT
|
||||||
{
|
{
|
||||||
|
@ -89,10 +88,10 @@ namespace tyti
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
template <> struct literal_macro_help<wchar_t>
|
||||||
struct literal_macro_help<wchar_t>
|
|
||||||
{
|
{
|
||||||
static CONSTEXPR const wchar_t* result(const char*, const wchar_t* wc) NOEXCEPT
|
static CONSTEXPR const wchar_t *result(const char *,
|
||||||
|
const wchar_t *wc) NOEXCEPT
|
||||||
{
|
{
|
||||||
return wc;
|
return wc;
|
||||||
}
|
}
|
||||||
|
@ -101,26 +100,28 @@ namespace tyti
|
||||||
return wc;
|
return wc;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
#define TYTI_L(type, text) vdf::detail::literal_macro_help<type>::result(text, L##text)
|
#define TYTI_L(type, text) \
|
||||||
|
vdf::detail::literal_macro_help<type>::result(text, L##text)
|
||||||
|
|
||||||
inline std::string string_converter(const std::string& w) NOEXCEPT
|
inline std::string string_converter(const std::string &w) NOEXCEPT { return w; }
|
||||||
{
|
|
||||||
return w;
|
|
||||||
}
|
|
||||||
|
|
||||||
// utility wrapper to adapt locale-bound facets for wstring/wbuffer convert
|
// utility wrapper to adapt locale-bound facets for wstring/wbuffer convert
|
||||||
// from cppreference
|
// from cppreference
|
||||||
template <class Facet>
|
template <class Facet> struct deletable_facet : Facet
|
||||||
struct deletable_facet : Facet
|
|
||||||
{
|
{
|
||||||
template <class... Args>
|
template <class... Args>
|
||||||
deletable_facet(Args &&... args) : Facet(std::forward<Args>(args)...) {}
|
deletable_facet(Args &&...args) : Facet(std::forward<Args>(args)...)
|
||||||
|
{
|
||||||
|
}
|
||||||
~deletable_facet() {}
|
~deletable_facet() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline std::string string_converter(const std::wstring& w) //todo: use us-locale
|
inline std::string
|
||||||
|
string_converter(const std::wstring &w) // todo: use us-locale
|
||||||
{
|
{
|
||||||
std::wstring_convert<deletable_facet<std::codecvt<wchar_t, char, std::mbstate_t>>> conv1;
|
std::wstring_convert<
|
||||||
|
deletable_facet<std::codecvt<wchar_t, char, std::mbstate_t>>>
|
||||||
|
conv1;
|
||||||
return conv1.to_bytes(w);
|
return conv1.to_bytes(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,14 +129,16 @@ namespace tyti
|
||||||
// Writer helper functions
|
// Writer helper functions
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
template <typename charT>
|
template <typename charT> class tabs
|
||||||
class tabs
|
|
||||||
{
|
{
|
||||||
const size_t t;
|
const size_t t;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit CONSTEXPR tabs(size_t i) NOEXCEPT : t(i) {}
|
explicit CONSTEXPR tabs(size_t i) NOEXCEPT : t(i) {}
|
||||||
std::basic_string<charT> print() const { return std::basic_string<charT>(t, TYTI_L(charT, '\t')); }
|
std::basic_string<charT> print() const
|
||||||
|
{
|
||||||
|
return std::basic_string<charT>(t, TYTI_L(charT, '\t'));
|
||||||
|
}
|
||||||
inline CONSTEXPR tabs operator+(size_t i) const NOEXCEPT
|
inline CONSTEXPR tabs operator+(size_t i) const NOEXCEPT
|
||||||
{
|
{
|
||||||
return tabs(t + i);
|
return tabs(t + i);
|
||||||
|
@ -156,51 +159,54 @@ namespace tyti
|
||||||
|
|
||||||
/// custom objects and their corresponding write functions
|
/// custom objects and their corresponding write functions
|
||||||
|
|
||||||
/// basic object node. Every object has a name and can contains attributes saved as key_value pairs or childrens
|
/// basic object node. Every object has a name and can contains attributes saved
|
||||||
template <typename CharT>
|
/// as key_value pairs or childrens
|
||||||
struct basic_object
|
template <typename CharT> struct basic_object
|
||||||
{
|
{
|
||||||
typedef CharT char_type;
|
typedef CharT char_type;
|
||||||
std::basic_string<char_type> name;
|
std::basic_string<char_type> name;
|
||||||
std::unordered_map<std::basic_string<char_type>, std::basic_string<char_type>> attribs;
|
std::unordered_map<std::basic_string<char_type>,
|
||||||
std::unordered_map<std::basic_string<char_type>, std::shared_ptr<basic_object<char_type>>> children;
|
std::basic_string<char_type>>
|
||||||
|
attribs;
|
||||||
|
std::unordered_map<std::basic_string<char_type>,
|
||||||
|
std::shared_ptr<basic_object<char_type>>>
|
||||||
|
childs;
|
||||||
|
|
||||||
void add_attribute(std::basic_string<char_type> key, std::basic_string<char_type> value)
|
void add_attribute(std::basic_string<char_type> key,
|
||||||
|
std::basic_string<char_type> value)
|
||||||
{
|
{
|
||||||
attribs.emplace(std::move(key), std::move(value));
|
attribs.emplace(std::move(key), std::move(value));
|
||||||
}
|
}
|
||||||
void add_child(std::unique_ptr<basic_object<char_type>> child)
|
void add_child(std::unique_ptr<basic_object<char_type>> child)
|
||||||
{
|
{
|
||||||
std::shared_ptr<basic_object<char_type>> obj{child.release()};
|
std::shared_ptr<basic_object<char_type>> obj{child.release()};
|
||||||
children.emplace(obj->name, obj);
|
childs.emplace(obj->name, obj);
|
||||||
}
|
|
||||||
void set_name(std::basic_string<char_type> n)
|
|
||||||
{
|
|
||||||
name = std::move(n);
|
|
||||||
}
|
}
|
||||||
|
void set_name(std::basic_string<char_type> n) { name = std::move(n); }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename CharT>
|
template <typename CharT> struct basic_multikey_object
|
||||||
struct basic_multikey_object
|
|
||||||
{
|
{
|
||||||
typedef CharT char_type;
|
typedef CharT char_type;
|
||||||
std::basic_string<char_type> name;
|
std::basic_string<char_type> name;
|
||||||
std::unordered_multimap<std::basic_string<char_type>, std::basic_string<char_type>> attribs;
|
std::unordered_multimap<std::basic_string<char_type>,
|
||||||
std::unordered_multimap<std::basic_string<char_type>, std::shared_ptr<basic_multikey_object<char_type>>> children;
|
std::basic_string<char_type>>
|
||||||
|
attribs;
|
||||||
|
std::unordered_multimap<std::basic_string<char_type>,
|
||||||
|
std::shared_ptr<basic_multikey_object<char_type>>>
|
||||||
|
childs;
|
||||||
|
|
||||||
void add_attribute(std::basic_string<char_type> key, std::basic_string<char_type> value)
|
void add_attribute(std::basic_string<char_type> key,
|
||||||
|
std::basic_string<char_type> value)
|
||||||
{
|
{
|
||||||
attribs.emplace(std::move(key), std::move(value));
|
attribs.emplace(std::move(key), std::move(value));
|
||||||
}
|
}
|
||||||
void add_child(std::unique_ptr<basic_multikey_object<char_type>> child)
|
void add_child(std::unique_ptr<basic_multikey_object<char_type>> child)
|
||||||
{
|
{
|
||||||
std::shared_ptr<basic_multikey_object<char_type>> obj{child.release()};
|
std::shared_ptr<basic_multikey_object<char_type>> obj{child.release()};
|
||||||
children.emplace(obj->name, obj);
|
childs.emplace(obj->name, obj);
|
||||||
}
|
|
||||||
void set_name(std::basic_string<char_type> n)
|
|
||||||
{
|
|
||||||
name = std::move(n);
|
|
||||||
}
|
}
|
||||||
|
void set_name(std::basic_string<char_type> n) { name = std::move(n); }
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef basic_object<char> object;
|
typedef basic_object<char> object;
|
||||||
|
@ -214,7 +220,11 @@ namespace tyti
|
||||||
bool ignore_all_platform_conditionals;
|
bool ignore_all_platform_conditionals;
|
||||||
bool ignore_includes;
|
bool ignore_includes;
|
||||||
|
|
||||||
Options() : strip_escape_symbols(true), ignore_all_platform_conditionals(false), ignore_includes(false) {}
|
Options()
|
||||||
|
: strip_escape_symbols(true), ignore_all_platform_conditionals(false),
|
||||||
|
ignore_includes(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// forward decls
|
// forward decls
|
||||||
|
@ -227,14 +237,17 @@ namespace tyti
|
||||||
*/
|
*/
|
||||||
template <typename oStreamT, typename T>
|
template <typename oStreamT, typename T>
|
||||||
void write(oStreamT &s, const T &r,
|
void write(oStreamT &s, const T &r,
|
||||||
const detail::tabs<typename oStreamT::char_type> tab = detail::tabs<typename oStreamT::char_type>(0))
|
const detail::tabs<typename oStreamT::char_type> tab =
|
||||||
|
detail::tabs<typename oStreamT::char_type>(0))
|
||||||
{
|
{
|
||||||
typedef typename oStreamT::char_type charT;
|
typedef typename oStreamT::char_type charT;
|
||||||
using namespace detail;
|
using namespace detail;
|
||||||
s << tab << TYTI_L(charT, '"') << r.name << TYTI_L(charT, "\"\n") << tab << TYTI_L(charT, "{\n");
|
s << tab << TYTI_L(charT, '"') << r.name << TYTI_L(charT, "\"\n") << tab
|
||||||
|
<< TYTI_L(charT, "{\n");
|
||||||
for (const auto &i : r.attribs)
|
for (const auto &i : r.attribs)
|
||||||
s << tab + 1 << TYTI_L(charT, '"') << i.first << TYTI_L(charT, "\"\t\t\"") << i.second << TYTI_L(charT, "\"\n");
|
s << tab + 1 << TYTI_L(charT, '"') << i.first
|
||||||
for (const auto& i : r.children)
|
<< TYTI_L(charT, "\"\t\t\"") << i.second << TYTI_L(charT, "\"\n");
|
||||||
|
for (const auto &i : r.childs)
|
||||||
if (i.second)
|
if (i.second)
|
||||||
write(s, *i.second, tab + 1);
|
write(s, *i.second, tab + 1);
|
||||||
s << tab << TYTI_L(charT, "}\n");
|
s << tab << TYTI_L(charT, "}\n");
|
||||||
|
@ -270,12 +283,16 @@ namespace tyti
|
||||||
- "std::bad_alloc" if not enough memory coup be allocated
|
- "std::bad_alloc" if not enough memory coup be allocated
|
||||||
*/
|
*/
|
||||||
template <typename OutputT, typename IterT>
|
template <typename OutputT, typename IterT>
|
||||||
std::vector<std::unique_ptr<OutputT>> read_internal(IterT first, const IterT last,
|
std::vector<std::unique_ptr<OutputT>> read_internal(
|
||||||
std::unordered_set<std::basic_string<typename std::iterator_traits<IterT>::value_type>>& exclude_files,
|
IterT first, const IterT last,
|
||||||
|
std::unordered_set<
|
||||||
|
std::basic_string<typename std::iterator_traits<IterT>::value_type>>
|
||||||
|
&exclude_files,
|
||||||
const Options &opt)
|
const Options &opt)
|
||||||
{
|
{
|
||||||
static_assert(std::is_default_constructible<OutputT>::value,
|
static_assert(std::is_default_constructible<OutputT>::value,
|
||||||
"Output Type must be default constructible (provide constructor without arguments)");
|
"Output Type must be default constructible (provide "
|
||||||
|
"constructor without arguments)");
|
||||||
static_assert(std::is_move_constructible<OutputT>::value,
|
static_assert(std::is_move_constructible<OutputT>::value,
|
||||||
"Output Type must be move constructible");
|
"Output Type must be move constructible");
|
||||||
|
|
||||||
|
@ -285,56 +302,73 @@ namespace tyti
|
||||||
const std::basic_string<charT> whitespaces = TYTI_L(charT, " \n\v\f\r\t");
|
const std::basic_string<charT> whitespaces = TYTI_L(charT, " \n\v\f\r\t");
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
std::function<bool(const std::basic_string<charT>&)> is_platform_str = [](const std::basic_string<charT>& in) {
|
std::function<bool(const std::basic_string<charT> &)> is_platform_str =
|
||||||
|
[](const std::basic_string<charT> &in)
|
||||||
|
{
|
||||||
return in == TYTI_L(charT, "$WIN32") || in == TYTI_L(charT, "$WINDOWS");
|
return in == TYTI_L(charT, "$WIN32") || in == TYTI_L(charT, "$WINDOWS");
|
||||||
};
|
};
|
||||||
#elif __APPLE__
|
#elif __APPLE__
|
||||||
// WIN32 stands for pc in general
|
// WIN32 stands for pc in general
|
||||||
std::function<bool(const std::basic_string<charT>&)> is_platform_str = [](const std::basic_string<charT>& in) {
|
std::function<bool(const std::basic_string<charT> &)> is_platform_str =
|
||||||
return in == TYTI_L(charT, "$WIN32") || in == TYTI_L(charT, "$POSIX") || in == TYTI_L(charT, "$OSX");
|
[](const std::basic_string<charT> &in)
|
||||||
|
{
|
||||||
|
return in == TYTI_L(charT, "$WIN32") || in == TYTI_L(charT, "$POSIX") ||
|
||||||
|
in == TYTI_L(charT, "$OSX");
|
||||||
};
|
};
|
||||||
|
|
||||||
#elif __linux__
|
#elif __linux__
|
||||||
// WIN32 stands for pc in general
|
// WIN32 stands for pc in general
|
||||||
std::function<bool(const std::basic_string<charT>&)> is_platform_str = [](const std::basic_string<charT>& in) {
|
std::function<bool(const std::basic_string<charT> &)> is_platform_str =
|
||||||
return in == TYTI_L(charT, "$WIN32") || in == TYTI_L(charT, "$POSIX") || in == TYTI_L(charT, "$LINUX");
|
[](const std::basic_string<charT> &in)
|
||||||
|
{
|
||||||
|
return in == TYTI_L(charT, "$WIN32") || in == TYTI_L(charT, "$POSIX") ||
|
||||||
|
in == TYTI_L(charT, "$LINUX");
|
||||||
};
|
};
|
||||||
#else
|
#else
|
||||||
std::function<bool(const std::basic_string<charT>&)> is_platform_str = [](const std::basic_string<charT>& in) {
|
std::function<bool(const std::basic_string<charT> &)> is_platform_str =
|
||||||
return false;
|
[](const std::basic_string<charT> &in) { return false; };
|
||||||
};
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (opt.ignore_all_platform_conditionals)
|
if (opt.ignore_all_platform_conditionals)
|
||||||
is_platform_str = [](const std::basic_string<charT>&) {
|
is_platform_str = [](const std::basic_string<charT> &)
|
||||||
return false;
|
{ return false; };
|
||||||
};
|
|
||||||
|
|
||||||
// function for skipping a comment block
|
// function for skipping a comment block
|
||||||
// iter: iterator poition to the position after a '/'
|
// iter: iterator poition to the position after a '/'
|
||||||
auto skip_comments = [&comment_end_str](IterT iter, const IterT& last) -> IterT {
|
auto skip_comments = [&comment_end_str](IterT iter,
|
||||||
++iter;
|
const IterT &last) -> IterT
|
||||||
if (iter != last)
|
|
||||||
{
|
{
|
||||||
|
++iter;
|
||||||
|
if (iter == last)
|
||||||
|
return last;
|
||||||
|
|
||||||
if (*iter == TYTI_L(charT, '/'))
|
if (*iter == TYTI_L(charT, '/'))
|
||||||
{
|
{
|
||||||
// line comment, skip whole line
|
// line comment, skip whole line
|
||||||
iter = std::find(iter + 1, last, TYTI_L(charT, '\n'));
|
iter = std::find(iter + 1, last, TYTI_L(charT, '\n'));
|
||||||
|
if (iter == last)
|
||||||
|
return last;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*iter == '*')
|
if (*iter == '*')
|
||||||
{
|
{
|
||||||
// block comment, skip until next occurance of "*\"
|
// block comment, skip until next occurance of "*\"
|
||||||
iter = std::search(iter + 1, last, std::begin(comment_end_str), std::end(comment_end_str));
|
iter = std::search(iter + 1, last, std::begin(comment_end_str),
|
||||||
|
std::end(comment_end_str));
|
||||||
|
if (std::distance(iter, last) <= 2)
|
||||||
|
return last;
|
||||||
iter += 2;
|
iter += 2;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return iter;
|
return iter;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto end_quote = [](IterT iter, const IterT& last) -> IterT {
|
auto end_quote = [](IterT iter, const IterT &last) -> IterT
|
||||||
|
{
|
||||||
const auto begin = iter;
|
const auto begin = iter;
|
||||||
auto last_esc = iter;
|
auto last_esc = iter;
|
||||||
|
if (iter == last)
|
||||||
|
throw std::runtime_error{"quote was opened but not closed."};
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
++iter;
|
++iter;
|
||||||
|
@ -345,48 +379,65 @@ namespace tyti
|
||||||
last_esc = std::prev(iter);
|
last_esc = std::prev(iter);
|
||||||
while (last_esc != begin && *last_esc == '\\')
|
while (last_esc != begin && *last_esc == '\\')
|
||||||
--last_esc;
|
--last_esc;
|
||||||
} while (!(std::distance(last_esc, iter) % 2));
|
} while (!(std::distance(last_esc, iter) % 2) && iter != last);
|
||||||
if (iter == last)
|
if (iter == last)
|
||||||
throw std::runtime_error{"quote was opened but not closed."};
|
throw std::runtime_error{"quote was opened but not closed."};
|
||||||
return iter;
|
return iter;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto end_word = [&whitespaces](IterT iter, const IterT& last) -> IterT {
|
auto end_word = [&whitespaces](IterT iter, const IterT &last) -> IterT
|
||||||
|
{
|
||||||
const auto begin = iter;
|
const auto begin = iter;
|
||||||
auto last_esc = iter;
|
auto last_esc = iter;
|
||||||
|
if (iter == last)
|
||||||
|
throw std::runtime_error{"quote was opened but not closed."};
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
++iter;
|
++iter;
|
||||||
iter = std::find_first_of(iter, last, std::begin(whitespaces), std::end(whitespaces));
|
iter = std::find_first_of(iter, last, std::begin(whitespaces),
|
||||||
|
std::end(whitespaces));
|
||||||
if (iter == last)
|
if (iter == last)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
last_esc = std::prev(iter);
|
last_esc = std::prev(iter);
|
||||||
while (last_esc != begin && *last_esc == '\\')
|
while (last_esc != begin && *last_esc == '\\')
|
||||||
--last_esc;
|
--last_esc;
|
||||||
} while (!(std::distance(last_esc, iter) % 2));
|
} while (!(std::distance(last_esc, iter) % 2) && iter != last);
|
||||||
//if (iter == last)
|
if (iter == last)
|
||||||
// throw std::runtime_error{ "word wasnt properly ended" };
|
throw std::runtime_error{"word wasnt properly ended"};
|
||||||
return iter;
|
return iter;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto skip_whitespaces = [&whitespaces](IterT iter, const IterT& last) -> IterT {
|
auto skip_whitespaces = [&whitespaces](IterT iter,
|
||||||
iter = std::find_if_not(iter, last, [&whitespaces](charT c) {
|
const IterT &last) -> IterT
|
||||||
|
{
|
||||||
|
if (iter == last)
|
||||||
|
return iter;
|
||||||
|
iter = std::find_if_not(iter, last,
|
||||||
|
[&whitespaces](charT c)
|
||||||
|
{
|
||||||
// return true if whitespace
|
// return true if whitespace
|
||||||
return std::any_of(std::begin(whitespaces), std::end(whitespaces), [c](charT pc) { return pc == c; });
|
return std::any_of(std::begin(whitespaces),
|
||||||
|
std::end(whitespaces),
|
||||||
|
[c](charT pc)
|
||||||
|
{ return pc == c; });
|
||||||
});
|
});
|
||||||
return iter;
|
return iter;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::function<void(std::basic_string<charT>&)> strip_escape_symbols = [](std::basic_string<charT>& s) {
|
std::function<void(std::basic_string<charT> &)> strip_escape_symbols =
|
||||||
auto quote_searcher = [&s](size_t pos) { return s.find(TYTI_L(charT, "\\\""), pos); };
|
[](std::basic_string<charT> &s)
|
||||||
|
{
|
||||||
|
auto quote_searcher = [&s](size_t pos)
|
||||||
|
{ return s.find(TYTI_L(charT, "\\\""), pos); };
|
||||||
auto p = quote_searcher(0);
|
auto p = quote_searcher(0);
|
||||||
while (p != s.npos)
|
while (p != s.npos)
|
||||||
{
|
{
|
||||||
s.replace(p, 2, TYTI_L(charT, "\""));
|
s.replace(p, 2, TYTI_L(charT, "\""));
|
||||||
p = quote_searcher(p);
|
p = quote_searcher(p);
|
||||||
}
|
}
|
||||||
auto searcher = [&s](size_t pos) { return s.find(TYTI_L(charT, "\\\\"), pos); };
|
auto searcher = [&s](size_t pos)
|
||||||
|
{ return s.find(TYTI_L(charT, "\\\\"), pos); };
|
||||||
p = searcher(0);
|
p = searcher(0);
|
||||||
while (p != s.npos)
|
while (p != s.npos)
|
||||||
{
|
{
|
||||||
|
@ -398,12 +449,20 @@ namespace tyti
|
||||||
if (!opt.strip_escape_symbols)
|
if (!opt.strip_escape_symbols)
|
||||||
strip_escape_symbols = [](std::basic_string<charT> &) {};
|
strip_escape_symbols = [](std::basic_string<charT> &) {};
|
||||||
|
|
||||||
auto conditional_fullfilled = [&skip_whitespaces, &is_platform_str](IterT& iter, const IterT& last) {
|
auto conditional_fullfilled =
|
||||||
|
[&skip_whitespaces, &is_platform_str](IterT &iter, const IterT &last)
|
||||||
|
{
|
||||||
iter = skip_whitespaces(iter, last);
|
iter = skip_whitespaces(iter, last);
|
||||||
|
if (iter == last)
|
||||||
|
return true;
|
||||||
if (*iter == '[')
|
if (*iter == '[')
|
||||||
{
|
{
|
||||||
++iter;
|
++iter;
|
||||||
|
if (iter == last)
|
||||||
|
throw std::runtime_error("conditional not closed");
|
||||||
const auto end = std::find(iter, last, ']');
|
const auto end = std::find(iter, last, ']');
|
||||||
|
if (end == last)
|
||||||
|
throw std::runtime_error("conditional not closed");
|
||||||
const bool negate = *iter == '!';
|
const bool negate = *iter == '!';
|
||||||
if (negate)
|
if (negate)
|
||||||
++iter;
|
++iter;
|
||||||
|
@ -433,23 +492,30 @@ namespace tyti
|
||||||
if (*curIter == TYTI_L(charT, '/'))
|
if (*curIter == TYTI_L(charT, '/'))
|
||||||
{
|
{
|
||||||
curIter = skip_comments(curIter, last);
|
curIter = skip_comments(curIter, last);
|
||||||
|
if (curIter == last || *curIter == '\0')
|
||||||
|
throw std::runtime_error("Unexpected eof");
|
||||||
}
|
}
|
||||||
else if (*curIter != TYTI_L(charT, '}'))
|
else if (*curIter != TYTI_L(charT, '}'))
|
||||||
{
|
{
|
||||||
|
|
||||||
// get key
|
// get key
|
||||||
const auto keyEnd = (*curIter == TYTI_L(charT, '\"')) ? end_quote(curIter, last) : end_word(curIter, last);
|
const auto keyEnd = (*curIter == TYTI_L(charT, '\"'))
|
||||||
|
? end_quote(curIter, last)
|
||||||
|
: end_word(curIter, last);
|
||||||
if (*curIter == TYTI_L(charT, '\"'))
|
if (*curIter == TYTI_L(charT, '\"'))
|
||||||
++curIter;
|
++curIter;
|
||||||
std::basic_string<charT> key(curIter, keyEnd);
|
std::basic_string<charT> key(curIter, keyEnd);
|
||||||
strip_escape_symbols(key);
|
strip_escape_symbols(key);
|
||||||
curIter = keyEnd + ((*keyEnd == TYTI_L(charT, '\"')) ? 1 : 0);
|
curIter = keyEnd + ((*keyEnd == TYTI_L(charT, '\"')) ? 1 : 0);
|
||||||
|
if (curIter == last)
|
||||||
|
throw std::runtime_error{"key opened, but never closed"};
|
||||||
|
|
||||||
curIter = skip_whitespaces(curIter, last);
|
curIter = skip_whitespaces(curIter, last);
|
||||||
|
|
||||||
auto conditional = conditional_fullfilled(curIter, last);
|
auto conditional = conditional_fullfilled(curIter, last);
|
||||||
if (!conditional)
|
if (!conditional)
|
||||||
continue;
|
continue;
|
||||||
|
if (curIter == last)
|
||||||
|
throw std::runtime_error{"key declared, but no value"};
|
||||||
|
|
||||||
while (*curIter == TYTI_L(charT, '/'))
|
while (*curIter == TYTI_L(charT, '/'))
|
||||||
{
|
{
|
||||||
|
@ -464,20 +530,30 @@ namespace tyti
|
||||||
// get value
|
// get value
|
||||||
if (*curIter != '{')
|
if (*curIter != '{')
|
||||||
{
|
{
|
||||||
const auto valueEnd = (*curIter == TYTI_L(charT, '\"')) ? end_quote(curIter, last) : end_word(curIter, last);
|
if (curIter == last)
|
||||||
|
throw std::runtime_error{"key declared, but no value"};
|
||||||
|
const auto valueEnd = (*curIter == TYTI_L(charT, '\"'))
|
||||||
|
? end_quote(curIter, last)
|
||||||
|
: end_word(curIter, last);
|
||||||
|
if (valueEnd == last)
|
||||||
|
throw std::runtime_error("No closed word");
|
||||||
if (*curIter == TYTI_L(charT, '\"'))
|
if (*curIter == TYTI_L(charT, '\"'))
|
||||||
++curIter;
|
++curIter;
|
||||||
|
if (curIter == last)
|
||||||
|
throw std::runtime_error("No closed word");
|
||||||
|
|
||||||
auto value = std::basic_string<charT>(curIter, valueEnd);
|
auto value = std::basic_string<charT>(curIter, valueEnd);
|
||||||
strip_escape_symbols(value);
|
strip_escape_symbols(value);
|
||||||
curIter = valueEnd + ((*valueEnd == TYTI_L(charT, '\"')) ? 1 : 0);
|
curIter =
|
||||||
|
valueEnd + ((*valueEnd == TYTI_L(charT, '\"')) ? 1 : 0);
|
||||||
|
|
||||||
auto conditional = conditional_fullfilled(curIter, last);
|
auto conditional = conditional_fullfilled(curIter, last);
|
||||||
if (!conditional)
|
if (!conditional)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// process value
|
// process value
|
||||||
if (key != TYTI_L(charT, "#include") && key != TYTI_L(charT, "#base"))
|
if (key != TYTI_L(charT, "#include") &&
|
||||||
|
key != TYTI_L(charT, "#base"))
|
||||||
{
|
{
|
||||||
if (curObj)
|
if (curObj)
|
||||||
{
|
{
|
||||||
|
@ -485,17 +561,21 @@ namespace tyti
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw std::runtime_error{ "unexpected key without object" };
|
throw std::runtime_error{
|
||||||
|
"unexpected key without object"};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!opt.ignore_includes && exclude_files.find(value) == exclude_files.end())
|
if (!opt.ignore_includes &&
|
||||||
|
exclude_files.find(value) == exclude_files.end())
|
||||||
{
|
{
|
||||||
exclude_files.insert(value);
|
exclude_files.insert(value);
|
||||||
std::basic_ifstream<charT> i(detail::string_converter(value));
|
std::basic_ifstream<charT> i(
|
||||||
|
detail::string_converter(value));
|
||||||
auto str = read_file(i);
|
auto str = read_file(i);
|
||||||
auto file_objs = read_internal<OutputT>(str.begin(), str.end(), exclude_files, opt);
|
auto file_objs = read_internal<OutputT>(
|
||||||
|
str.begin(), str.end(), exclude_files, opt);
|
||||||
for (auto &n : file_objs)
|
for (auto &n : file_objs)
|
||||||
{
|
{
|
||||||
if (curObj)
|
if (curObj)
|
||||||
|
@ -563,8 +643,10 @@ namespace tyti
|
||||||
template <typename OutputT, typename IterT>
|
template <typename OutputT, typename IterT>
|
||||||
OutputT read(IterT first, const IterT last, const Options &opt = Options{})
|
OutputT read(IterT first, const IterT last, const Options &opt = Options{})
|
||||||
{
|
{
|
||||||
auto exclude_files = std::unordered_set<std::basic_string<typename std::iterator_traits<IterT>::value_type>>{};
|
auto exclude_files = std::unordered_set<
|
||||||
auto roots = detail::read_internal<OutputT>(first, last, exclude_files, opt);
|
std::basic_string<typename std::iterator_traits<IterT>::value_type>>{};
|
||||||
|
auto roots =
|
||||||
|
detail::read_internal<OutputT>(first, last, exclude_files, opt);
|
||||||
|
|
||||||
OutputT result;
|
OutputT result;
|
||||||
if (roots.size() > 1)
|
if (roots.size() > 1)
|
||||||
|
@ -590,7 +672,8 @@ namespace tyti
|
||||||
std::errc::invalid_argument: iterators throws e.g. out of range
|
std::errc::invalid_argument: iterators throws e.g. out of range
|
||||||
*/
|
*/
|
||||||
template <typename OutputT, typename IterT>
|
template <typename OutputT, typename IterT>
|
||||||
OutputT read(IterT first, IterT last, std::error_code& ec, const Options& opt = Options{}) NOEXCEPT
|
OutputT read(IterT first, IterT last, std::error_code &ec,
|
||||||
|
const Options &opt = Options{}) NOEXCEPT
|
||||||
|
|
||||||
{
|
{
|
||||||
ec.clear();
|
ec.clear();
|
||||||
|
@ -621,7 +704,8 @@ namespace tyti
|
||||||
@param ok output bool. true, if parser successed, false, if parser failed
|
@param ok output bool. true, if parser successed, false, if parser failed
|
||||||
*/
|
*/
|
||||||
template <typename OutputT, typename IterT>
|
template <typename OutputT, typename IterT>
|
||||||
OutputT read(IterT first, const IterT last, bool* ok, const Options& opt = Options{}) NOEXCEPT
|
OutputT read(IterT first, const IterT last, bool *ok,
|
||||||
|
const Options &opt = Options{}) NOEXCEPT
|
||||||
{
|
{
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
auto r = read<OutputT>(first, last, ec, opt);
|
auto r = read<OutputT>(first, last, ec, opt);
|
||||||
|
@ -631,30 +715,37 @@ namespace tyti
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename IterT>
|
template <typename IterT>
|
||||||
inline auto read(IterT first, const IterT last, bool* ok, const Options& opt = Options{}) NOEXCEPT -> basic_object<typename std::iterator_traits<IterT>::value_type>
|
inline auto read(IterT first, const IterT last, bool *ok,
|
||||||
|
const Options &opt = Options{}) NOEXCEPT
|
||||||
|
->basic_object<typename std::iterator_traits<IterT>::value_type>
|
||||||
{
|
{
|
||||||
return read<basic_object<typename std::iterator_traits<IterT>::value_type>>(first, last, ok, opt);
|
return read<basic_object<typename std::iterator_traits<IterT>::value_type>>(
|
||||||
|
first, last, ok, opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename IterT>
|
template <typename IterT>
|
||||||
inline auto read(IterT first, IterT last, std::error_code& ec, const Options& opt = Options{}) NOEXCEPT
|
inline auto read(IterT first, IterT last, std::error_code &ec,
|
||||||
|
const Options &opt = Options{}) NOEXCEPT
|
||||||
->basic_object<typename std::iterator_traits<IterT>::value_type>
|
->basic_object<typename std::iterator_traits<IterT>::value_type>
|
||||||
{
|
{
|
||||||
return read<basic_object<typename std::iterator_traits<IterT>::value_type>>(first, last, ec, opt);
|
return read<basic_object<typename std::iterator_traits<IterT>::value_type>>(
|
||||||
|
first, last, ec, opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename IterT>
|
template <typename IterT>
|
||||||
inline auto read(IterT first, const IterT last, const Options &opt = Options{})
|
inline auto read(IterT first, const IterT last, const Options &opt = Options{})
|
||||||
-> basic_object<typename std::iterator_traits<IterT>::value_type>
|
-> basic_object<typename std::iterator_traits<IterT>::value_type>
|
||||||
{
|
{
|
||||||
return read<basic_object<typename std::iterator_traits<IterT>::value_type>>(first, last, opt);
|
return read<basic_object<typename std::iterator_traits<IterT>::value_type>>(
|
||||||
|
first, last, opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \brief Loads a stream (e.g. filestream) into the memory and parses the vdf formatted data.
|
/** \brief Loads a stream (e.g. filestream) into the memory and parses the vdf
|
||||||
throws "std::bad_alloc" if file buffer could not be allocated
|
formatted data. throws "std::bad_alloc" if file buffer could not be allocated
|
||||||
*/
|
*/
|
||||||
template <typename OutputT, typename iStreamT>
|
template <typename OutputT, typename iStreamT>
|
||||||
OutputT read(iStreamT& inStream, std::error_code& ec, const Options& opt = Options{})
|
OutputT read(iStreamT &inStream, std::error_code &ec,
|
||||||
|
const Options &opt = Options{})
|
||||||
{
|
{
|
||||||
// cache the file
|
// cache the file
|
||||||
typedef typename iStreamT::char_type charT;
|
typedef typename iStreamT::char_type charT;
|
||||||
|
@ -665,13 +756,14 @@ namespace tyti
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename iStreamT>
|
template <typename iStreamT>
|
||||||
inline basic_object<typename iStreamT::char_type> read(iStreamT& inStream, std::error_code& ec, const Options& opt = Options{})
|
inline basic_object<typename iStreamT::char_type>
|
||||||
|
read(iStreamT &inStream, std::error_code &ec, const Options &opt = Options{})
|
||||||
{
|
{
|
||||||
return read<basic_object<typename iStreamT::char_type>>(inStream, ec, opt);
|
return read<basic_object<typename iStreamT::char_type>>(inStream, ec, opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \brief Loads a stream (e.g. filestream) into the memory and parses the vdf formatted data.
|
/** \brief Loads a stream (e.g. filestream) into the memory and parses the vdf
|
||||||
throws "std::bad_alloc" if file buffer could not be allocated
|
formatted data. throws "std::bad_alloc" if file buffer could not be allocated
|
||||||
ok == false, if a parsing error occured
|
ok == false, if a parsing error occured
|
||||||
*/
|
*/
|
||||||
template <typename OutputT, typename iStreamT>
|
template <typename OutputT, typename iStreamT>
|
||||||
|
@ -685,13 +777,14 @@ namespace tyti
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename iStreamT>
|
template <typename iStreamT>
|
||||||
inline basic_object<typename iStreamT::char_type> read(iStreamT& inStream, bool* ok, const Options& opt = Options{})
|
inline basic_object<typename iStreamT::char_type>
|
||||||
|
read(iStreamT &inStream, bool *ok, const Options &opt = Options{})
|
||||||
{
|
{
|
||||||
return read<basic_object<typename iStreamT::char_type>>(inStream, ok, opt);
|
return read<basic_object<typename iStreamT::char_type>>(inStream, ok, opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \brief Loads a stream (e.g. filestream) into the memory and parses the vdf formatted data.
|
/** \brief Loads a stream (e.g. filestream) into the memory and parses the vdf
|
||||||
throws "std::bad_alloc" if file buffer could not be allocated
|
formatted data. throws "std::bad_alloc" if file buffer could not be allocated
|
||||||
throws "std::runtime_error" if a parsing error occured
|
throws "std::runtime_error" if a parsing error occured
|
||||||
*/
|
*/
|
||||||
template <typename OutputT, typename iStreamT>
|
template <typename OutputT, typename iStreamT>
|
||||||
|
@ -706,7 +799,8 @@ namespace tyti
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename iStreamT>
|
template <typename iStreamT>
|
||||||
inline basic_object<typename iStreamT::char_type> read(iStreamT& inStream, const Options& opt = Options{})
|
inline basic_object<typename iStreamT::char_type>
|
||||||
|
read(iStreamT &inStream, const Options &opt = Options{})
|
||||||
{
|
{
|
||||||
return read<basic_object<typename iStreamT::char_type>>(inStream, opt);
|
return read<basic_object<typename iStreamT::char_type>>(inStream, opt);
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,9 +79,9 @@ find_steamvr_install()
|
||||||
std::ifstream file(STEAM_INSTALL_DIR + "/steamapps/libraryfolders.vdf");
|
std::ifstream file(STEAM_INSTALL_DIR + "/steamapps/libraryfolders.vdf");
|
||||||
auto root = vdf::read(file);
|
auto root = vdf::read(file);
|
||||||
assert(root.name == "libraryfolders");
|
assert(root.name == "libraryfolders");
|
||||||
for (auto &[_, child] : root.children) {
|
for (auto &[_, child] : root.childs) {
|
||||||
U_LOG_D("Found library folder %s", child->attribs["path"].c_str());
|
U_LOG_D("Found library folder %s", child->attribs["path"].c_str());
|
||||||
std::shared_ptr<vdf::object> apps = child->children["apps"];
|
std::shared_ptr<vdf::object> apps = child->childs["apps"];
|
||||||
for (auto &[appid, _] : apps->attribs) {
|
for (auto &[appid, _] : apps->attribs) {
|
||||||
if (appid == STEAMVR_APPID) {
|
if (appid == STEAMVR_APPID) {
|
||||||
return child->attribs["path"] + "/steamapps/common/SteamVR";
|
return child->attribs["path"] + "/steamapps/common/SteamVR";
|
||||||
|
|
Loading…
Reference in a new issue