1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
// file : libbutl/manifest-parser.mxx -*- C++ -*-
// copyright : Copyright (c) 2014-2018 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#ifndef __cpp_modules
#pragma once
#endif
// C includes.
#ifndef __cpp_lib_modules
#include <string>
#include <iosfwd>
#include <cstdint> // uint64_t
#include <utility> // pair, move()
#include <stdexcept> // runtime_error
#include <functional>
#endif
// Other includes.
#ifdef __cpp_modules
export module butl.manifest_parser;
#ifdef __cpp_lib_modules
import std.core;
import std.io;
#endif
import butl.char_scanner;
import butl.manifest_types;
#else
#include <libbutl/char-scanner.mxx>
#include <libbutl/manifest-types.mxx>
#endif
#include <libbutl/export.hxx>
LIBBUTL_MODEXPORT namespace butl
{
class LIBBUTL_SYMEXPORT manifest_parsing: public std::runtime_error
{
public:
manifest_parsing (const std::string& name,
std::uint64_t line,
std::uint64_t column,
const std::string& description);
std::string name;
std::uint64_t line;
std::uint64_t column;
std::string description;
};
class LIBBUTL_SYMEXPORT manifest_parser: protected butl::char_scanner
{
public:
// The filter, if specified, is called by next() prior to returning the
// pair to the caller. If the filter returns false, then the pair is
// discarded.
//
// Note that the filter should handle the end-of-manifest pairs (see
// below) carefully, so next() doesn't end up with an infinite cycle.
//
using filter_function = bool (manifest_name_value&);
manifest_parser (std::istream& is,
const std::string& name,
std::function<filter_function> filter = {})
: char_scanner (is), name_ (name), filter_ (std::move (filter)) {}
const std::string&
name () const {return name_;}
// The first returned pair is special "start-of-manifest" with
// empty name and value being the format version: {"", "<ver>"}.
// After that we have a sequence of ordinary pairs which are
// the manifest. At the end of the manifest we have the special
// "end-of-manifest" pair with empty name and value: {"", ""}.
// After that we can either get another start-of-manifest pair
// (in which case the whole sequence repeats from the beginning)
// or we get another end-of-manifest pair which signals the end
// of stream (aka EOF). To put it another way, the parse sequence
// always has the following form:
//
// ({"", "<ver>"} {"<name>", "<value>"}* {"", ""})* {"", ""}
//
manifest_name_value
next ();
// Split the manifest value, optionally followed by ';' character and a
// comment into the value/comment pair. Note that ';' characters in the
// value must be escaped by the backslash.
//
static std::pair<std::string, std::string>
split_comment (const std::string&);
private:
void
parse_next (manifest_name_value&);
void
parse_name (manifest_name_value&);
void
parse_value (manifest_name_value&);
// Skip spaces and return the first peeked non-space character and the
// starting position of the line it belongs to. If the later is not
// available (skipped spaces are all in the middle of a line, we are at
// eos, etc.), then fallback to the first peeked character position.
//
std::pair<xchar, std::uint64_t>
skip_spaces ();
private:
const std::string name_;
const std::function<filter_function> filter_;
enum {start, body, end} s_ = start;
std::string version_; // Current format version.
};
}
#include <libbutl/manifest-parser.ixx>
|