// -*- c-basic-offset: 4; related-file-name: "../../lib/args.cc" -*- #ifndef CLICK_ARGS_HH #define CLICK_ARGS_HH #include #include #include #include #include #if CLICK_BSDMODULE # include #else # include #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 struct Args_has_enable_direct_parse { private: template static char test(typename X::enable_direct_parse *); template static int test(...); public: enum { value = (sizeof(test(0)) == 1) }; }; template ::value> struct Args_parse_helper; template struct Args_parse_helper { template static inline T *slot(T &variable, A &args) { return args.slot(variable); } template static inline T *initialized_slot(T &variable, A &args) { return args.initialized_slot(variable); } template static inline bool parse(P parser, const String &str, T &s, A &args) { return parser.parse(str, s, args); } template static inline bool parse(P parser, const String &str, T1 &s1, T2 &s2, A &args) { return parser.parse(str, s1, s2, args); } }; template struct Args_parse_helper { template static inline T *slot(T &variable, A &) { return &variable; } template static inline T *initialized_slot(T &variable, A &) { return &variable; } template static inline bool parse(P parser, const String &str, T &s, A &args) { return parser.direct_parse(str, s, args); } template 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 arguments and result slots. 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 executes 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 any 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 flags 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 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 parser objects. Many common variable types have default parsers defined by the DefaultArg 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 = 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:
  1. const String &str: The string to be parsed.
  2. T &result: 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.)
  3. Args &args: A reference to the calling Args object, for error reporting.
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 args.error(). For generic errors, the parse() method can simply return false; Args will generate a "KEYWORD: parse error" message. Most parsers are disciplined, meaning that they modify result 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 &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 &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 &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 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 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().parse(string, result, *this). */ template Args &read(const char *keyword, T &x) { return read(keyword, 0, x); } template Args &read_m(const char *keyword, T &x) { return read(keyword, mandatory, x); } template Args &read_p(const char *keyword, T &x) { return read(keyword, positional, x); } template Args &read_mp(const char *keyword, T &x) { return read(keyword, mandatory | positional, x); } template 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().parse(string, result, this). Otherwise, assigns the * result to @a value. */ template Args &read_or_set(const char *keyword, T &x, const V &default_value) { return read_or_set(keyword, 0, x, default_value); } template Args &read_or_set_p(const char *keyword, T &x, const V &default_value) { return read_or_set(keyword, positional, x, default_value); } template 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 Args &read(const char *keyword, P parser, T &x) { return read(keyword, 0, parser, x); } template Args &read_m(const char *keyword, P parser, T &x) { return read(keyword, mandatory, parser, x); } template Args &read_p(const char *keyword, P parser, T &x) { return read(keyword, positional, parser, x); } template Args &read_mp(const char *keyword, P parser, T &x) { return read(keyword, mandatory | positional, parser, x); } template 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 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 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 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 Args &read(const char *keyword, P parser, T1 &x1, T2 &x2) { return read(keyword, 0, parser, x1, x2); } template Args &read_m(const char *keyword, P parser, T1 &x1, T2 &x2) { return read(keyword, mandatory, parser, x1, x2); } template Args &read_p(const char *keyword, P parser, T1 &x1, T2 &x2) { return read(keyword, positional, parser, x1, x2); } template Args &read_mp(const char *keyword, P parser, T1 &x1, T2 &x2) { return read(keyword, mandatory | positional, parser, x1, x2); } template 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 Args &read_with(const char *keyword, P parser) { return read_with(keyword, 0, parser); } template Args &read_m_with(const char *keyword, P parser) { return read_with(keyword, mandatory, parser); } template Args &read_p_with(const char *keyword, P parser) { return read_with(keyword, positional, parser); } template Args &read_mp_with(const char *keyword, P parser) { return read_with(keyword, mandatory | positional, parser); } template 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 Args &read_with(const char *keyword, P parser, T &x) { return read(keyword, parser, x); } template Args &read_m_with(const char *keyword, P parser, T &x) { return read_m(keyword, parser, x); } template Args &read_p_with(const char *keyword, P parser, T &x) { return read_p(keyword, parser, x); } template Args &read_mp_with(const char *keyword, P parser, T &x) { return read_mp(keyword, parser, x); } template 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 Args &read_all_with(const char *keyword, P parser) { return read_all_with(keyword, 0, parser); } template 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 Args &read_all_with(const char *keyword, P parser, T &x) { return read_all_with(keyword, 0, parser, x); } template 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 Args &read_all(const char *keyword, P parser, Vector &x) { return read_all(keyword, 0, parser, x); } template Args &read_all(const char *keyword, Vector &x) { return read_all(keyword, 0, DefaultArg(), x); } template Args &read_all(const char *keyword, int flags, P parser, Vector &x) { args_base_read_all(this, keyword, flags | firstmatch, parser, x); return *this; } template Args &read_all(const char *keyword, int flags, Vector &x) { return read_all(keyword, flags, DefaultArg(), 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 T *slot(T &x) { if (has_trivial_copy::value) return reinterpret_cast(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 T *initialized_slot(T &x) { T *s = slot(x); if (has_trivial_copy::value) *s = T(); return s; } /** @brief Add a result that assigns @a x to @a value. * @return *this */ template Args &set(T &x, const V &value) { if (T *s = slot(x)) *s = value; return *this; } /** @cond never */ template 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 >::slot(variable, *this); postparse(s && Args_parse_helper >::parse(DefaultArg(), str, *s, *this), slot_status); } } template 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 >::slot(variable, *this); postparse(s && (str ? Args_parse_helper >::parse(DefaultArg(), str, *s, *this) : (*s = value, true)), slot_status); } template 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

::slot(variable, *this); postparse(s && Args_parse_helper

::parse(parser, str, *s, *this), slot_status); } } template 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

