os: turn Xml_node::Attribute to Xml_attribute
Moving the XML attribute class to the Genode namespace simplifies the API.
This commit is contained in:
parent
394fce110e
commit
e1b4408090
|
@ -17,31 +17,69 @@
|
||||||
#include <util/token.h>
|
#include <util/token.h>
|
||||||
#include <base/exception.h>
|
#include <base/exception.h>
|
||||||
|
|
||||||
namespace Genode { class Xml_node; }
|
namespace Genode {
|
||||||
|
|
||||||
|
class Xml_attribute;
|
||||||
|
class Xml_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Representation of an XML node
|
* Representation of an XML-node attribute
|
||||||
|
*
|
||||||
|
* An attribute has the form 'name="value"'.
|
||||||
*/
|
*/
|
||||||
class Genode::Xml_node
|
class Genode::Xml_attribute
|
||||||
{
|
{
|
||||||
/**
|
private:
|
||||||
* Scanner policy that accepts hyphens in identifiers
|
|
||||||
*/
|
|
||||||
struct Scanner_policy_xml_identifier {
|
|
||||||
static bool identifier_char(char c, unsigned i) {
|
|
||||||
return is_letter(c) || c == '_' || c == ':'
|
|
||||||
|| (i && (c == '-' || c == '.' || is_digit(c))); } };
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define tokenizer that matches XML tags (with hyphens) as identifiers
|
* Scanner policy that accepts hyphens in identifiers
|
||||||
*/
|
*/
|
||||||
typedef ::Genode::Token<Scanner_policy_xml_identifier> Token;
|
struct Scanner_policy_xml_identifier {
|
||||||
|
static bool identifier_char(char c, unsigned i) {
|
||||||
|
return is_letter(c) || c == '_' || c == ':'
|
||||||
|
|| (i && (c == '-' || c == '.' || is_digit(c))); } };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Forward declaration needed for befriending Tag with Attribut
|
* Define tokenizer that matches XML tags (with hyphens) as identifiers
|
||||||
*/
|
*/
|
||||||
class Tag;
|
typedef ::Genode::Token<Scanner_policy_xml_identifier> Token;
|
||||||
|
|
||||||
|
Token _name;
|
||||||
|
Token _value;
|
||||||
|
|
||||||
|
friend class Xml_node;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Even though 'Tag' is part of 'Xml_node', the friendship
|
||||||
|
* to 'Xml_node' does not apply for 'Tag' when compiling
|
||||||
|
* the code with 'gcc-3.4'. Hence, we need to add an
|
||||||
|
* explicit friendship to 'Tag'.
|
||||||
|
*/
|
||||||
|
friend class Tag;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* This constructor is meant to be used as implicitly to
|
||||||
|
* construct an 'Xml_attribute' from a token sequence via an
|
||||||
|
* assignment from the leading 'Token'.
|
||||||
|
*/
|
||||||
|
Xml_attribute(Token t) :
|
||||||
|
_name(t.eat_whitespace()), _value(_name.next().next())
|
||||||
|
{
|
||||||
|
if (_name.type() != Token::IDENT)
|
||||||
|
throw Nonexistent_attribute();
|
||||||
|
|
||||||
|
if (_name.next()[0] != '=' || _value.type() != Token::STRING)
|
||||||
|
throw Invalid_syntax();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return token following the attribute declaration
|
||||||
|
*/
|
||||||
|
Token _next() const { return _name.next().next().next(); }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -49,136 +87,121 @@ class Genode::Xml_node
|
||||||
** Exception types **
|
** Exception types **
|
||||||
*********************/
|
*********************/
|
||||||
|
|
||||||
class Exception : public ::Genode::Exception { };
|
|
||||||
class Invalid_syntax : public Exception { };
|
class Invalid_syntax : public Exception { };
|
||||||
class Nonexistent_sub_node : public Exception { };
|
|
||||||
class Nonexistent_attribute : public Exception { };
|
class Nonexistent_attribute : public Exception { };
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Representation of an XML-node attribute
|
* Return attribute type as null-terminated string
|
||||||
*
|
|
||||||
* An attribute has the form 'name="value"'.
|
|
||||||
*/
|
*/
|
||||||
class Attribute
|
void type(char *dst, size_t max_len) const
|
||||||
{
|
{
|
||||||
private:
|
/*
|
||||||
|
* Limit number of characters by token length, take
|
||||||
|
* null-termination into account.
|
||||||
|
*/
|
||||||
|
max_len = min(max_len, _name.len() + 1);
|
||||||
|
strncpy(dst, _name.start(), max_len);
|
||||||
|
}
|
||||||
|
|
||||||
Token _name;
|
/**
|
||||||
Token _value;
|
* Return true if attribute has specified type
|
||||||
|
*/
|
||||||
|
bool has_type(const char *type) {
|
||||||
|
return strlen(type) == _name.len() &&
|
||||||
|
strcmp(type, _name.start(), _name.len()) == 0; }
|
||||||
|
|
||||||
friend class Xml_node;
|
/**
|
||||||
|
* Return size of value
|
||||||
|
*/
|
||||||
|
size_t value_size() const { return _value.len() - 2; }
|
||||||
|
char const *value_base() const { return _value.start() + 1; }
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Even though 'Tag' is part of 'Xml_node', the friendship
|
* Return attribute value as null-terminated string
|
||||||
* to 'Xml_node' does not apply for 'Tag' when compiling
|
*
|
||||||
* the code with 'gcc-3.4'. Hence, we need to add an
|
* \return true on success, or
|
||||||
* explicit friendship to 'Tag'.
|
* false if attribute is invalid
|
||||||
*/
|
*/
|
||||||
friend class Tag;
|
bool value(char *dst, size_t max_len) const
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The value of 'max_len' denotes the maximum number of
|
||||||
|
* characters to be written to 'dst' including the null
|
||||||
|
* termination. From the quoted value string, we strip
|
||||||
|
* both quote characters and add a null-termination
|
||||||
|
* character.
|
||||||
|
*/
|
||||||
|
max_len = min(max_len, _value.len() - 2 + 1);
|
||||||
|
strncpy(dst, _value.start() + 1, max_len);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Return true if attribute has the specified value
|
||||||
*
|
*/
|
||||||
* This constructor is meant to be used as implicitly to
|
bool has_value(const char *value) const {
|
||||||
* construct an 'Xml_attribute' from a token sequence via an
|
return strlen(value) == (_value.len() - 2) &&
|
||||||
* assignment from the leading 'Token'.
|
!strcmp(value, _value.start() + 1, _value.len() - 2); }
|
||||||
*/
|
|
||||||
Attribute(Token t) :
|
|
||||||
_name(t.eat_whitespace()), _value(_name.next().next())
|
|
||||||
{
|
|
||||||
if (_name.type() != Token::IDENT)
|
|
||||||
throw Nonexistent_attribute();
|
|
||||||
|
|
||||||
if (_name.next()[0] != '=' || _value.type() != Token::STRING)
|
/**
|
||||||
throw Invalid_syntax();
|
* Return attribute value as typed value
|
||||||
}
|
*
|
||||||
|
* \param T type of value to read
|
||||||
|
* \return true on success, or
|
||||||
|
* false if attribute is invalid or value
|
||||||
|
* conversion failed
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
bool value(T *out) const
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The '_value' token starts with a quote, which we
|
||||||
|
* need to skip to access the string. For validating
|
||||||
|
* the length, we have to consider both the starting
|
||||||
|
* and the trailing quote character.
|
||||||
|
*/
|
||||||
|
return ascii_to(_value.start() + 1, out) == _value.len() - 2;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return token following the attribute declaration
|
* Return next attribute in attribute list
|
||||||
*/
|
*/
|
||||||
Token _next() const { return _name.next().next().next(); }
|
Xml_attribute next() const { return Xml_attribute(_next()); }
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return attribute type as null-terminated string
|
* Representation of an XML node
|
||||||
*/
|
*/
|
||||||
void type(char *dst, size_t max_len) const
|
class Genode::Xml_node
|
||||||
{
|
{
|
||||||
/*
|
private:
|
||||||
* Limit number of characters by token length, take
|
|
||||||
* null-termination into account.
|
|
||||||
*/
|
|
||||||
max_len = min(max_len, _name.len() + 1);
|
|
||||||
strncpy(dst, _name.start(), max_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
typedef Xml_attribute::Token Token;
|
||||||
* Return true if attribute has specified type
|
|
||||||
*/
|
|
||||||
bool has_type(const char *type) {
|
|
||||||
return strlen(type) == _name.len() &&
|
|
||||||
strcmp(type, _name.start(), _name.len()) == 0; }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return size of value
|
* Forward declaration needed for befriending Tag with Xml_attribute
|
||||||
*/
|
*/
|
||||||
size_t value_size() const { return _value.len() - 2; }
|
class Tag;
|
||||||
char const *value_base() const { return _value.start() + 1; }
|
|
||||||
|
|
||||||
/**
|
public:
|
||||||
* Return attribute value as null-terminated string
|
|
||||||
*
|
|
||||||
* \return true on success, or
|
|
||||||
* false if attribute is invalid
|
|
||||||
*/
|
|
||||||
bool value(char *dst, size_t max_len) const
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* The value of 'max_len' denotes the maximum number of
|
|
||||||
* characters to be written to 'dst' including the null
|
|
||||||
* termination. From the quoted value string, we strip
|
|
||||||
* both quote characters and add a null-termination
|
|
||||||
* character.
|
|
||||||
*/
|
|
||||||
max_len = min(max_len, _value.len() - 2 + 1);
|
|
||||||
strncpy(dst, _value.start() + 1, max_len);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/*********************
|
||||||
* Return true if attribute has the specified value
|
** Exception types **
|
||||||
*/
|
*********************/
|
||||||
bool has_value(const char *value) const {
|
|
||||||
return strlen(value) == (_value.len() - 2) &&
|
|
||||||
!strcmp(value, _value.start() + 1, _value.len() - 2); }
|
|
||||||
|
|
||||||
/**
|
typedef Genode::Exception Exception;
|
||||||
* Return attribute value as typed value
|
typedef Xml_attribute::Nonexistent_attribute Nonexistent_attribute;
|
||||||
*
|
typedef Xml_attribute::Invalid_syntax Invalid_syntax;
|
||||||
* \param T type of value to read
|
|
||||||
* \return true on success, or
|
|
||||||
* false if attribute is invalid or value
|
|
||||||
* conversion failed
|
|
||||||
*/
|
|
||||||
template <typename T>
|
|
||||||
bool value(T *out) const
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* The '_value' token starts with a quote, which we
|
|
||||||
* need to skip to access the string. For validating
|
|
||||||
* the length, we have to consider both the starting
|
|
||||||
* and the trailing quote character.
|
|
||||||
*/
|
|
||||||
return ascii_to(_value.start() + 1, out) == _value.len() - 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
class Nonexistent_sub_node : public Exception { };
|
||||||
* Return next attribute in attribute list
|
|
||||||
*/
|
|
||||||
Attribute next() const { return Attribute(_next()); }
|
/**
|
||||||
};
|
* Type definition for maintaining backward compatibility
|
||||||
|
*/
|
||||||
|
typedef Xml_attribute Attribute;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -231,7 +254,7 @@ class Genode::Xml_node
|
||||||
Token delimiter = _name.next();
|
Token delimiter = _name.next();
|
||||||
if (supposed_type != END)
|
if (supposed_type != END)
|
||||||
try {
|
try {
|
||||||
for (Attribute a = _name.next(); ; a = a._next())
|
for (Xml_attribute a = _name.next(); ; a = a._next())
|
||||||
delimiter = a._next();
|
delimiter = a._next();
|
||||||
} catch (Nonexistent_attribute) { }
|
} catch (Nonexistent_attribute) { }
|
||||||
|
|
||||||
|
@ -303,7 +326,7 @@ class Genode::Xml_node
|
||||||
/**
|
/**
|
||||||
* Return first attribute of tag
|
* Return first attribute of tag
|
||||||
*/
|
*/
|
||||||
Attribute attribute() const { return Attribute(_name.next()); }
|
Xml_attribute attribute() const { return Xml_attribute(_name.next()); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class Comment
|
class Comment
|
||||||
|
@ -694,10 +717,10 @@ class Genode::Xml_node
|
||||||
* \throw Nonexistent_attribute no such attribute exists
|
* \throw Nonexistent_attribute no such attribute exists
|
||||||
* \return XML attribute
|
* \return XML attribute
|
||||||
*/
|
*/
|
||||||
Attribute attribute(unsigned idx) const
|
Xml_attribute attribute(unsigned idx) const
|
||||||
{
|
{
|
||||||
/* get first attribute of the node */
|
/* get first attribute of the node */
|
||||||
Attribute a = _start_tag.attribute();
|
Xml_attribute a = _start_tag.attribute();
|
||||||
|
|
||||||
/* skip attributes until we reach the target index */
|
/* skip attributes until we reach the target index */
|
||||||
for (; idx > 0; idx--)
|
for (; idx > 0; idx--)
|
||||||
|
@ -713,10 +736,10 @@ class Genode::Xml_node
|
||||||
* \throw Nonexistent_attribute no such attribute exists
|
* \throw Nonexistent_attribute no such attribute exists
|
||||||
* \return XML attribute
|
* \return XML attribute
|
||||||
*/
|
*/
|
||||||
Attribute attribute(const char *type) const
|
Xml_attribute attribute(const char *type) const
|
||||||
{
|
{
|
||||||
/* iterate, beginning with the first attribute of the node */
|
/* iterate, beginning with the first attribute of the node */
|
||||||
for (Attribute a = _start_tag.attribute(); ; a = a.next())
|
for (Xml_attribute a = _start_tag.attribute(); ; a = a.next())
|
||||||
if (a.has_type(type))
|
if (a.has_type(type))
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue