2 * @brief Field parsing for Omega.
4 /* Copyright 2018 Olly Betts
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
22 #ifndef OMEGA_INCLUDED_FIELDS_H
23 #define OMEGA_INCLUDED_FIELDS_H
25 #include <unordered_map>
30 std::unordered_map
<std::string
, std::string
> fields
;
37 * @param data The data to parse.
39 * @param names If non-NULL and not pointing to an empty string, then
40 * specifies the field names for corresponding lines in
43 void parse_fields(const std::string
& data
, const std::string
* names
);
45 /// Lookup field @a name.
46 const std::string
& get_field(const std::string
& name
) const {
47 auto it
= fields
.find(name
);
48 if (it
!= fields
.end()) {
51 const static std::string empty_string
;
57 Fields::parse_fields(const std::string
& data
,
58 const std::string
* names
)
62 if (names
&& !names
->empty()) {
63 // Each line in data is a field, with field names taken from
64 // corresponding entries in the tab-separated list specified by names.
65 std::string::size_type v
= 0;
66 std::string::size_type n
= 0;
68 std::string::size_type n_start
= n
;
69 n
= names
->find('\t', n
);
70 std::string::size_type v_start
= v
;
71 v
= data
.find('\n', v
);
72 fields
.emplace(names
->substr(n_start
, n
- n_start
),
73 data
.substr(v_start
, v
- v_start
));
74 // If n or v is std::string::npos then incrementing wraps to 0.
79 // Each line specifies a field in the format NAME=VALUE, where NAME doesn't
80 // contain "=" but VALUE may.
81 std::string::size_type i
= 0;
83 std::string::size_type n_start
= i
;
85 while ((ch
= data
[i
]) != '=') {
86 // Fast test for '\n' or '\0', with false positives for '\x02' and
87 // '\x08' (the latter two are probably unlikely in this context).
88 if (rare((ch
&~ '\n') == 0)) {
89 // Lines without an '=' should be rare.
91 // No "=" in this line - such lines are ignored.
95 if (i
== data
.size()) {
102 std::string::size_type eq
= i
;
104 // Scan ahead to the end of the line.
105 while ((ch
= data
[++i
]) != '\n') {
106 if (ch
== '\0' && i
== data
.size()) {
107 i
= std::string::npos
;
112 std::string::size_type v
= eq
+ 1;
113 std::string
name(data
, n_start
, eq
- n_start
);
114 auto r
= fields
.emplace(name
, std::string());
116 // New entry - fill in.
117 r
.first
->second
.assign(data
, v
, i
- v
);
119 // Existing entry, so accumulate values as tab-separated list.
120 std::string
& value
= r
.first
->second
;
122 value
.append(data
, v
, i
- v
);
124 // If i is std::string::npos then incrementing wraps to 0.
128 #endif // OMEGA_INCLUDED_FIELDS_H