::slot(variable, *this); postparse(s && (str ? Args_parse_helper

::parse(parser, str, *s, *this) : (*s = value, true)), slot_status); } template 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

::slot(variable1, *this); T2 *s2 = Args_parse_helper

::slot(variable2, *this); postparse(s1 && s2 && Args_parse_helper

::parse(parser, str, *s1, *s2, *this), slot_status); } } template 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 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 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

::initialized_slot(variable, *this); while (String str = find(keyword, flags, slot_status)) { postparse(s && Args_parse_helper

::parse(parser, str, *s, *this), slot_status); read_status = (read_status != 0) && _read_status; flags &= ~mandatory; } _read_status = (read_status == 1); } template void base_read_all(const char *keyword, int flags, P parser, Vector &variable) { Slot *slot_status; int read_status = -1; Vector *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 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 *_conf; Vector _kwpos; Slot *_slots; uint8_t _simple_slotbuf[simple_slotbuf_size]; inline void initialize(const Vector *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 T *complex_slot(T &variable); }; extern const ArgContext blank_args; template struct DefaultArg { }; template T *Args::complex_slot(T &variable) { if (SlotT *s = new SlotT(&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 void args_base_read(Args *args, const char *keyword, int flags, T &variable) CLICK_NOINLINE; template void args_base_read(Args *args, const char *keyword, int flags, T &variable) { args->base_read(keyword, flags, variable); } template void args_base_read_or_set(Args *args, const char *keyword, int flags, T &variable, const V &value) CLICK_NOINLINE; template 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 void args_base_read(Args *args, const char *keyword, int flags, P parser, T &variable) CLICK_NOINLINE; template void args_base_read(Args *args, const char *keyword, int flags, P parser, T &variable) { args->base_read(keyword, flags, parser, variable); } template void args_base_read_or_set(Args *args, const char *keyword, int flags, P parser, T &variable, const V &value) CLICK_NOINLINE; template 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 void args_base_read(Args *args, const char *keyword, int flags, P parser, T1 &variable1, T2 &variable2) CLICK_NOINLINE; template 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 void args_base_read_with(Args *args, const char *keyword, int flags, P parser) CLICK_NOINLINE; template void args_base_read_with(Args *args, const char *keyword, int flags, P parser) { args->base_read_with(keyword, flags, parser); } template void args_base_read_all_with(Args *args, const char *keyword, int flags, P parser) CLICK_NOINLINE; template void args_base_read_all_with(Args *args, const char *keyword, int flags, P parser) { args->base_read_all_with(keyword, flags, parser); } template void args_base_read_all_with(Args *args, const char *keyword, int flags, P parser, T &variable) CLICK_NOINLINE; template 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 void args_base_read_all(Args *args, const char *keyword, int flags, P parser, Vector &variable) CLICK_NOINLINE; template void args_base_read_all(Args *args, const char *keyword, int flags, P parser, Vector &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 bool parse_saturating(const String &str, V &result, const ArgContext &args = blank_args) { constexpr bool is_signed = integer_traits::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::type unsigned_v_type; extract_integer(x, reinterpret_cast(result)); return true; } template 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::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 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 BoundedIntArg(T min_value, T max_value, int b = 0) : IntArg(b), min_value(min_value), max_value(max_value) { static_assert(integer_traits::is_integral, "BoundedIntArg argument must be integral"); is_signed = integer_traits::is_signed; } template 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::max_type(x))) { range_error(args, is_signed, min_value); return false; } else if (!check_max(typename integer_traits::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 : public IntArg {}; template<> struct DefaultArg : public IntArg {}; template<> struct DefaultArg : public IntArg {}; template<> struct DefaultArg : public IntArg {}; template<> struct DefaultArg : public IntArg {}; template<> struct DefaultArg : public IntArg {}; template<> struct DefaultArg : public IntArg {}; template<> struct DefaultArg : public IntArg {}; template<> struct DefaultArg : public IntArg {}; #if HAVE_LONG_LONG template<> struct DefaultArg : public IntArg {}; template<> struct DefaultArg : 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 : 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 : public BoolArg {}; class UnitArg { public: explicit UnitArg(const char *unit_def, const char *prefix_chars_def) : units_(reinterpret_cast(unit_def)), prefix_chars_(reinterpret_cast(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 &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 : 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 : 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 bool parse(const String &str, T *&result, const ArgContext &args) { return parse(str, reinterpret_cast(result), args); } const char *type; }; #endif CLICK_ENDDECLS #endif