23 std::string
make_link(
const std::string& text,
const std::string&
dst)
26 return "<ref dst='" +
dst+
"'>" + text +
"</ref>";
29 std::string
img(
const std::string&
src,
const std::string& align,
const bool floating)
32 <<
"<img src='" <<
src <<
"' "
33 <<
"float='" << std::boolalpha << floating <<
"' "
34 <<
"align='" << align <<
"' "
94 enum { UNKNOWN, NAMED, HEX, DECIMAL }
type = UNKNOWN;
97 for(; beg != end && *beg !=
';'; ++beg) {
102 }
else if(isalnum(*beg) || *beg ==
'_') {
118 }
else if(isdigit(*beg)) {
134 std::string name =
s.str();
135 entity[
"name"] = name;
137 entity[
"code_point"] =
'<';
138 }
else if(name ==
"gt") {
139 entity[
"code_point"] =
'>';
140 }
else if(name ==
"apos") {
141 entity[
"code_point"] =
'\'';
142 }
else if(name ==
"quot") {
143 entity[
"code_point"] =
'"';
144 }
else if(name ==
"amp") {
145 entity[
"code_point"] =
'&';
154 entity[
"code_point"] =
n;
159 static char parse_escape(std::string::const_iterator& beg, std::string::const_iterator end)
161 assert(*beg ==
'\\');
164 if((beg + 1) != end) {
175 std::ostringstream
s;
176 bool saw_newline =
false;
178 for(; beg != end && *beg != close; ++beg) {
184 if(entity.has_attribute(
"code_point")) {
185 s << unicode_cast<std::string>(entity[
"code_point"].to_int());
189 res.
add_child(
"character_entity", entity);
192 }
else if(*beg ==
'\\') {
194 }
else if(*beg ==
'\n') {
215 assert(beg == end || *beg == close);
219 static std::string
parse_name(std::string::const_iterator& beg, std::string::const_iterator end)
221 std::ostringstream
s;
222 for(; beg != end && (isalnum(*beg) || *beg ==
'_'); ++beg) {
228 static std::pair<std::string, std::string>
parse_attribute(std::string::const_iterator& beg, std::string::const_iterator end,
bool allow_empty)
230 std::string attr =
parse_name(beg, end), value;
234 while(isspace(*beg)) ++beg;
240 return {attr, value};
241 }
else throw parse_error(
"attribute missing value in old-style tag");
244 while(isspace(*beg)) ++beg;
245 if(*beg ==
'\'' || *beg ==
'"') {
248 throw parse_error(
"unsupported entity in attribute value");
250 throw parse_error(
"paragraph break in attribute value");
253 value =
t[
"text"].str();
256 std::ostringstream
s;
257 bool found_slash =
false;
258 for(; beg != end && *beg !=
'>' && *beg !=
'<' && !isspace(*beg); ++beg) {
264 if(entity.has_attribute(
"code_point")) {
265 s << unicode_cast<std::string>(entity[
"code_point"].to_int());
267 throw parse_error(
"unsupported entity in attribute value");
269 }
else if(*beg ==
'\\') {
271 }
else if(*beg ==
'/') {
285 if(found_slash) --beg;
287 return {attr, value};
290 static void check_closing_tag(std::string::const_iterator& beg, std::string::const_iterator end, std::string_view match)
292 size_t remaining = end - beg;
293 assert(remaining >= 2 && *beg ==
'<' && *(beg + 1) ==
'/');
294 if(remaining < match.size() + 3) {
295 throw parse_error(
"Unexpected eos in closing tag");
298 if(!std::equal(match.begin(), match.end(), beg)) {
308 static std::pair<std::string, config>
parse_tag(std::string::const_iterator& beg, std::string::const_iterator end);
309 static config parse_tag_contents(std::string::const_iterator& beg, std::string::const_iterator end, std::string_view match,
bool check_for_attributes)
315 for(; check_for_attributes && beg != end && *beg !=
'<'; ++beg) {
316 if(isspace(*beg))
continue;
323 while(beg != end && isspace(*beg)) ++beg;
328 if(beg == end || *beg !=
'<' || (beg + 1) == end || *(beg + 1) !=
'/') {
329 throw parse_error(
"Extra text at the end of old-style tag with explicit 'text' attribute");
335 if(beg == end || *beg !=
'<' || (beg + 1) == end || *(beg + 1) !=
'/') {
336 throw parse_error(
"Extra text at the end of old-style tag with explicit 'text' attribute");
348 if(beg == end || beg + 1 == end) {
352 if(*(beg + 1) ==
'/') {
365 static std::pair<std::string, config>
parse_tag(std::string::const_iterator& beg, std::string::const_iterator end)
370 if(tag_name.empty()) {
373 bool auto_closed =
false;
375 for(; beg != end && *beg !=
'>'; ++beg) {
376 if(isspace(*beg))
continue;
377 if(*beg ==
'/' && (beg + 1) != end && *(beg + 1) ==
'>') {
379 }
else if(isalnum(*beg) || *beg ==
'_') {
382 throw parse_error(
"unexpected eos following attribute");
393 elem[
"text"] = contents[
"text"];
398 return {tag_name, elem};
404 auto beg = text.begin(), end = text.end();
A config object defines a single node in a WML file, with access to child nodes.
void append(const config &cfg)
Append data from another config object to this one.
std::size_t attribute_count() const
Count the number of non-blank attributes.
config & mandatory_child(config_key_type key, int n=0)
Returns the nth child with the given key, or throws an error if there is none.
bool has_child(config_key_type key) const
Determine whether a config has a child or not.
bool has_attribute(config_key_type key) const
std::size_t all_children_count() const
void append_children(const config &cfg)
Adds children from cfg.
optional_config_impl< config > optional_child(config_key_type key, int n=0)
Equivalent to mandatory_child, but returns an empty optional if the nth child was not found.
config & add_child(config_key_type key)
static std::string parse_name(std::string::const_iterator &beg, std::string::const_iterator end)
static config parse_tag_contents(std::string::const_iterator &beg, std::string::const_iterator end, std::string_view match, bool check_for_attributes)
std::string make_link(const std::string &text, const std::string &dst)
std::string img(const std::string &src, const std::string &align, const bool floating)
std::string tag(const std::string &tag_name, Args &&... contents)
static std::pair< std::string, std::string > parse_attribute(std::string::const_iterator &beg, std::string::const_iterator end, bool allow_empty)
static std::pair< std::string, config > parse_tag(std::string::const_iterator &beg, std::string::const_iterator end)
static char parse_escape(std::string::const_iterator &beg, std::string::const_iterator end)
static config parse_text_until(std::string::const_iterator &beg, std::string::const_iterator end, char close)
static config parse_entity(std::string::const_iterator &beg, std::string::const_iterator end)
static void check_closing_tag(std::string::const_iterator &beg, std::string::const_iterator end, std::string_view match)
config parse_text(const std::string &text)
Parse a xml style marked up text string.
rect dst
Location on the final composed sheet.
rect src
Non-transparent portion of the surface to compose.
Thrown when the help system fails to parse something.
static map_location::direction n
static map_location::direction s