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

578 lines
22 KiB
C++

// -*- c-basic-offset: 4; related-file-name: "../../lib/handlercall.cc" -*-
#ifndef CLICK_HANDLERCALL_HH
#define CLICK_HANDLERCALL_HH
#include <click/router.hh>
CLICK_DECLS
class VariableExpander;
/** @brief Convenience class for calling handlers.
*
* The HandlerCall class simplifies the process of calling Click handlers.
* (The lower-level interface is the Handler class.) HandlerCall is used in
* two ways: (1) to call handlers immediately via static member functions,
* and (2) to set up future handler calls via HandlerCall objects. The
* immediate handler call functions take handler names as arguments and
* perform all necessary error checks before calling handlers, if any. A
* HandlerCall object encapsulates a handler reference (possibly including
* parameters), again automating all necessary error checks.
*
* <h2>Immediate Handler Calls</h2>
*
* This example code shows how to use the HandlerCall functions for calling
* handlers immediately.
*
* @code
* class YourElement { ...
* Element *_other;
* }
*
* void YourElement::function() {
* // Call _other's "config" read handler.
* String result = HandlerCall::call_read(_other, "config");
*
* // The same, providing an error handler to print errors.
* ErrorHandler *errh = ErrorHandler::default_handler();
* result = HandlerCall::call_read(_other, "config", errh);
* // (Each function takes an optional last argument of "errh".)
*
* // Call the "foo.config" read handler. Search for element "foo" in
* // the current compound element context.
* result = HandlerCall::call_read("foo.config", this);
*
* // Call the global "config" read handler for the current router.
* result = HandlerCall::call_read("config", this);
*
* // Call _other's "stop" write handler with empty value.
* int success = HandlerCall::call_write(_other, "stop");
*
* // Call _other's "config" write handler with value "blah".
* success = HandlerCall::call_write(_other, "config", "blah");
*
* // Call the "foo.config" write handler with value "blah".
* success = HandlerCall::call_write("foo.config blah", this);
* // Or, alternately:
* success = HandlerCall::call_write("foo.config", "blah", this);
* }
* @endcode
*
* <h2>HandlerCall Objects</h2>
*
* This example code shows how to use the HandlerCall objects to call
* handlers with simplified error checking.
*
* @code
* class YourElement { ...
* HandlerCall _read_call;
* HandlerCall _write_call;
* }
*
* YourElement::YourElement()
* : _read_call(), _write_call() {
* }
*
* int YourElement::configure(Vector<String> &conf, ErrorHandler *errh) {
* return cp_va_kparse(conf, this, errh,
* "READ_CALL", cpkP, cpHandlerCallRead, &_read_call,
* "WRITE_CALL", cpkP, cpHandlerCallWrite, &_write_call,
* cpEnd);
* }
*
* int YourElement::initialize(ErrorHandler *errh) {
* if ((_read_call && _read_call.initialize_read(this, errh) < 0)
* || (_write_call && _write_call.initialize_write(this, errh) < 0))
* return -1;
* return 0;
* }
*
* void YourElement::function() {
* // call _read_call, print result
* if (_read_call)
* click_chatter("%s", _read_call.call_read());
*
* // call _write_call with error handler
* if (_write_call)
* _write_call.call_write(ErrorHandler::default_handler());
* }
* @endcode
*
* If usually your element's handler calls aren't used, you can save a small
* amount of space by using pointers to HandlerCall objects, as in this
* example. The cpHandlerCallPtrRead and cpHandlerCallPtrWrite types allow
* the _read_call and _write_call members to start out as null pointers.
*
* @code
* class YourElement { ...
* HandlerCall *_read_call;
* HandlerCall *_write_call;
* }
*
* YourElement::YourElement()
* : _read_call(0), _write_call(0) {
* }
*
* int YourElement::configure(Vector<String> &conf, ErrorHandler *errh) {
* return cp_va_kparse(conf, this, errh,
* "READ_CALL", cpkP, cpHandlerCallPtrRead, &_read_call,
* "WRITE_CALL", cpkP, cpHandlerCallPtrWrite, &_write_call,
* cpEnd);
* }
*
* int YourElement::initialize(ErrorHandler *errh) {
* if ((_read_call && _read_call->initialize_read(this, errh) < 0)
* || (_write_call && _write_call->initialize_write(this, errh) < 0))
* return -1;
* return 0;
* }
*
* void YourElement::cleanup(CleanupStage) {
* delete _read_call;
* delete _write_call;
* }
*
* void YourElement::function() {
* // call _read_call, print result
* if (_read_call)
* click_chatter("%s", _read_call->call_read());
*
* // call _write_call with error handler
* if (_write_call)
* _write_call->call_write(ErrorHandler::default_handler());
* }
* @endcode
*/
class HandlerCall { public:
/** @name Immediate Handler Calls */
//@{
static String call_read(Element *e, const String &hname,
ErrorHandler *errh = 0);
static String call_read(const String &hdesc, const Element *context,
ErrorHandler *errh = 0);
static int call_write(Element *e, const String &hname,
ErrorHandler *errh = 0);
static int call_write(Element *e, const String &hname, const String &value,
ErrorHandler *errh = 0);
static int call_write(const String &hdesc,
const Element *context, ErrorHandler *errh = 0);
static int call_write(const String &hdesc, const String &value,
const Element *context, ErrorHandler *errh = 0);
//@}
/** @brief Construct an empty HandlerCall.
*
* Any attempt to read, write, or initialize the HandlerCall will
* fail. */
HandlerCall()
: _e(0), _h(Handler::blank_handler()) {
}
/** @brief Construct a HandlerCall described by @a hdesc.
* @param hdesc handler description <tt>"[ename.]hname[ value]"</tt>
*
* Although the resulting HandlerCall isn't empty, it must be initialized
* before it can be used. It returns false for initialized(). The
* handler description is not checked for syntax errors, though;
* initialize() does that. */
HandlerCall(const String &hdesc)
: _e(reinterpret_cast<Element *>(4)), _h(Handler::blank_handler()),
_value(hdesc) {
}
enum Flags {
readable = Handler::f_read,
f_read = Handler::f_read,
writable = Handler::f_write,
f_write = Handler::f_write,
f_preinitialize = 4,
f_unquote_param = 8
};
/** @brief Initialize the HandlerCall.
* @param flags zero or more of f_read, f_write, f_preinitialize,
* f_unquote_param
* @param context optional element context
* @param errh optional error handler
* @return 0 on success, negative on failure
*
* Initializes the HandlerCall object. The handler description supplied
* to the constructor is parsed and checked for syntax errors. Any
* element reference is looked up relative to @a context, if any. (For
* example, if @a hdesc was "x.config" and @a context's name is
* "aaa/bbb/ccc", this will search for elements named aaa/bbb/x, aaa/x,
* and finally x. If @a context is null, then the description must refer
* to a global handler.) If f_read is set in @a flags, then there
* must be a read handler named appropriately; if f_write is set,
* then there must be a write handler. If f_unquote_param is set, then any
* parameters are unquoted.
*
* Initialization fails if the handler description was bogus (for
* example, an empty string, or something like "*#!$&!(#&$."), if the
* named handler does not exist, if a read handler description has
* parameters but the read handler doesn't actually take parameters, and
* so forth. If @a errh is nonnull, errors are reported there. The
* HandlerCall becomes empty on failure: empty() will return true, and
* (bool) *this will return false. Future call_read() and call_write()
* attempts will correctly fail.
*
* If the f_preinitialize flag is set, the initialize function will check
* whether the router's handlers are ready (Router::handlers_ready()).
* If handlers are not ready, then initialize() will check for syntax
* errors, but not actually look up the handler (since we don't know yet
* whether or not the handler exists). Absent a syntax error,
* initialize() will return 0 for success even though the HandlerCall
* remains uninitialized. */
int initialize(int flags, const Element *context, ErrorHandler *errh = 0);
/** @brief Initialize the HandlerCall for reading.
* @param context optional element context
* @param errh optional error handler
*
* Equivalent to @link initialize(int, const Element*, ErrorHandler*)
* initialize@endlink(f_read, @a context, @a errh). */
inline int initialize_read(const Element *context, ErrorHandler *errh = 0);
/** @brief Initialize the HandlerCall for writing.
* @param context optional element context
* @param errh optional error handler
*
* Equivalent to @link initialize(int, const Element*, ErrorHandler*)
* initialize@endlink(f_write, @a context, @a errh). */
inline int initialize_write(const Element *context, ErrorHandler *errh = 0);
typedef bool (HandlerCall::*unspecified_bool_type)() const;
/** @brief Test if HandlerCall is empty.
* @return True if HandlerCall is not empty, false otherwise.
*
* Valid HandlerCall objects have been successfully initialized. */
operator unspecified_bool_type() const {
return _h != Handler::blank_handler() || _e ? &HandlerCall::empty : 0;
}
/** @brief Test if HandlerCall is empty.
* @return True if HandlerCall is empty, false otherwise. */
bool empty() const {
return _h == Handler::blank_handler() && !_e;
}
/** @brief Test if HandlerCall is initialized.
* @return True if HandlerCall is initialized, false otherwise. */
bool initialized() const {
return _h != Handler::blank_handler();
}
/** @brief Call a read handler.
* @param errh optional error handler
* @return Read handler result.
*
* Fails and returns the empty string if this HandlerCall is invalid or
* not a read handler. If @a errh is nonnull, then any errors are
* reported there, whether from HandlerCall or the handler itself. */
inline String call_read(ErrorHandler *errh = 0) const;
/** @brief Call a write handler.
* @param errh optional error handler
* @return Write handler result.
*
* Fails and returns -EINVAL if this HandlerCall is invalid or not a
* write handler. If @a errh is nonnull, then any errors are reported
* there, whether from HandlerCall or the handler itself. */
inline int call_write(ErrorHandler *errh = 0) const;
/** @brief Call a write handler, expanding its argument.
* @param scope variable scope
* @param errh optional error handler
* @return Write handler result.
*
* The write value is expanded in @a scope before the handler is called.
* Fails and returns -EINVAL if this HandlerCall is invalid or not a
* write handler. If @a errh is nonnull, then any errors are reported
* there, whether from HandlerCall or the handler itself. */
inline int call_write(const VariableExpander &scope, ErrorHandler *errh = 0) const;
/** @brief Call a write handler with an additional value.
* @param value_ext write value extension
* @param errh optional error handler
* @return Write handler result.
*
* The @a value_ext is appended to the write value before the handler is
* called. (For example, consider a handler with description "a.set
* value". call_write("foo") will call "a.set value foo".) Fails and
* returns -EINVAL if this HandlerCall is invalid or not a write handler.
* If @a errh is nonnull, then any errors are reported there, whether
* from HandlerCall or the handler itself. */
inline int call_write(const String &value_ext, ErrorHandler *errh = 0) const;
/** @brief Create and initialize a HandlerCall from @a hdesc.
* @param hcall stores the HandlerCall result
* @param hdesc handler description "[ename.]hname[ value]"
* @param flags initialization flags (f_read, f_write, f_preinitialize)
* @param context optional element context
* @param errh optional error handler
* @return 0 on success, -EINVAL on failure
*
* Creates a HandlerCall and initializes it. Behaves somewhat like:
*
* @code
* hcall = new HandlerCall(hdesc);
* return hcall->initialize(flags, context, errh);
* @endcode
*
* However, (1) if initialization fails, then @a hcall is untouched; and
* (2) if initialization succeeds and @a hcall is not null, then the
* existing HandlerCall is assigned so that it corresponds to the new one
* (no new memory allocations).
*
* If @a errh is nonnull, then any errors are reported there. */
static int reset(HandlerCall *&hcall, const String &hdesc, int flags,
const Element *context, ErrorHandler *errh = 0);
/** @brief Create and initialize a HandlerCall on element @a e.
* @param hcall stores the HandlerCall result
* @param e relevant element, if any
* @param hname handler name
* @param value handler value
* @param flags initialization flags (f_read, f_write, f_preinitialize)
* @param errh optional error handler
* @return 0 on success, -EINVAL on failure
*
* Creates a HandlerCall and initializes it. Behaves analogously to
* reset(HandlerCall*&, const String&, int, const Element*, ErrorHandler*). */
static int reset(HandlerCall *&hcall,
Element *e, const String &hname, const String &value,
int flags, ErrorHandler *errh = 0);
/** @brief Create and initialize a read HandlerCall from @a hdesc.
* @param hcall stores the HandlerCall result
* @param hdesc handler description "[ename.]hdesc[ param]"
* @param context optional element context
* @param errh optional error handler
* @return 0 on success, -EINVAL on failure
*
* Equivalent to
* @link reset(HandlerCall*&, const String&, int, const Element*, ErrorHandler*) reset@endlink(@a hcall, @a hdesc, f_read, @a context, @a errh). */
static inline int reset_read(HandlerCall *&hcall, const String &hdesc,
const Element *context, ErrorHandler *errh = 0);
/** @brief Create and initialize a read HandlerCall from @a hdesc.
* @param hcall stores the HandlerCall result
* @param e relevant element, if any
* @param hname handler name
* @param errh optional error handler
* @return 0 on success, -EINVAL on failure
*
* Equivalent to
* @link reset(HandlerCall*&, Element*, const String&, const String&, int, ErrorHandler*) reset@endlink(@a hcall, @a e, @a hname, String(), f_read, @a context, @a errh). */
static inline int reset_read(HandlerCall *&hcall,
Element *e, const String &hname,
ErrorHandler *errh = 0);
/** @brief Create and initialize a write HandlerCall from @a hdesc.
* @param hcall stores the HandlerCall result
* @param hdesc handler description "[ename.]hdesc[ value]"
* @param context optional element context
* @param errh optional error handler
* @return 0 on success, -EINVAL on failure
*
* Equivalent to
* @link reset(HandlerCall*&, const String&, int, const Element*, ErrorHandler*) reset@endlink(@a hcall, @a hdesc, f_write, @a context, @a errh). */
static inline int reset_write(HandlerCall *&hcall, const String &hdesc,
const Element *context, ErrorHandler *errh = 0);
/** @brief Create and initialize a read HandlerCall from @a hdesc.
* @param hcall stores the HandlerCall result
* @param e relevant element, if any
* @param hname handler name
* @param value write handler value
* @param errh optional error handler
* @return 0 on success, -EINVAL on failure
*
* Equivalent to
* @link reset(HandlerCall*&, Element*, const String&, const String&, int, ErrorHandler*) reset@endlink(@a hcall, @a e, @a hname, @ value, f_write, @a context, @a errh). */
static inline int reset_write(HandlerCall *&hcall,
Element *e, const String &hname,
const String &value = String(),
ErrorHandler *errh = 0);
/** @brief Return the Element corresponding to this HandlerCall.
*
* Returns null if invalid. A global handler may return some
* Router::root_element() or null. */
Element *element() const {
return _e;
}
/** @brief Return the Handler corresponding to this HandlerCall.
*
* Returns Handler::blank_handler() if invalid. */
const Handler *handler() const {
return _h;
}
/** @brief Return the write handler value and/or read handler parameters.
*
* Returns the empty string if invalid. */
const String &value() const {
return initialized() ? _value : String::make_empty();
}
/** @brief Sets the write handler value and/or read handler parameters.
* @param value new value and/or parameters
*
* Does nothing if invalid. */
void set_value(const String &value) {
if (initialized())
_value = value;
}
/** @brief Return a String that will parse into an equivalent HandlerCall.
*
* Will work even if the HandlerCall has not been initialized. */
String unparse() const;
/** @brief Make this HandlerCall empty.
*
* Subsequent attempts to read, write, or initialize the HandlerCall will
* fail. */
void clear() {
_e = 0;
_h = Handler::blank_handler();
_value = String();
}
/** @cond never */
enum {
CHECK_READ = f_read, OP_READ = f_read, h_read = f_read,
CHECK_WRITE = f_write, OP_WRITE = f_write, h_write = f_write,
PREINITIALIZE = f_preinitialize, h_preinitialize = f_preinitialize,
UNQUOTE_PARAM = f_unquote_param, h_unquote_param = f_unquote_param
};
/** @endcond never */
private:
Element *_e;
const Handler *_h;
String _value;
int parse(int flags, Element*, ErrorHandler*);
int assign(Element*, const String&, const String&, int flags, ErrorHandler*);
};
inline int
HandlerCall::reset_read(HandlerCall*& hcall, const String& hdesc, const Element* context, ErrorHandler* errh)
{
return reset(hcall, hdesc, f_read, context, errh);
}
inline int
HandlerCall::reset_write(HandlerCall*& hcall, const String& hdesc, const Element* context, ErrorHandler* errh)
{
return reset(hcall, hdesc, f_write, context, errh);
}
inline int
HandlerCall::reset_read(HandlerCall*& hcall, Element* e, const String& hname, ErrorHandler* errh)
{
return reset(hcall, e, hname, String(), f_read, errh);
}
inline int
HandlerCall::reset_write(HandlerCall*& hcall, Element* e, const String& hname, const String& value, ErrorHandler* errh)
{
return reset(hcall, e, hname, value, f_write, errh);
}
inline int
HandlerCall::initialize_read(const Element* context, ErrorHandler* errh)
{
return initialize(f_read, context, errh);
}
inline int
HandlerCall::initialize_write(const Element* context, ErrorHandler* errh)
{
return initialize(f_write, context, errh);
}
inline String
HandlerCall::call_read(ErrorHandler *errh) const
{
return _h->call_read(_e, _value, errh);
}
inline int
HandlerCall::call_write(ErrorHandler *errh) const
{
return _h->call_write(_value, _e, errh);
}
String cp_expand(const String &str, const VariableExpander &env, bool expand_quote, int depth);
inline int
HandlerCall::call_write(const VariableExpander &scope, ErrorHandler *errh) const
{
return _h->call_write(cp_expand(_value, scope, false, 0), _e, errh);
}
inline int
HandlerCall::call_write(const String &value_ext, ErrorHandler *errh) const
{
if (_value && value_ext)
return _h->call_write(_value + " " + value_ext, _e, errh);
else
return _h->call_write(_value ? _value : value_ext, _e, errh);
}
/** @brief Call a write handler specified by element and handler name.
* @param e relevant element, if any
* @param hname handler name
* @param errh optional error handler
* @return handler result, or -EINVAL on error
*
* Searches for a write handler named @a hname on element @a e. If the
* handler exists, calls it (with empty write value) and returns the result.
* If @a errh is nonnull, then errors, such as a missing handler or a
* read-only handler, are reported there. If @a e is some router's @link
* Router::root_element() root element@endlink, calls the global write
* handler named @a hname on that router. */
inline int
HandlerCall::call_write(Element *e, const String &hname, ErrorHandler *errh)
{
return call_write(e, hname, String(), errh);
}
/** @class HandlerCallArg
@brief Parser class for handler call specifications.
The constructor argument should generally be either HandlerCall::writable or
HandlerCall::readable. For example:
@code
HandlerCall end_h;
... Args(...) ...
.read("END_CALL", HandlerCallArg(HandlerCall::writable), end_h)
...
@endcode */
struct HandlerCallArg {
HandlerCallArg(int f)
: flags(f) {
}
bool parse(const String &str, HandlerCall &result, const ArgContext &args);
int flags;
};
CLICK_ENDDECLS
#endif