Files
NE_YuR/openflow/include/click/args.hh

1410 lines
46 KiB
C++

// -*- c-basic-offset: 4; related-file-name: "../../lib/args.cc" -*-
#ifndef CLICK_ARGS_HH
#define CLICK_ARGS_HH
#include <click/type_traits.hh>
#include <click/vector.hh>
#include <click/string.hh>
#include <click/confparse.hh>
#include <click/timestamp.hh>
#if CLICK_BSDMODULE
# include <machine/stdarg.h>
#else
# include <stdarg.h>
#endif
CLICK_DECLS
class Element;
class ErrorHandler;
/** @class ArgContext
@brief Argument context class.
The ArgContext class encapsulates state useful for parsing arguments: an
element context and an ErrorHandler for reporting parse errors.
Args is derived from ArgContext. Some parser functions take an ArgContext
reference rather than an Args reference. This clarifies that the parser
function doesn't modify Args internals. Also, ArgContext objects are smaller
and quicker to construct than Args objects.
*/
class ArgContext { public:
/** @brief Construct an argument context.
* @param errh optional error handler */
ArgContext(ErrorHandler *errh = 0)
: _errh(errh), _arg_keyword(0), _read_status(false) {
#if !CLICK_TOOL
_context = 0;
#endif
}
#if !CLICK_TOOL
/** @brief Construct an argument context.
* @param context optional element context
* @param errh optional error handler */
ArgContext(const Element *context, ErrorHandler *errh = 0)
: _context(context), _errh(errh), _arg_keyword(0), _read_status(false) {
}
/** @brief Return the element context. */
const Element *context() const {
return _context;
}
#endif
/** @brief Return the associated error handler. */
ErrorHandler *errh() const {
return _errh;
}
/** @brief Return a prefix string associated with the current argument.
*
* If the current argument is keyword FOO, returns "FOO: ". */
String error_prefix() const;
/** @brief Report a parse error for the current argument. */
void error(const char *fmt, ...) const;
/** @brief Report a parse warning for the current argument. */
void warning(const char *fmt, ...) const;
/** @brief Report a message for the current argument. */
void message(const char *fmt, ...) const;
void xmessage(const String &anno, const String &str) const;
void xmessage(const String &anno, const char *fmt, va_list val) const;
protected:
#if !CLICK_TOOL
const Element *_context;
#endif
ErrorHandler *_errh;
const char *_arg_keyword;
mutable bool _read_status;
};
/** @cond never */
template <typename T> struct Args_has_enable_direct_parse {
private:
template <typename X> static char test(typename X::enable_direct_parse *);
template <typename> static int test(...);
public:
enum { value = (sizeof(test<T>(0)) == 1) };
};
template <typename P, bool direct = Args_has_enable_direct_parse<P>::value>
struct Args_parse_helper;
template <typename P> struct Args_parse_helper<P, false> {
template <typename T, typename A>
static inline T *slot(T &variable, A &args) {
return args.slot(variable);
}
template <typename T, typename A>
static inline T *initialized_slot(T &variable, A &args) {
return args.initialized_slot(variable);
}
template <typename T, typename A>
static inline bool parse(P parser, const String &str, T &s, A &args) {
return parser.parse(str, s, args);
}
template <typename T1, typename T2, typename A>
static inline bool parse(P parser, const String &str, T1 &s1, T2 &s2, A &args) {
return parser.parse(str, s1, s2, args);
}
};
template <typename P> struct Args_parse_helper<P, true> {
template <typename T, typename A>
static inline T *slot(T &variable, A &) {
return &variable;
}
template <typename T, typename A>
static inline T *initialized_slot(T &variable, A &) {
return &variable;
}
template <typename T, typename A>
static inline bool parse(P parser, const String &str, T &s, A &args) {
return parser.direct_parse(str, s, args);
}
template <typename T1, typename T2, typename A>
static inline bool parse(P parser, const String &str, T1 &s1, T2 &s2, A &args) {
return parser.direct_parse(str, s1, s2, args);
}
};
/** @endcond never */
/** @class Args
@brief Argument parser class.
Args parses Click configuration strings in a type-safe manner.
Args manages <em>arguments</em> and <em>result slots</em>. Arguments are
strings to be parsed and result slots are parsed values.
The read() functions parse arguments into result slots.
@code
Args args;
args.push_back("A 1"); // add argument
int a_result;
args.read("A", a_result); // parse "A" into a result slot
@endcode
As arguments are parsed, Args marks them off and adds new result slots.
Each result slot is paired with a variable belonging to the caller.
However, the caller's variables aren't modified until the parse
<em>executes</em> via complete(), consume(), or execute().
@code
Args args; args.push_back("A 1");
int a_result = 0;
args.read("A", a_result);
assert(a_result == 0); // parsed value not yet assigned
args.execute(); // this call assigns results
assert(a_result == 1);
@endcode
If Args encounters a parse error, then execution doesn't modify
<em>any</em> of the caller's variables.
@code
Args args; args.push_back("A 1, B NOT_AN_INTEGER");
int a_result = 0, b_result = 0;
args.read("A", a_result) // succeeds
.read("B", b_result) // fails, since B is not an integer
.execute();
assert(a_result == 0 && b_result == 0);
@endcode
Each read() function comes in five variants. read() reads an optional
keyword argument. read_m() reads a mandatory keyword argument: if the
argument was not supplied, Args will report a parse error. read_p() reads
an optional positional argument. If the keyword was not supplied, but a
positional argument was, that is used. read_mp() reads a mandatory
positional argument. Positional arguments are parsed in order. The fifth
variant of read() takes an integer <em>flags</em> argument; flags include
Args::positional, Args::mandatory, and others, such as Args::deprecated.
The complete() execution method checks that every argument has been
successfully parsed and reports an error if not. consume()
doesn't check for completion, but removes parsed arguments from the
argument set. Execution methods return 0 on success and <0 on failure.
You can check the parse status before execution using status().
Args methods are designed to chain. All read() methods (and some others)
return a reference to the Args itself. It is often possible to parse a
whole set of arguments using a single temporary Args. For example:
@code
Vector<String> conf;
conf.push_back("A 1");
conf.push_back("B 2");
int a, b;
if (Args(conf).read("A", a)
.read("B", b)
.complete() >= 0)
click_chatter("Success! a=%d, b=%d", a, b);
@endcode
The actual work of parsing is handled by <em>parser objects</em>. Many
common variable types have default parsers defined by the DefaultArg<T>
template. For example, the default parser for an integer value understands
the common textual representations of integers. You can also pass a parser
explicitly. For example:
@code
int a, b, c;
args.read("A", a) // parse A using DefaultArg<int> = IntArg()
.read("B", IntArg(2), b); // parse B using IntArg(2): base-2
@endcode
Args generally calls a parser object's parse() method with three arguments:
<ol>
<li>const String &<b>str</b>: The string to be parsed.</li>
<li>T &<b>result</b>: A reference to the result. The parsed value, if any,
should be stored here. (This points to storage local to Args, not to
the caller's variable.)</li>
<li>Args &<b>args</b>: A reference to the calling Args object, for error
reporting.</li>
</ol>
The parse() method should return true if the parse succeeds and false if it
fails. Type-specific error messages should be reported using methods like
<b>args</b>.error(). For generic errors, the parse() method can simply
return false; Args will generate a "KEYWORD: parse error" message.
Most parsers are <em>disciplined</em>, meaning that they modify
<b>result</b> only if the parse succeeds. This doesn't matter in the
context of Args, but can matter to users who call a parse function
directly.
*/
class Args : public ArgContext {
struct Slot;
public:
/** @brief Construct an argument parser.
* @param errh optional error handler */
Args(ErrorHandler *errh = 0);
/** @brief Construct an argument parser parsing a copy of @a conf.
* @param conf list of configuration arguments
* @param errh optional error handler */
Args(const Vector<String> &conf, ErrorHandler *errh = 0);
#if !CLICK_TOOL
/** @brief Construct an argument parser.
* @param context optional element context
* @param errh optional error handler */
Args(const Element *context, ErrorHandler *errh = 0);
/** @brief Construct an argument parser parsing a copy of @a conf.
* @param conf list of configuration arguments
* @param context optional element context
* @param errh optional error handler */
Args(const Vector<String> &conf, const Element *context,
ErrorHandler *errh = 0);
#endif
/** @brief Copy construct an argument parser.
* @note @a x's results are not copied. */
Args(const Args &x);
~Args();
/** @brief Assign to a copy of @a x.
* @pre results_empty() && @a x.results_empty() */
Args &operator=(const Args &x);
/** @brief Return true iff this parser has no arguments or results. */
bool empty() const {
return (!_conf || !_conf->size()) && !_slots && _simple_slotbuf[0] == 0;
}
/** @brief Return true iff this parser has no results. */
bool results_empty() const {
return !_slots && _simple_slotbuf[0] == 0;
}
/** @brief Remove all arguments.
* @return *this */
Args &clear() {
if (_conf)
_conf->clear();
_kwpos.clear();
return *this;
}
/** @brief Bind this parser's arguments to @a conf.
* @param conf reference to new arguments
* @return *this
* @post This Args shares @a conf with the caller.
* For instance, consume() will modify @a conf. */
Args &bind(Vector<String> &conf);
/** @brief Append argument @a arg to this parser.
* @return *this */
Args &push_back(const String &arg);
/** @brief Append arguments in the range [@a begin, @a end) to this parser.
* @return *this */
template<typename Iter> Args &push_back(Iter begin, Iter end) {
while (begin != end) {
push_back(*begin);
++begin;
}
return *this;
}
/** @brief Append the space-separated words in @a str to this parser.
* @return *this */
Args &push_back_words(const String &str);
/** @brief Append the comma-separated arguments in @a str to this parser.
* @return *this */
Args &push_back_args(const String &str);
/** @brief Reset the parse status for every argument.
* @return *this
*
* For example:
* @code
* Vector<String> conf; conf.push_back("1"); conf.push_back("2");
* int a, b;
* Args(conf).read_p("A", a).read_p("B", b).execute();
* assert(a == 1 && b == 2);
* Args(conf).read_p("A", a).reset().read_p("B", b).execute();
* assert(a == 1 && b == 1);
* @endcode
* Results are not affected. */
Args &reset() {
reset_from(0);
return *this;
}
static constexpr int mandatory = 1; ///< read flag for mandatory arguments
static constexpr int positional = 2; ///< read flag for positional arguments
static constexpr int deprecated = 4; ///< read flag for deprecated arguments
static constexpr int firstmatch = 8; ///< read flag to take first matching argument
/** @brief Read an argument using its type's default parser.
* @param keyword argument name
* @param x reference to result
* @return *this
*
* Creates a result slot for @a x and calls
* DefaultArg<T>().parse(string, result, *this). */
template <typename T>
Args &read(const char *keyword, T &x) {
return read(keyword, 0, x);
}
template <typename T>
Args &read_m(const char *keyword, T &x) {
return read(keyword, mandatory, x);
}
template <typename T>
Args &read_p(const char *keyword, T &x) {
return read(keyword, positional, x);
}
template <typename T>
Args &read_mp(const char *keyword, T &x) {
return read(keyword, mandatory | positional, x);
}
template <typename T>
Args &read(const char *keyword, int flags, T &x) {
args_base_read(this, keyword, flags, x);
return *this;
}
/** @brief Read an argument using the default parser, or set it to a
* default value if the argument is was not supplied.
* @param keyword argument name
* @param x reference to result
* @param default_value default value
* @return *this
*
* Creates a result slot for @a x. If @a keyword was supplied, calls
* DefaultArg<T>().parse(string, result, this). Otherwise, assigns the
* result to @a value. */
template <typename T, typename V>
Args &read_or_set(const char *keyword, T &x, const V &default_value) {
return read_or_set(keyword, 0, x, default_value);
}
template <typename T, typename V>
Args &read_or_set_p(const char *keyword, T &x, const V &default_value) {
return read_or_set(keyword, positional, x, default_value);
}
template <typename T, typename V>
Args &read_or_set(const char *keyword, int flags, T &x, const V &default_value) {
args_base_read_or_set(this, keyword, flags, x, default_value);
return *this;
}
/** @brief Read an argument using a specified parser.
* @param keyword argument name
* @param parser parser object
* @param x reference to result
* @return *this
*
* Creates a result slot for @a x and calls @a parser.parse(string,
* result, *this). */
template <typename P, typename T>
Args &read(const char *keyword, P parser, T &x) {
return read(keyword, 0, parser, x);
}
template <typename P, typename T>
Args &read_m(const char *keyword, P parser, T &x) {
return read(keyword, mandatory, parser, x);
}
template <typename P, typename T>
Args &read_p(const char *keyword, P parser, T &x) {
return read(keyword, positional, parser, x);
}
template <typename P, typename T>
Args &read_mp(const char *keyword, P parser, T &x) {
return read(keyword, mandatory | positional, parser, x);
}
template <typename P, typename T>
Args &read(const char *keyword, int flags, P parser, T &x) {
args_base_read(this, keyword, flags, parser, x);
return *this;
}
/** @brief Read an argument using a specified parser, or set it to a
* default value if the argument is was not supplied.
* @param keyword argument name
* @param parser parser object
* @param x reference to result variable
* @param default_value default value
* @return *this
*
* Creates a result slot for @a x. If argument @a keyword was supplied,
* calls @a parser.parse(string, result, *this). Otherwise, assigns the
* result to @a default_value. */
template <typename P, typename T, typename V>
Args &read_or_set(const char *keyword, P parser, T &x, const V &default_value) {
return read_or_set(keyword, 0, parser, x, default_value);
}
template <typename P, typename T, typename V>
Args &read_or_set_p(const char *keyword, P parser, T &x, const V &default_value) {
return read_or_set(keyword, positional, parser, x, default_value);
}
template <typename P, typename T, typename V>
Args &read_or_set(const char *keyword, int flags, P parser, T &x, const V &default_value) {
args_base_read_or_set(this, keyword, flags, parser, x, default_value);
return *this;
}
/** @brief Read an argument using a specified parser with two results.
* @param keyword argument name
* @param parser parser object
* @param x1 reference to first result
* @param x2 reference to second result
* @return *this
*
* Creates results for @a x1 and @a x2 and calls @a parser.parse(string,
* result1, result2, *this). */
template<typename P, typename T1, typename T2>
Args &read(const char *keyword, P parser, T1 &x1, T2 &x2) {
return read(keyword, 0, parser, x1, x2);
}
template<typename P, typename T1, typename T2>
Args &read_m(const char *keyword, P parser, T1 &x1, T2 &x2) {
return read(keyword, mandatory, parser, x1, x2);
}
template<typename P, typename T1, typename T2>
Args &read_p(const char *keyword, P parser, T1 &x1, T2 &x2) {
return read(keyword, positional, parser, x1, x2);
}
template<typename P, typename T1, typename T2>
Args &read_mp(const char *keyword, P parser, T1 &x1, T2 &x2) {
return read(keyword, mandatory | positional, parser, x1, x2);
}
template<typename P, typename T1, typename T2>
Args &read(const char *keyword, int flags, P parser, T1 &x1, T2 &x2) {
args_base_read(this, keyword, flags, parser, x1, x2);
return *this;
}
/** @brief Pass an argument to a specified parser.
* @param keyword argument name
* @param parser parser object
* @return *this
*
* Calls @a parser.parse(string, *this). */
template <typename P>
Args &read_with(const char *keyword, P parser) {
return read_with(keyword, 0, parser);
}
template <typename P>
Args &read_m_with(const char *keyword, P parser) {
return read_with(keyword, mandatory, parser);
}
template <typename P>
Args &read_p_with(const char *keyword, P parser) {
return read_with(keyword, positional, parser);
}
template <typename P>
Args &read_mp_with(const char *keyword, P parser) {
return read_with(keyword, mandatory | positional, parser);
}
template <typename P>
Args &read_with(const char *keyword, int flags, P parser) {
args_base_read_with(this, keyword, flags, parser);
return *this;
}
/** @brief Pass an argument to a specified parser.
* @param keyword argument name
* @param parser parser object
* @param x reference to result
* @return *this
*
* Creates a result slot for @a x and calls @a parser.parse(string,
* result, *this).
*
* @deprecated Use read(keyword, parser, variable) instead. */
template <typename P, typename T>
Args &read_with(const char *keyword, P parser, T &x) {
return read(keyword, parser, x);
}
template <typename P, typename T>
Args &read_m_with(const char *keyword, P parser, T &x) {
return read_m(keyword, parser, x);
}
template <typename P, typename T>
Args &read_p_with(const char *keyword, P parser, T &x) {
return read_p(keyword, parser, x);
}
template <typename P, typename T>
Args &read_mp_with(const char *keyword, P parser, T &x) {
return read_mp(keyword, parser, x);
}
template <typename P, typename T>
Args &read_with(const char *keyword, int flags, P parser, T &x) {
return read(keyword, flags, parser, x);
}
/** @brief Pass all matching arguments to a specified parser.
* @param keyword argument name
* @param parser parser object
* @return *this
*
* Calls @a parser.parse(string, *this) zero or more times.
*
* @note The value of read_status() is true iff at least one argument
* matched and all matching arguments successfully parsed. */
template <typename P>
Args &read_all_with(const char *keyword, P parser) {
return read_all_with(keyword, 0, parser);
}
template <typename P>
Args &read_all_with(const char *keyword, int flags, P parser) {
args_base_read_all_with(this, keyword, flags | firstmatch, parser);
return *this;
}
/** @brief Pass all matching arguments to a specified parser.
* @param keyword argument name
* @param parser parser object
* @param x reference to result
* @return *this
*
* Creates a result for @a x and calls @a parser.parse(string, result,
* *this) zero or more times, once per matching argument.
*
* @note The value of read_status() is true iff at least one argument
* matched and all matching arguments successfully parsed. */
template <typename P, typename T>
Args &read_all_with(const char *keyword, P parser, T &x) {
return read_all_with(keyword, 0, parser, x);
}
template <typename P, typename T>
Args &read_all_with(const char *keyword, int flags, P parser, T &x) {
args_base_read_all_with(this, keyword, flags | firstmatch, parser, x);
return *this;
}
/** @brief Pass all matching arguments to a specified parser.
* @param keyword argument name
* @param parser parser object
* @param x reference to vector of results
* @return *this
*
* For each @a keyword argument, calls @a parser.parse(string, value,
* *this). The resulting values are collected into a vector result slot
* for @a x.
*
* @note The value of read_status() is true iff at least one argument
* matched and all matching arguments successfully parsed. */
template <typename P, typename T>
Args &read_all(const char *keyword, P parser, Vector<T> &x) {
return read_all(keyword, 0, parser, x);
}
template <typename T>
Args &read_all(const char *keyword, Vector<T> &x) {
return read_all(keyword, 0, DefaultArg<T>(), x);
}
template <typename P, typename T>
Args &read_all(const char *keyword, int flags, P parser, Vector<T> &x) {
args_base_read_all(this, keyword, flags | firstmatch, parser, x);
return *this;
}
template <typename P, typename T>
Args &read_all(const char *keyword, int flags, Vector<T> &x) {
return read_all(keyword, flags, DefaultArg<T>(), x);
}
/** @brief Return the current parse status. */
bool status() const {
return _status;
}
/** @brief Set @a x to the current parse status.
* @return *this */
Args &status(bool &x) {
x = _status;
return *this;
}
/** @overload */
const Args &status(bool &x) const {
x = _status;
return *this;
}
/** @brief Return true iff the last read request succeeded.
*
* This function should only be called after a read. */
bool read_status() const {
return _read_status;
}
/** @brief Set @a x to the success status of the last read request.
*
* This function should only be called after a read. */
Args &read_status(bool &x) {
x = _read_status;
return *this;
}
/** @overload */
const Args &read_status(bool &x) const {
x = _read_status;
return *this;
}
/** @brief Remove all arguments matched so far. */
Args &strip();
/** @brief Assign results.
* @return 0 if the parse succeeded, <0 otherwise
* @post results_empty()
*
* Results are only assigned if status() is true (the parse is successful
* so far). Clears results as a side effect. */
int execute();
/** @brief Assign results and remove matched arguments.
* @return 0 if the parse succeeded, <0 otherwise
* @post results_empty()
*
* Matched arguments are always removed. Results are only assigned if
* status() is true (the parse is successful so far). Clears results as a
* side effect. */
int consume();
/** @brief Assign results if all arguments matched.
* @return 0 if the parse succeeded, <0 otherwise
* @post results_empty()
*
* Results are only assigned if status() is true (the parse is successful
* so far) and all arguments have been parsed. Clears results as a side
* effect. */
int complete();
/** @brief Create and return a result slot for @a x.
*
* If T is a trivially copyable type, such as int, then the resulting
* slot might not be initialized. */
template <typename T>
T *slot(T &x) {
if (has_trivial_copy<T>::value)
return reinterpret_cast<T *>(simple_slot(&x, sizeof(T)));
else
return complex_slot(x);
}
/** @brief Create and return a result slot for @a x.
*
* The resulting slot is always default-initialized. */
template <typename T>
T *initialized_slot(T &x) {
T *s = slot(x);
if (has_trivial_copy<T>::value)
*s = T();
return s;
}
/** @brief Add a result that assigns @a x to @a value.
* @return *this */
template <typename T, typename V>
Args &set(T &x, const V &value) {
if (T *s = slot(x))
*s = value;
return *this;
}
/** @cond never */
template<typename T>
void base_read(const char *keyword, int flags, T &variable) {
Slot *slot_status;
if (String str = find(keyword, flags, slot_status)) {
T *s = Args_parse_helper<DefaultArg<T> >::slot(variable, *this);
postparse(s && Args_parse_helper<DefaultArg<T> >::parse(DefaultArg<T>(), str, *s, *this), slot_status);
}
}
template<typename T, typename V>
void base_read_or_set(const char *keyword, int flags, T &variable, const V &value) {
Slot *slot_status;
String str = find(keyword, flags, slot_status);
T *s = Args_parse_helper<DefaultArg<T> >::slot(variable, *this);
postparse(s && (str ? Args_parse_helper<DefaultArg<T> >::parse(DefaultArg<T>(), str, *s, *this) : (*s = value, true)), slot_status);
}
template<typename P, typename T>
void base_read(const char *keyword, int flags, P parser, T &variable) {
Slot *slot_status;
if (String str = find(keyword, flags, slot_status)) {
T *s = Args_parse_helper<P>::slot(variable, *this);
postparse(s && Args_parse_helper<P>::parse(parser, str, *s, *this), slot_status);
}
}
template<typename T, typename P, typename V>
void base_read_or_set(const char *keyword, int flags, P parser, T &variable, const V &value) {
Slot *slot_status;
String str = find(keyword, flags, slot_status);
T *s = Args_parse_helper<P>::slot(variable, *this);
postparse(s && (str ? Args_parse_helper<P>::parse(parser, str, *s, *this) : (*s = value, true)), slot_status);
}
template<typename P, typename T1, typename T2>
void base_read(const char *keyword, int flags,
P parser, T1 &variable1, T2 &variable2) {
Slot *slot_status;
if (String str = find(keyword, flags, slot_status)) {
T1 *s1 = Args_parse_helper<P>::slot(variable1, *this);
T2 *s2 = Args_parse_helper<P>::slot(variable2, *this);
postparse(s1 && s2 && Args_parse_helper<P>::parse(parser, str, *s1, *s2, *this), slot_status);
}
}
template<typename P>
void base_read_with(const char *keyword, int flags, P parser) {
Slot *slot_status;
if (String str = find(keyword, flags, slot_status))
postparse(parser.parse(str, *this), slot_status);
}
template<typename P>
void base_read_all_with(const char *keyword, int flags, P parser) {
Slot *slot_status;
int read_status = -1;
while (String str = find(keyword, flags, slot_status)) {
postparse(parser.parse(str, *this), slot_status);
read_status = (read_status != 0) && _read_status;
flags &= ~mandatory;
}
_read_status = (read_status == 1);
}
template<typename P, typename T>
void base_read_all_with(const char *keyword, int flags, P parser, T &variable) {
Slot *slot_status;
int read_status = -1;
T *s = Args_parse_helper<P>::initialized_slot(variable, *this);
while (String str = find(keyword, flags, slot_status)) {
postparse(s && Args_parse_helper<P>::parse(parser, str, *s, *this), slot_status);
read_status = (read_status != 0) && _read_status;
flags &= ~mandatory;
}
_read_status = (read_status == 1);
}
template<typename P, typename T>
void base_read_all(const char *keyword, int flags, P parser, Vector<T> &variable) {
Slot *slot_status;
int read_status = -1;
Vector<T> *s = slot(variable);
while (String str = find(keyword, flags, slot_status)) {
T sx = T();
postparse(parser.parse(str, sx, *this), slot_status);
if (_read_status)
s->push_back(sx);
read_status = (read_status != 0) && _read_status;
flags &= ~mandatory;
}
_read_status = (read_status == 1);
}
/** @endcond never */
private:
struct Slot {
Slot() {
}
virtual ~Slot() {
}
virtual void store() = 0;
Slot *_next;
};
struct BytesSlot : public Slot {
BytesSlot(void *ptr, size_t size)
: _ptr(ptr), _slot(new char[size]), _size(size) {
}
~BytesSlot() {
delete[] _slot;
}
void store() {
memcpy(_ptr, _slot, _size);
}
void *_ptr;
char *_slot;
size_t _size;
};
template<typename T>
struct SlotT : public Slot {
SlotT(T *ptr)
: _ptr(ptr) {
}
void store() {
assign_consume(*_ptr, _slot);
}
T *_ptr;
T _slot;
};
enum {
#if SIZEOF_VOID_P == 4
simple_slotbuf_size = 24
#else
simple_slotbuf_size = 48
#endif
};
#if !CLICK_DEBUG_ARGS_USAGE
bool _my_conf;
#else
bool _my_conf : 1;
bool _consumed : 1;
#endif
bool _status;
uint8_t _simple_slotpos;
Vector<String> *_conf;
Vector<int> _kwpos;
Slot *_slots;
uint8_t _simple_slotbuf[simple_slotbuf_size];
inline void initialize(const Vector<String> *conf);
void reset_from(int i);
String find(const char *keyword, int flags, Slot *&slot_status);
void postparse(bool ok, Slot *slot_status);
void check_complete();
static inline int simple_slot_size(int size);
inline void simple_slot_info(int offset, int size,
void *&slot, void **&pointer);
void *simple_slot(void *data, size_t size);
template<typename T> T *complex_slot(T &variable);
};
extern const ArgContext blank_args;
template<typename T>
struct DefaultArg {
};
template<typename T>
T *Args::complex_slot(T &variable)
{
if (SlotT<T> *s = new SlotT<T>(&variable)) {
s->_next = _slots;
_slots = s;
return &s->_slot;
} else {
error("out of memory");
return 0;
}
}
/** @cond never */
/* These functions are here because some GCC versions ignore noinline
attributes on member function templates. */
template<typename T>
void args_base_read(Args *args, const char *keyword, int flags, T &variable)
CLICK_NOINLINE;
template<typename T>
void args_base_read(Args *args, const char *keyword, int flags, T &variable)
{
args->base_read(keyword, flags, variable);
}
template<typename T, typename V>
void args_base_read_or_set(Args *args, const char *keyword, int flags,
T &variable, const V &value) CLICK_NOINLINE;
template<typename T, typename V>
void args_base_read_or_set(Args *args, const char *keyword, int flags,
T &variable, const V &value)
{
args->base_read_or_set(keyword, flags, variable, value);
}
template<typename P, typename T>
void args_base_read(Args *args, const char *keyword, int flags,
P parser, T &variable) CLICK_NOINLINE;
template<typename P, typename T>
void args_base_read(Args *args, const char *keyword, int flags,
P parser, T &variable)
{
args->base_read(keyword, flags, parser, variable);
}
template<typename P, typename T, typename V>
void args_base_read_or_set(Args *args, const char *keyword, int flags,
P parser, T &variable, const V &value) CLICK_NOINLINE;
template<typename P, typename T, typename V>
void args_base_read_or_set(Args *args, const char *keyword, int flags,
P parser, T &variable, const V &value)
{
args->base_read_or_set(keyword, flags, parser, variable, value);
}
template<typename P, typename T1, typename T2>
void args_base_read(Args *args, const char *keyword, int flags,
P parser, T1 &variable1, T2 &variable2) CLICK_NOINLINE;
template<typename P, typename T1, typename T2>
void args_base_read(Args *args, const char *keyword, int flags,
P parser, T1 &variable1, T2 &variable2)
{
args->base_read(keyword, flags, parser, variable1, variable2);
}
template<typename P>
void args_base_read_with(Args *args, const char *keyword, int flags, P parser)
CLICK_NOINLINE;
template<typename P>
void args_base_read_with(Args *args, const char *keyword, int flags, P parser)
{
args->base_read_with(keyword, flags, parser);
}
template<typename P>
void args_base_read_all_with(Args *args, const char *keyword, int flags, P parser)
CLICK_NOINLINE;
template<typename P>
void args_base_read_all_with(Args *args, const char *keyword, int flags, P parser)
{
args->base_read_all_with(keyword, flags, parser);
}
template<typename P, typename T>
void args_base_read_all_with(Args *args, const char *keyword, int flags,
P parser, T &variable) CLICK_NOINLINE;
template<typename P, typename T>
void args_base_read_all_with(Args *args, const char *keyword, int flags,
P parser, T &variable)
{
args->base_read_all_with(keyword, flags, parser, variable);
}
template <typename P, typename T>
void args_base_read_all(Args *args, const char *keyword, int flags,
P parser, Vector<T> &variable) CLICK_NOINLINE;
template <typename P, typename T>
void args_base_read_all(Args *args, const char *keyword, int flags,
P parser, Vector<T> &variable)
{
args->base_read_all(keyword, flags, parser, variable);
}
/** @endcond never */
class NumArg { public:
enum {
status_ok = 0,
status_inval = EINVAL,
status_range = ERANGE,
#if defined(ENOTSUP)
status_notsup = ENOTSUP,
#elif defined(ENOTSUPP)
status_notsup = ENOTSUPP,
#else
status_notsup,
#endif
status_unitless
};
};
/** @class IntArg
@brief Parser class for integers.
IntArg(@a base) reads integers in base @a base. @a base defaults to 0,
which means arguments are parsed in base 10 by default, but prefixes 0x, 0,
and 0b parse hexadecimal, octal, and binary numbers, respectively.
Integer overflow is treated as an error.
@sa SaturatingIntArg, BoundedIntArg */
class IntArg : public NumArg { public:
typedef uint32_t limb_type;
IntArg(int b = 0)
: base(b) {
}
const char *parse(const char *begin, const char *end,
bool is_signed, int size,
limb_type *value, int nlimb);
template<typename V>
bool parse_saturating(const String &str, V &result, const ArgContext &args = blank_args) {
constexpr bool is_signed = integer_traits<V>::is_signed;
constexpr int nlimb = int((sizeof(V) + sizeof(limb_type) - 1) / sizeof(limb_type));
limb_type x[nlimb];
if (parse(str.begin(), str.end(), is_signed, int(sizeof(V)), x, nlimb)
!= str.end())
status = status_inval;
if (status && status != status_range) {
args.error("invalid number");
return false;
}
typedef typename make_unsigned<V>::type unsigned_v_type;
extract_integer(x, reinterpret_cast<unsigned_v_type &>(result));
return true;
}
template<typename V>
bool parse(const String &str, V &result, const ArgContext &args = blank_args) {
V x;
if (!parse_saturating(str, x, args)
|| (status && status != status_range))
return false;
else if (status == status_range) {
range_error(args, integer_traits<V>::is_signed,
click_int_large_t(x));
return false;
} else {
result = x;
return true;
}
}
int base;
int status;
protected:
static const char *span(const char *begin, const char *end,
bool is_signed, int &b);
void range_error(const ArgContext &args, bool is_signed,
click_int_large_t value);
};
/** @class SaturatingIntArg
@brief Parser class for integers with saturating overflow.
SaturatingIntArg(@a base) is like IntArg(@a base), but integer overflow is
not an error; instead, the closest representable value is returned.
@sa IntArg */
class SaturatingIntArg : public IntArg { public:
SaturatingIntArg(int b = 0)
: IntArg(b) {
}
template<typename V>
bool parse(const String &str, V &result, const ArgContext &args = blank_args) {
return parse_saturating(str, result, args);
}
};
/** @class BoundedIntArg
@brief Parser class for integers with explicit bounds.
BoundedIntArg(@a min, @a max, @a base) is like IntArg(@a base), but numbers
less than @a min or greater than @a max are treated as errors.
@sa IntArg */
class BoundedIntArg : public IntArg { public:
template <typename T>
BoundedIntArg(T min_value, T max_value, int b = 0)
: IntArg(b), min_value(min_value), max_value(max_value) {
static_assert(integer_traits<T>::is_integral, "BoundedIntArg argument must be integral");
is_signed = integer_traits<T>::is_signed;
}
template <typename V>
bool parse(const String &str, V &result, const ArgContext &args = blank_args) {
V x;
if (!IntArg::parse(str, x, args))
return false;
else if (!check_min(typename integer_traits<V>::max_type(x))) {
range_error(args, is_signed, min_value);
return false;
} else if (!check_max(typename integer_traits<V>::max_type(x))) {
range_error(args, is_signed, max_value);
return false;
} else {
result = x;
return true;
}
}
inline bool check_min(click_int_large_t x) const {
if (is_signed)
return x >= min_value;
else
return x >= 0 && click_uint_large_t(x) >= click_uint_large_t(min_value);
}
inline bool check_min(click_uint_large_t x) const {
if (is_signed)
return min_value < 0 || x >= click_uint_large_t(min_value);
else
return click_uint_large_t(x) >= click_uint_large_t(min_value);
}
inline bool check_max(click_int_large_t x) const {
if (is_signed)
return x <= max_value;
else
return x >= 0 && click_uint_large_t(x) <= click_uint_large_t(max_value);
}
inline bool check_max(click_uint_large_t x) const {
if (is_signed)
return max_value >= 0 && x <= click_uint_large_t(max_value);
else
return click_uint_large_t(x) <= click_uint_large_t(max_value);
}
click_intmax_t min_value;
click_intmax_t max_value;
bool is_signed;
};
template<> struct DefaultArg<unsigned char> : public IntArg {};
template<> struct DefaultArg<signed char> : public IntArg {};
template<> struct DefaultArg<char> : public IntArg {};
template<> struct DefaultArg<unsigned short> : public IntArg {};
template<> struct DefaultArg<short> : public IntArg {};
template<> struct DefaultArg<unsigned int> : public IntArg {};
template<> struct DefaultArg<int> : public IntArg {};
template<> struct DefaultArg<unsigned long> : public IntArg {};
template<> struct DefaultArg<long> : public IntArg {};
#if HAVE_LONG_LONG
template<> struct DefaultArg<unsigned long long> : public IntArg {};
template<> struct DefaultArg<long long> : public IntArg {};
#endif
/** @class FixedPointArg
@brief Parser class for fixed-point numbers with @a b bits of fraction. */
class FixedPointArg : public NumArg { public:
explicit FixedPointArg(int b, int exponent = 0)
: fraction_bits(b), exponent_delta(exponent) {
}
inline bool parse_saturating(const String &str, uint32_t &result, const ArgContext &args = blank_args);
bool parse(const String &str, uint32_t &result, const ArgContext &args = blank_args);
bool parse_saturating(const String &str, int32_t &result, const ArgContext &args = blank_args);
bool parse(const String &str, int32_t &result, const ArgContext &args = blank_args);
int fraction_bits;
int exponent_delta;
int status;
private:
bool underparse(const String &str, bool is_signed, uint32_t &result);
};
inline bool
FixedPointArg::parse_saturating(const String &str, uint32_t &result, const ArgContext &)
{
return underparse(str, false, result);
}
/** @class DecimalFixedPointArg
@brief Parser class for fixed-point numbers with @a d decimal digits of fraction. */
class DecimalFixedPointArg : public NumArg { public:
DecimalFixedPointArg(int d, int exponent = 0)
: fraction_digits(d), exponent_delta(exponent) {
}
inline bool parse_saturating(const String &str, uint32_t &result, const ArgContext &args = blank_args);
bool parse(const String &str, uint32_t &result, const ArgContext &args = blank_args);
bool parse_saturating(const String &str, int32_t &result, const ArgContext &args = blank_args);
bool parse(const String &str, int32_t &result, const ArgContext &args = blank_args);
bool parse_saturating(const String &str, uint32_t &iresult, uint32_t &fresult, const ArgContext &args = blank_args);
bool parse(const String &str, uint32_t &iresult, uint32_t &fresult, const ArgContext &args = blank_args);
int fraction_digits;
int exponent_delta;
int status;
private:
bool underparse(const String &str, bool is_signed, uint32_t &result);
};
inline bool
DecimalFixedPointArg::parse_saturating(const String &str, uint32_t &result, const ArgContext &)
{
return underparse(str, false, result);
}
#if HAVE_FLOAT_TYPES
/** @class DoubleArg
@brief Parser class for double-precision floating point numbers. */
class DoubleArg : public NumArg { public:
DoubleArg() {
}
bool parse(const String &str, double &result, const ArgContext &args = blank_args);
int status;
};
template<> struct DefaultArg<double> : public DoubleArg {};
#endif
/** @class BoolArg
@brief Parser class for booleans. */
class BoolArg { public:
static bool parse(const String &str, bool &result, const ArgContext &args = blank_args);
static String unparse(bool x) {
return String(x);
}
};
template<> struct DefaultArg<bool> : public BoolArg {};
class UnitArg { public:
explicit UnitArg(const char *unit_def, const char *prefix_chars_def)
: units_(reinterpret_cast<const unsigned char *>(unit_def)),
prefix_chars_(reinterpret_cast<const unsigned char *>(prefix_chars_def)) {
}
const char *parse(const char *begin, const char *end, int &power, int &factor) const;
private:
const unsigned char *units_;
const unsigned char *prefix_chars_;
void check_units();
};
/** @class BandwidthArg
@brief Parser class for bandwidth specifications.
Handles suffixes such as "Gbps", "k", etc. */
class BandwidthArg : public NumArg { public:
bool parse(const String &str, uint32_t &result, const ArgContext & = blank_args);
static String unparse(uint32_t x);
int status;
};
#if !CLICK_TOOL
/** @class AnnoArg
@brief Parser class for annotation specifications. */
class AnnoArg { public:
AnnoArg(int s)
: size(s) {
}
bool parse(const String &str, int &result, const ArgContext &args = blank_args);
private:
int size;
};
#endif
/** @class SecondsArg
@brief Parser class for seconds and powers thereof.
The @a d argument is the number of digits of fraction to parse.
For example, to parse milliseconds, use SecondsArg(3). */
class SecondsArg : public NumArg { public:
SecondsArg(int d = 0)
: fraction_digits(d) {
}
bool parse_saturating(const String &str, uint32_t &result, const ArgContext &args = blank_args);
bool parse(const String &str, uint32_t &result, const ArgContext &args = blank_args);
#if HAVE_FLOAT_TYPES
bool parse(const String &str, double &result, const ArgContext &args = blank_args);
#endif
int fraction_digits;
int status;
};
/** @class AnyArg
@brief Parser class that accepts any argument. */
class AnyArg { public:
static bool parse(const String &, const ArgContext & = blank_args) {
return true;
}
static bool parse(const String &str, String &result, const ArgContext & = blank_args) {
result = str;
return true;
}
static bool parse(const String &str, Vector<String> &result, const ArgContext & = blank_args) {
result.push_back(str);
return true;
}
};
bool cp_string(const String &str, String *result, String *rest);
/** @class StringArg
@brief Parser class for possibly-quoted strings. */
class StringArg { public:
static bool parse(const String &str, String &result, const ArgContext & = blank_args) {
return cp_string(str, &result, 0);
}
};
template<> struct DefaultArg<String> : public StringArg {};
bool cp_keyword(const String &str, String *result, String *rest);
/** @class KeywordArg
@brief Parser class for keywords. */
class KeywordArg { public:
static bool parse(const String &str, String &result, const ArgContext & = blank_args) {
return cp_keyword(str, &result, 0);
}
};
bool cp_word(const String &str, String *result, String *rest);
/** @class KeywordArg
@brief Parser class for words. */
class WordArg { public:
static bool parse(const String &str, String &result, const ArgContext & = blank_args) {
return cp_word(str, &result, 0);
}
};
#if CLICK_USERLEVEL || CLICK_TOOL
/** @class FilenameArg
@brief Parser class for filenames. */
class FilenameArg { public:
static bool parse(const String &str, String &result, const ArgContext &args = blank_args);
};
#endif
#if !CLICK_TOOL
/** @class ElementArg
@brief Parser class for elements. */
class ElementArg { public:
static bool parse(const String &str, Element *&result, const ArgContext &args);
};
template<> struct DefaultArg<Element *> : public ElementArg {};
/** @class ElementCastArg
@brief Parser class for elements of type @a t. */
class ElementCastArg { public:
ElementCastArg(const char *t)
: type(t) {
}
bool parse(const String &str, Element *&result, const ArgContext &args);
template<typename T> bool parse(const String &str, T *&result, const ArgContext &args) {
return parse(str, reinterpret_cast<Element *&>(result), args);
}
const char *type;
};
#endif
CLICK_ENDDECLS
#endif