29 std::string
make_link(
const std::string& text,
const std::string&
dst)
32 return formatter() <<
"<ref dst='" <<
dst <<
"'>" << text <<
"</ref>";
35 std::string
img(
const std::string&
src,
const std::string& align,
bool floating)
38 <<
"<img src='" <<
src <<
"' "
39 <<
"float='" << std::boolalpha << floating <<
"' "
40 <<
"align='" << align <<
"' "
97 static std::string
position_info(
const std::string::const_iterator& text_start,
const std::string::const_iterator& error_position)
100 int lines = std::count(text_start, error_position,
'\n') + 1;
103 auto pos = error_position;
104 for(; pos != text_start && *pos !=
'\n'; pos--);
107 <<
", character " <<
utf8::size(pos, error_position);
114 enum { UNKNOWN, NAMED, HEX, DECIMAL }
type = UNKNOWN;
117 for(; beg != end && *beg !=
';'; ++beg) {
122 }
else if(isalnum(*beg) || *beg ==
'_') {
126 throw parse_error(beg,
"invalid entity: unexpected characters after '&', alphanumeric characters, '#' or '_' expected.");
131 throw parse_error(beg,
"invalid entity: non-alphanumeric characters after '&'.");
138 }
else if(isdigit(*beg)) {
141 throw parse_error(beg,
"invalid entity: unexpected characters after '&#', numbers or 'x' expected.");
148 throw parse_error(beg,
"invalid entity: unexpected characters after '&#x', hexadecimal digits expected.");
154 std::string name =
s.str();
155 entity[
"name"] = name;
157 entity[
"code_point"] =
'<';
158 }
else if(name ==
"gt") {
159 entity[
"code_point"] =
'>';
160 }
else if(name ==
"apos") {
161 entity[
"code_point"] =
'\'';
162 }
else if(name ==
"quot") {
163 entity[
"code_point"] =
'"';
164 }
else if(name ==
"amp") {
165 entity[
"code_point"] =
'&';
174 entity[
"code_point"] =
n;
179 static char parse_escape(std::string::const_iterator& beg, std::string::const_iterator end)
181 assert(*beg ==
'\\');
184 if((beg + 1) != end) {
195 std::ostringstream
s;
196 bool saw_newline =
false;
198 for(; beg != end && *beg != close; ++beg) {
202 throw parse_error(beg,
"unexpected end of stream after entity");
204 if(entity.has_attribute(
"code_point")) {
205 s << unicode_cast<std::string>(entity[
"code_point"].to_int());
209 res.
add_child(
"character_entity", entity);
212 }
else if(*beg ==
'\\') {
214 }
else if(*beg ==
'\n') {
235 assert(beg == end || *beg == close);
239 static std::string
parse_name(std::string::const_iterator& beg, std::string::const_iterator end)
241 std::ostringstream
s;
242 for(; beg != end && (isalnum(*beg) || *beg ==
'_'); ++beg) {
248 static std::pair<std::string, std::string>
parse_attribute(std::string::const_iterator& beg, std::string::const_iterator end,
bool allow_empty)
250 std::string attr =
parse_name(beg, end), value;
254 while(isspace(*beg)) ++beg;
260 return {attr, value};
261 }
else throw parse_error(beg,
"attribute missing value in old-style tag");
264 while(isspace(*beg)) ++beg;
265 if(*beg ==
'\'' || *beg ==
'"') {
268 throw parse_error(beg,
"unsupported entity in attribute value");
270 throw parse_error(beg,
"paragraph break in attribute value");
273 value =
t[
"text"].str();
276 std::ostringstream
s;
277 bool found_slash =
false;
278 for(; beg != end && *beg !=
'>' && *beg !=
'<' && !isspace(*beg); ++beg) {
282 throw parse_error(beg,
"unexpected end of stream after entity");
284 if(entity.has_attribute(
"code_point")) {
285 s << unicode_cast<std::string>(entity[
"code_point"].to_int());
287 throw parse_error(beg,
"unsupported entity in attribute value");
289 }
else if(*beg ==
'\\') {
291 }
else if(*beg ==
'/') {
305 if(found_slash) --beg;
307 return {attr, value};
310 static void check_closing_tag(std::string::const_iterator& beg, std::string::const_iterator end, std::string_view match)
312 std::size_t remaining = end - beg;
313 assert(remaining >= 2 && *beg ==
'<' && *(beg + 1) ==
'/');
314 if(remaining < match.size() + 3) {
315 throw parse_error(beg,
"Unexpected end of stream in closing tag");
318 if(!std::equal(match.begin(), match.end(), beg)) {
319 throw parse_error(beg,
"Mismatched closing tag " + std::string(match));
323 throw parse_error(beg,
"Unterminated closing tag " + std::string(match));
328 static std::pair<std::string, config>
parse_tag(std::string::const_iterator& beg, std::string::const_iterator end);
329 static config parse_tag_contents(std::string::const_iterator& beg, std::string::const_iterator end, std::string_view match,
bool check_for_attributes)
335 for(; check_for_attributes && beg != end && *beg !=
'<'; ++beg) {
336 if(isspace(*beg))
continue;
343 while(beg != end && isspace(*beg)) ++beg;
348 if(beg == end || *beg !=
'<' || (beg + 1) == end || *(beg + 1) !=
'/') {
349 throw parse_error(beg,
"Extra text at the end of old-style tag with explicit 'text' attribute");
355 if(beg == end || *beg !=
'<' || (beg + 1) == end || *(beg + 1) !=
'/') {
356 throw parse_error(beg,
"Extra text at the end of old-style tag with explicit 'text' attribute");
368 if(beg == end || beg + 1 == end) {
369 throw parse_error(beg,
"Missing closing tag for " + std::string(match));
372 if(*(beg + 1) ==
'/') {
385 static std::pair<std::string, config>
parse_tag(std::string::const_iterator& beg, std::string::const_iterator end)
390 if(tag_name.empty()) {
393 bool auto_closed =
false;
395 for(; beg != end && *beg !=
'>'; ++beg) {
396 if(isspace(*beg))
continue;
397 if(*beg ==
'/' && (beg + 1) != end && *(beg + 1) ==
'>') {
399 }
else if(isalnum(*beg) || *beg ==
'_') {
402 throw parse_error(beg,
"unexpected end of stream following attribute");
413 elem[
"text"] = contents[
"text"];
418 return {tag_name, elem};
424 auto beg = text.begin(), end = text.end();
439 e.message =
position_info(text.begin(),
e.error_location()) +
": " +
e.message;
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)
Definitions for the interface to Wesnoth Markup Language (WML).
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 img(const std::string &src, const std::string &align, bool floating)
Generates a Help markup tag corresponding to an image.
std::string make_link(const std::string &text, const std::string &dst)
Generates a Help markup tag corresponding to a reference or link.
static std::string position_info(const std::string::const_iterator &text_start, const std::string::const_iterator &error_position)
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)
std::string tag(std::string_view tag, Args &&... data)
Wraps the given data in the specified tag.
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.
std::size_t size(std::string_view str)
Length in characters of a UTF-8 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