You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by am...@apache.org on 2010/11/20 16:17:56 UTC

svn commit: r1037235 [2/2] - /trafficserver/traffic/branches/wccp/proxy/tsconfig/

Added: trafficserver/traffic/branches/wccp/proxy/tsconfig/TsConfigLexer.h
URL: http://svn.apache.org/viewvc/trafficserver/traffic/branches/wccp/proxy/tsconfig/TsConfigLexer.h?rev=1037235&view=auto
==============================================================================
--- trafficserver/traffic/branches/wccp/proxy/tsconfig/TsConfigLexer.h (added)
+++ trafficserver/traffic/branches/wccp/proxy/tsconfig/TsConfigLexer.h Sat Nov 20 15:17:55 2010
@@ -0,0 +1,16 @@
+# if ! defined(TS_CONFIG_LEXER_HEADER)
+# define TS_CONFIG_LEXER_HEADER
+
+// Need this for TsConfigHandlers
+# include "TsConfigParseEvents.h"
+
+# if defined(__cplusplus)
+    extern "C" {
+# endif
+#   include "TsConfig.lex.h"
+    extern int tsconfigparse(yyscan_t lexer, struct TsConfigHandlers* handlers);
+# if defined(__cplusplus)
+}
+# endif
+
+# endif // TS_CONFIG_LEXER_HEADER

Added: trafficserver/traffic/branches/wccp/proxy/tsconfig/TsConfigParseEvents.h
URL: http://svn.apache.org/viewvc/trafficserver/traffic/branches/wccp/proxy/tsconfig/TsConfigParseEvents.h?rev=1037235&view=auto
==============================================================================
--- trafficserver/traffic/branches/wccp/proxy/tsconfig/TsConfigParseEvents.h (added)
+++ trafficserver/traffic/branches/wccp/proxy/tsconfig/TsConfigParseEvents.h Sat Nov 20 15:17:55 2010
@@ -0,0 +1,46 @@
+# if ! defined(TS_CONFIG_PARSE_EVENTS_HEADER)
+# define TS_CONFIG_PARSE_EVENTS_HEADER
+
+// Parsing events.
+
+# include "TsConfigTypes.h"
+
+typedef void (*TsConfigEventFunction)(void* data, YYSTYPE* token);
+struct TsConfigEventHandler {
+    TsConfigEventFunction _f; ///< Callback function.
+    void* _data; ///< Callback context data.
+};
+typedef int (*TsConfigErrorFunction)(void* data, char const* text);
+struct TsConfigErrorHandler {
+    TsConfigErrorFunction _f; ///< Callback function.
+    void* _data; ///< Callback context data.
+};
+
+enum TsConfigEventType {
+    TsConfigEventGroupOpen,
+    TsConfigEventGroupName,
+    TsConfigEventGroupClose,
+    TsConfigEventListOpen,
+    TsConfigEventListClose,
+    TsConfigEventPathOpen,
+    TsConfigEventPathTag,
+    TsConfigEventPathIndex,
+    TsConfigEventPathClose,
+    TsConfigEventLiteralValue,
+    TsConfigEventInvalidToken
+};
+
+# if defined(__cplusplus)
+static const size_t TS_CONFIG_N_EVENT_TYPES = TsConfigEventInvalidToken + 1;
+# else
+# define TS_CONFIG_N_EVENT_TYPES (TsConfigEventInvalidToken + 1)
+# endif
+
+struct TsConfigHandlers {
+    struct TsConfigErrorHandler error; ///< Syntax error.
+    /// Parsing event handlers.
+    /// Indexed by @c TsConfigEventType.
+    struct TsConfigEventHandler handler[TS_CONFIG_N_EVENT_TYPES];
+};
+
+# endif // TS_CONFIG_PARSE_EVENTS_HEADER

Added: trafficserver/traffic/branches/wccp/proxy/tsconfig/TsConfigTypes.h
URL: http://svn.apache.org/viewvc/trafficserver/traffic/branches/wccp/proxy/tsconfig/TsConfigTypes.h?rev=1037235&view=auto
==============================================================================
--- trafficserver/traffic/branches/wccp/proxy/tsconfig/TsConfigTypes.h (added)
+++ trafficserver/traffic/branches/wccp/proxy/tsconfig/TsConfigTypes.h Sat Nov 20 15:17:55 2010
@@ -0,0 +1,33 @@
+# if ! defined(TS_CONFIG_TYPES_HEADER)
+# define TS_CONFIG_TYPES_HEADER
+
+# if defined(_MSC_VER)
+#   include <stddef.h>
+# else
+#   include <unistd.h>
+# endif
+
+# if defined(__cplusplus)
+namespace ts { namespace config {
+# endif
+struct Location {
+    int _col; ///< Column.
+    int _line; ///< Line.
+};
+
+struct Token {
+  char* _s; ///< Text of token.
+  size_t _n; ///< Text length.
+  int _type; ///< Type of token.
+  struct Location _loc; ///< Location of token.
+};
+
+# if defined(__cplusplus)
+}} // namespace ts::config
+# define YYSTYPE ts::config::Token
+# else
+# define YYSTYPE struct Token
+#endif
+
+
+# endif // TS_CONFIG_TYPES_HEADER
\ No newline at end of file

Added: trafficserver/traffic/branches/wccp/proxy/tsconfig/TsErrataUtil.cc
URL: http://svn.apache.org/viewvc/trafficserver/traffic/branches/wccp/proxy/tsconfig/TsErrataUtil.cc?rev=1037235&view=auto
==============================================================================
--- trafficserver/traffic/branches/wccp/proxy/tsconfig/TsErrataUtil.cc (added)
+++ trafficserver/traffic/branches/wccp/proxy/tsconfig/TsErrataUtil.cc Sat Nov 20 15:17:55 2010
@@ -0,0 +1,151 @@
+/// @file
+/// Statics and utilities.
+
+# if !defined(_MSC_VER)
+# include <stdio.h>
+# include <string.h>
+# endif
+# include <stdarg.h>
+# include <errno.h>
+# include <TsErrataUtil.h>
+
+namespace ts { namespace msg {
+
+Errata::Code FATAL = 3; ///< Fatal, cannot continue.
+Errata::Code WARN = 2; ///< Significant, should be fixed.
+Errata::Code INFO = 1; /// Interesting, not necessarily a problem.
+Errata::Code DEBUG = 0; /// Debugging information.
+
+# if defined(_MSC_VER)
+char* strerror_r(int err, char* s, size_t n) {
+    strncpy(s, strerror(err), n-1);
+    s[n-1] = 0; // guarantee null termination.
+    return s;
+}
+
+# define snprintf _snprintf
+# endif
+
+Errata&
+log(Errata& err, Errata::Id id, Errata::Code code, char const* text) {
+  err.push(id, code, text);
+  return err;
+}
+
+Errata&
+log(Errata& err, Errata::Code code, char const* text) {
+  err.push(0, code, text);
+  return err;
+}
+
+Errata&
+log(RvBase& rv, Errata::Code code, char const* text) {
+    rv._errata.push(0, code, text);
+    return rv._errata;
+}
+
+Errata
+log(Errata::Code code, char const* text) {
+  Errata err;
+  err.push(0, code, text);
+  return err;
+}
+
+Errata&
+vlogf(
+  Errata& err,
+  Errata::Id id,
+  Errata::Code code,
+  char const* format,
+  va_list& rest
+) {
+  int n;
+  static size_t const SIZE = 8192;
+  char buffer[SIZE];
+  
+  n = vsnprintf(buffer, SIZE, format, rest);
+  err.push(id, code, buffer);
+  return err;
+}
+
+Errata&
+logf(
+  Errata& err,
+  Errata::Id id,
+  Errata::Code code,
+  char const* format,
+  ...
+) {
+  va_list rest;
+  va_start(rest, format);
+  return vlogf(err, id, code, format, rest);
+}
+
+Errata
+logf(Errata::Code code, char const* format, ...) {
+  Errata err;
+  va_list rest;
+  va_start(rest, format);
+  return vlogf(err, Errata::Id(0), code, format, rest);
+}
+
+Errata&
+logf(Errata& err, Errata::Code code, char const* format, ...) {
+  va_list rest;
+  va_start(rest, format);
+  return vlogf(err, Errata::Id(0), code, format, rest);
+}
+
+Errata&
+logf(RvBase& base, Errata::Code code, char const* format, ...) {
+    va_list rest;
+    va_start(rest, format);
+    return vlogf(base._errata, Errata::Id(0), code, format, rest);
+}
+
+Errata
+log_errno(Errata::Code code, char const* text) {
+  static size_t const SIZE = 1024;
+  char buffer[SIZE];
+  return logf(code, "%s [%d] %s", text, errno, strerror_r(errno, buffer, SIZE));
+}
+
+Errata
+vlogf_errno(Errata& errata, Errata::Id id, Errata::Code code, char const* format, va_list& rest) {
+  int e = errno; // Preserve value before making system calls.
+  int n;
+  static int const E_SIZE = 256;
+  char e_buffer[E_SIZE];
+  static int const T_SIZE = 8192;
+  char t_buffer[T_SIZE];
+  
+  n = vsnprintf(t_buffer, T_SIZE, format, rest);
+  if (0 <= n && n < T_SIZE) // still have room.
+    n += snprintf(t_buffer + n, T_SIZE - n, "[%d] %s", e, strerror_r(e, e_buffer, E_SIZE));
+  errata.push(id, code, t_buffer);
+  return errata;
+}
+
+Errata
+logf_errno(Errata::Code code, char const* format, ...) {
+  Errata zret;
+  va_list rest;
+  va_start(rest, format);
+  return vlogf_errno(zret, Errata::Id(), code, format, rest);
+}
+
+Errata
+logf_errno(Errata& errata, Errata::Code code, char const* format, ...) {
+  va_list rest;
+  va_start(rest, format);
+  return vlogf_errno(errata, Errata::Id(), code, format, rest);
+}
+
+Errata
+logf_errno(RvBase& rv, Errata::Code code, char const* format, ...) {
+    va_list rest;
+    va_start(rest, format);
+    return vlogf_errno(rv._errata, Errata::Id(), code, format, rest);
+}
+// ------------------------------------------------------
+}} // namespace ts::msg

Added: trafficserver/traffic/branches/wccp/proxy/tsconfig/TsErrataUtil.h
URL: http://svn.apache.org/viewvc/trafficserver/traffic/branches/wccp/proxy/tsconfig/TsErrataUtil.h?rev=1037235&view=auto
==============================================================================
--- trafficserver/traffic/branches/wccp/proxy/tsconfig/TsErrataUtil.h (added)
+++ trafficserver/traffic/branches/wccp/proxy/tsconfig/TsErrataUtil.h Sat Nov 20 15:17:55 2010
@@ -0,0 +1,151 @@
+/** @file
+    Utilities and logging.
+    Original implementation: Alan M. Carroll
+ */
+
+# if !defined(TS_ERRATA_UTIL_HEADER)
+# define TS_ERRATA_UTIL_HEADER
+
+// TBD: Need to do something better than this to get around using
+// 'DEBUG' as the name of a constant.
+# if defined DEBUG
+# undef DEBUG
+# define DEBUG DEBUG
+# endif
+
+# include <Errata.h>
+
+namespace ts { namespace msg {
+
+/// @name Message severity levels.
+//@{
+extern Errata::Code FATAL; ///< Fatal, cannot continue.
+extern Errata::Code WARN; ///< Significant, function degraded.
+extern Errata::Code INFO; ///< Interesting, not necessarily a problem.
+extern Errata::Code DEBUG; ///< Debugging information.
+//@}
+
+/** Logging / reporting support.
+    We build on top of @c Errata but we want to be able to prevent
+    message generation / allocation for messages with severity levels
+    less than a run time controllable value.
+
+    @internal Far from complete but serving as a prototype / experiment
+    to learn what's actually useful.
+*/
+//@{
+/// Report literal string to an Errata.
+/// @return @a err.
+Errata& log(
+  Errata& err,///< Target errata.
+  Errata::Id id, ///< Message ID.
+  Errata::Code code, ///< Severity level.
+  char const* text ///< Message text.
+);
+/// Report literal string to an Errata.
+/// Use message ID 0.
+/// @return @a err.
+Errata& log(
+    Errata& err,///< Target errata.
+    Errata::Code code, ///< Severity level.
+    char const* text ///< Message text.
+);
+/// Report literal string to a return value.
+/// Use message ID 0.
+/// @return The @c Errata in @a rv.
+Errata& log(
+    RvBase& rv,///< Return value.
+    Errata::Code code, ///< Severity level.
+    char const* text ///< Message text.
+);
+/// printf style log to Errata.
+/// @return @a err.
+Errata& logf(
+  Errata& err,///< Target errata.
+  Errata::Id id, ///< Message ID.
+  Errata::Code code, ///< Severity level.
+  char const* format, ///< Format string.
+  ... ///< Format string parameters.
+);
+/// printf style log to Errata.
+/// The message id is set to zero.
+/// @return @a err.
+Errata& logf(
+  Errata& err,///< Target errata.
+  Errata::Code code, ///< Severity level.
+  char const* format, ///< Format string.
+  ... ///< Format string parameters.
+);
+/// Return an Errata in a return value populated with a printf style formatted string.
+/// Use message ID 0.
+/// @return The @c Errata in @a rv.
+Errata& logf(
+    RvBase& rv, ///< Rv value.
+    Errata::Code code, ///< Severity level.
+    char const* format, ///< Message text.
+    ...
+);
+/// Return an Errata populated with a literal string.
+/// Use message ID 0.
+/// @return @a err.
+Errata log(
+  Errata::Code code, ///< Severity level.
+  char const* text ///< Message text.
+);
+/// Return an Errata populated with a printf style formatted string.
+/// Use message ID 0.
+/// @return @a err.
+Errata logf(
+  Errata::Code code, ///< Severity level.
+  char const* format, ///< Message text.
+  ...
+);
+/** Return an Errata based on @c errno.
+    The literal string is combined with the system text for the current
+    value of @c errno. This is modeled on @c perror. Message ID 0 is used.
+    @return The new @c Errata.
+ */
+Errata log_errno(
+  Errata::Code code, ///< Severity level.
+  char const* text ///< Message text.
+);
+/** Return an @c Errata based on @c errno.
+    @c errno and the corresponding system error string are appended to
+    the results from the @a format and following arguments.
+    @return The new @c Errata.
+ */
+Errata
+logf_errno(
+  Errata::Code code,  ///< Severity code.
+  char const* format, ///< Format string.
+  ... ///< Arguments for @a format.
+);
+/** Add a message to an @a errata based on @c errno.
+    @c errno and the corresponding system error string are appended to
+    the results from the @a format and following arguments.
+    @return @a errata.
+ */
+Errata
+logf_errno(
+  Errata& errata, ///< Errata to use.
+  Errata::Code code,  ///< Severity code.
+  char const* format, ///< Format string.
+  ... ///< Arguments for @a format.
+);
+/** Add a message to a return value based on @c errno.
+    @c errno and the corresponding system error string are appended to
+    the results from the @a format and following arguments.
+    @return The errata in @a rv.
+ */
+Errata
+logf_errno(
+  RvBase& rv, ///< Return value.
+  Errata::Code code,  ///< Severity code.
+  char const* format, ///< Format string.
+  ... ///< Arguments for @a format.
+);
+//@}
+
+}} // namespace ts::msg
+
+# endif // define TS_ERRATA_UTIL_HEADER

Added: trafficserver/traffic/branches/wccp/proxy/tsconfig/TsValue.cc
URL: http://svn.apache.org/viewvc/trafficserver/traffic/branches/wccp/proxy/tsconfig/TsValue.cc?rev=1037235&view=auto
==============================================================================
--- trafficserver/traffic/branches/wccp/proxy/tsconfig/TsValue.cc (added)
+++ trafficserver/traffic/branches/wccp/proxy/tsconfig/TsValue.cc Sat Nov 20 15:17:55 2010
@@ -0,0 +1,338 @@
+# include "TsValue.h"
+# include "TsBuilder.h"
+
+# include <TsErrataUtil.h>
+# include <sys/stat.h>
+# include <malloc.h>
+
+# if !defined(_MSC_VER)
+# define _fileno fileno
+# endif
+
+// ---------------------------------------------------------------------------
+namespace ts { namespace config {
+// ---------------------------------------------------------------------------
+Buffer const detail::NULL_BUFFER(0,0);
+ConstBuffer const detail::NULL_CONST_BUFFER(0,0);
+detail::ValueItem detail::ValueTableImpl::NULL_ITEM(VoidValue);
+detail::PseudoBool::Type const detail::PseudoBool::FALSE = 0;
+detail::PseudoBool::Type const detail::PseudoBool::TRUE = &detail::PseudoBool::operator !;
+// This should not be called, it is used only as a pointer value.
+bool detail::PseudoBool::operator ! () const { return false; }
+// ---------------------------------------------------------------------------
+unsigned int const detail::Type_Property[N_VALUE_TYPES] = {
+    0, // Void
+    detail::IS_VALID | detail::IS_CONTAINER, // List
+    detail::IS_VALID | detail::IS_CONTAINER, // Group
+    detail::IS_VALID | detail::IS_LITERAL, // String
+    detail::IS_VALID | detail::IS_LITERAL, // Integer
+};
+// ---------------------------------------------------------------------------
+detail::ValueTableImpl::ValueTableImpl() : _generation(0) { }
+detail::ValueTableImpl::~ValueTableImpl() {
+    for ( BufferGroup::iterator spot(_buffers.begin()), limit(_buffers.end()) ; spot != limit ; ++spot)
+        free(spot->_ptr);
+}
+// ---------------------------------------------------------------------------
+detail::ValueTable::ImplType*
+detail::ValueTable::instance() {
+    if (! _ptr) _ptr.reset(new ImplType);
+    return _ptr.get();
+}
+
+detail::ValueTable&
+detail::ValueTable::forceRootItem() {
+    ImplType* imp = this->instance();
+    if (0 == imp->_values.size())
+        imp->_values.push_back(ValueItem(GroupValue));
+    return *this;
+}
+
+Rv<detail::ValueIndex>
+detail::ValueTable::make(ValueIndex pidx, ValueType type, ConstBuffer const& name) {
+  Rv<ValueIndex> zret = NULL_VALUE_INDEX;
+  if (_ptr) {
+    size_t n = _ptr->_values.size();
+    // Check the parent
+    if (pidx < n) {
+      ValueItem* parent = &(_ptr->_values[pidx]);
+      if (IS_CONTAINER & Type_Property[parent->_type]) {
+        ValueItem* item;
+
+        _ptr->_values.push_back(ValueItem(type));
+        parent = &(_ptr->_values[pidx]); // possibly stale, refresh.
+        item = &(_ptr->_values[n]);
+        item->_parent = pidx;
+        parent->_children.push_back(n);
+        // Only use the name if the parent is a group.
+        if (GroupValue == parent->_type) item->_name = name;
+        zret = n; // mark for return to caller.
+      } else {
+        msg::log(zret.errata(), msg::WARN, "Add child failed because parent is not a container.");
+      }
+    } else {
+      msg::logf(zret.errata(), msg::WARN, "Add child failed because parent index (%ul) is out of range (%ul).", pidx.raw(), n);
+    }
+  } else {
+    msg::log(zret.errata(), msg::WARN, "Add child failed because the configuration is null.");
+  }
+  return zret;
+}
+
+detail::ValueItem&
+detail::ValueTable::operator [] ( ValueIndex idx ) {
+    assert(_ptr && idx < _ptr->_values.size());
+    return _ptr->_values[idx];
+}
+Buffer
+detail::ValueTable::alloc(size_t n) {
+    ImplType* imp = this->instance();
+    Buffer zret(static_cast<char*>(malloc(n)), n);
+    if (zret._ptr) imp->_buffers.push_back(zret);
+    return zret;
+}
+
+// ---------------------------------------------------------------------------
+Value
+Value::operator [] (size_t idx) {
+    Value zret;
+    detail::ValueItem* item = this->item();
+    if (item && idx < item->_children.size()) {
+        zret = Value(_config, item->_children[idx]);
+        if (PathValue == zret.getType()) zret = _config.getRoot().find(_config._table[zret._vidx]._path);
+    }
+    return zret;
+}
+
+Value
+Value::operator [] (ConstBuffer const& name) {
+    Value zret;
+    detail::ValueItem* item = this->item();
+    if (item) {
+        for ( detail::ValueItem::ChildGroup::iterator spot = item->_children.begin(), limit = item->_children.end(); spot != limit; ++spot ) {
+            if (_config._table[*spot]._name == name) {
+                zret = Value(_config, *spot);
+                if (PathValue == zret.getType()) zret = _config.getRoot().find(_config._table[zret._vidx]._path);
+                break;
+            }
+        }
+    }
+    return zret;
+}
+
+Value
+Value::find( ConstBuffer const& path ) {
+    Value zret = *this;
+    Path::Parser parser(path);
+    Rv<Path::Parser::Result> x;
+    ConstBuffer elt;
+    for ( x = parser.parse(&elt) ; zret && Path::Parser::EOP != x && Path::Parser::ERROR != x ; x = parser.parse(&elt) ) {
+        if (Path::Parser::TAG == x) zret = zret[elt];
+        else if (Path::Parser::INDEX == x) zret = zret[elt._size];
+        else zret.reset();
+    }
+    if (Path::Parser::EOP != x) zret.reset();
+    return zret;
+}
+
+Value
+Value::find(Path const& path ) {
+    Value zret = *this;
+    for ( size_t i = 0, n = path.count() ; i < n && zret ; ++i ) {
+        ConstBuffer const& elt = path[i];
+        if (elt._ptr) zret = zret[elt];
+        else zret = zret[elt._size];
+    }
+    return zret;
+}
+
+Rv<Value>
+Value::makeChild(ValueType type, ConstBuffer const& name) {
+    Rv<Value> zret;
+    Rv<detail::ValueIndex> vr = _config._table.make(this->_vidx, type, name);
+    if (vr.isOK()) zret = Value(_config, vr.result());
+    else zret.errata() = vr.errata();
+    return zret;
+}
+
+Rv<Value>
+Value::makeGroup(ConstBuffer const& name) {
+    return this->makeChild(GroupValue, name);
+}
+
+Rv<Value>
+Value::makeList(ConstBuffer const& name) {
+    return this->makeChild(ListValue, name);
+}
+
+Rv<Value>
+Value::makeString(ConstBuffer const& text, ConstBuffer const& name) {
+    Rv<Value> zret = this->makeChild(StringValue, name);
+    if (zret.isOK()) zret.result().setText(text);
+    return zret;
+}
+
+Rv<Value>
+Value::makeInteger(ConstBuffer const& text, ConstBuffer const& name) {
+    Rv<Value> zret = this->makeChild(IntegerValue, name);
+    if (zret.isOK()) zret.result().setText(text);
+    return zret;
+}
+
+Rv<Value>
+Value::makePath(Path const& path, ConstBuffer const& name) {
+    Rv<Value> zret = this->makeChild(PathValue, name);
+    if (zret.isOK()) _config._table[zret.result()._vidx]._path = path;
+    return zret;
+}
+// ---------------------------------------------------------------------------
+Path& Path::reset() {
+    if (_ptr) {
+        // If we're sharing the instance, make a new one for us.
+        if (_ptr.isShared()) _ptr = new ImplType;
+        else { // clear out the existing instance.
+            _ptr->_elements.clear();
+        }
+    }
+    return *this;
+}
+// ---------------------------------------------------------------------------
+Rv<Path::Parser::Result>
+Path::Parser::parse(ConstBuffer *cbuff) {
+    Rv<Result> zret = EOP;
+    enum State {
+        S_INIT, // initial state
+        S_INDEX, // reading index.
+        S_TAG, // reading tag.
+        S_DASH, // reading dashes in tag.
+    } state = S_INIT;
+
+    // Character bucket
+    enum Bucket {
+        C_INVALID, // Invalid input.
+        C_DIGIT, // digit.
+        C_IDENT, // Identifier character.
+        C_DASH, // A dash
+        C_DOT, // A dot (period).
+    };
+
+    if (cbuff) cbuff->reset();
+    char const* start = _c; // save starting character location.
+    size_t idx = 0; // accumulator for index value.
+
+    bool final = false;
+    while (! final && this->hasInput()) {
+        Bucket cb;
+        if (isdigit(*_c)) cb = C_DIGIT;
+        else if ('_' == *_c || isalpha(*_c)) cb = C_IDENT;
+        else if ('-' == *_c) cb = C_DASH;
+        else if ('.' == *_c) cb = C_DOT;
+        else cb = C_INVALID;
+
+        if (C_INVALID == cb) {
+            msg::logf(zret, msg::WARN, "Invalid character '%c' [%u] in path.", *_c, *_c);
+        } else switch (state) {
+            case S_INIT:
+                switch (cb) {
+                    case C_DIGIT: state = S_INDEX; idx = *_c - '0'; break;
+                    case C_IDENT: state = S_TAG; break;
+                    case C_DASH: msg::logf(zret, msg::WARN, "Dash not allowed as leading character for tag."); final = true; break;
+                    case C_DOT: msg::logf(zret, msg::WARN, "Separator without preceding element."); final = true; break;
+                    default: msg::logf(zret, msg::WARN, "Internal error: unexpected character %u in INIT state.", *_c); final = true; break;
+                }
+                break;
+            case S_INDEX: // reading an index.
+                if (C_DIGIT == cb) idx = 10 * idx + *_c - '0';
+                else if (C_DOT == cb) { final = true; }
+                else {
+                    msg::logf(zret, msg::WARN, "Invalid character '%c' [%u] in index element.", *_c, *_c);
+                    final = true;
+                }
+                break;
+            case S_TAG: // reading a tag.
+                if (C_IDENT == cb || C_DIGIT == cb) ; // continue
+                else if (C_DASH == cb) state = S_DASH;
+                else if (C_DOT == cb) { final = true; }
+                else { // should never happen, but be safe.
+                    msg::logf(zret, msg::WARN, "Invalid character '%c' [%u] in index element.", *_c, *_c);
+                    final = true;
+                }
+                break;
+            case S_DASH: // dashes inside tag.
+                if (C_IDENT == cb || C_DIGIT == cb) state = S_TAG;
+                else if (C_DOT == cb) {
+                    msg::log(zret, msg::WARN, "Trailing dash not allowed in tag element.");
+                    final = true;
+                } else if (C_DASH != cb) { // should never happen, but be safe.
+                    msg::logf(zret, msg::WARN, "Invalid character '%c' [%u] in index element.", *_c, *_c);
+                    final = true;
+                }
+                break;
+        }
+        ++_c;
+    }
+    if (!zret.isOK()) {
+        zret = ERROR;
+        if (cbuff) cbuff->set(_c - 1, 1);
+        _c = 0;
+        _input.reset();
+    } else if (S_INIT == state) {
+        zret = EOP;
+    } else if (S_TAG == state) {
+        zret = TAG;
+        if (cbuff) {
+            cbuff->set(start, _c - start);
+            // if @a final is set, then we parsed a dot separator.
+            // don't include it in the returned tag.
+            if (final) cbuff->_size -= 1;
+        }
+    } else if (S_INDEX == state) {
+        zret = INDEX;
+        if (cbuff) cbuff->_size = idx;
+    } else if (S_DASH == state) {
+        zret = ERROR;
+        msg::log(zret, msg::WARN, "Trailing dash not allowed in tag element.");
+        if (cbuff) cbuff->set(start, _c - start);
+    }
+    return zret;
+}
+// ---------------------------------------------------------------------------
+Value
+Configuration::getRoot() {
+    this->_table.forceRootItem();
+    return Value(*this, 0);
+}
+
+Rv<Configuration>
+Configuration::loadFromPath(char const* path) {
+    Rv<Configuration> zret;
+    Buffer buffer(0,0);
+    FILE* in = fopen(path, "r");
+
+    if (in) {
+        struct stat info;
+        if (0 == fstat(_fileno(in), &info)) {
+            // Must reserve 2 bytes at the end for FLEX terminator.
+            buffer = zret.result().alloc(info.st_size + 2);
+            if (buffer._ptr) {
+                size_t n;
+                if (0 < (n = fread(buffer._ptr, sizeof(char), info.st_size, in))) {
+                    buffer._size = n+2;
+                    memset(buffer._ptr + n, 0, 2); // required by FLEX
+                    zret = Builder(zret.result()).build(buffer);
+                } else {
+                    msg::logf_errno(zret, msg::WARN, "failed to read %llu bytes from configuration file '%s'", info.st_size, path);
+                }
+            } else {
+                msg::logf_errno(zret, msg::WARN, "failed to allocate buffer for configuration file '%s' - needed %llu bytes.", path, info.st_size);
+            }
+        } else {
+            msg::logf_errno(zret, msg::WARN, "failed to determine file information on '%s'", path);
+        }
+    } else {
+        msg::logf_errno(zret, msg::WARN, "failed to open configuration file '%s'", path);
+    }
+    return zret;
+}
+
+}} // namespace ts::config

Added: trafficserver/traffic/branches/wccp/proxy/tsconfig/TsValue.h
URL: http://svn.apache.org/viewvc/trafficserver/traffic/branches/wccp/proxy/tsconfig/TsValue.h?rev=1037235&view=auto
==============================================================================
--- trafficserver/traffic/branches/wccp/proxy/tsconfig/TsValue.h (added)
+++ trafficserver/traffic/branches/wccp/proxy/tsconfig/TsValue.h Sat Nov 20 15:17:55 2010
@@ -0,0 +1,604 @@
+# if ! defined(TS_CONFIG_VALUE_HEADER)
+# define TS_CONFIG_VALUE_HEADER
+
+# include <TsBuffer.h>
+# include <NumericType.h>
+# include <IntrusivePtr.h>
+# include <Errata.h>
+# include <vector>
+
+namespace ts { namespace config {
+
+// Forward declares.
+class Value;
+class Path;
+
+namespace detail {
+  /** Class to provide a "pseudo bool" value.
+      This is used as the return type for the positive logical operator
+      (the converse of @c operator! ). This makes a class directly
+      usable in logical expressions. It is like a pointer but @b not
+      convertible to anything else, and so avoiding any undesirable
+      automatic conversions and the resulting ambiguities.
+  */
+  struct PseudoBool {
+    typedef bool (PseudoBool::*Type)() const; ///< The type itself.
+    bool operator ! () const; ///< A method to use for the @c true value.
+    static Type const TRUE; ///< The @c true equivalent.
+    static Type const FALSE; ///< The @c false equivalent.
+  };
+}
+
+/// Type of value.
+enum ValueType {
+  VoidValue, ///< No value, invalid.
+  ListValue, ///< List of values.
+  GroupValue, ///< Group of values.
+  StringValue, ///< Text string.
+  IntegerValue, ///< Integer.
+  PathValue, ///< Path.
+  // Update N_VALUE_TYPES if you change the last enum value !!
+};
+/// Number of value types.
+static size_t const N_VALUE_TYPES = PathValue + 1;
+
+/** A path to a value in a configuration.
+ */
+class Path {
+  friend class Value;
+protected:
+  class ImplType : public IntrusivePtrCounter {
+    friend class Path;
+  public:
+    ImplType(); ///< Constructor.
+  protected:
+    /** Container for path elements.
+        We are subtle with our elements, which can be either a string
+        or a numeric index. By convention, if the pointer in the buffer is
+        @c NULL, then the size is a numeric index. Otherwise it's a name.
+    */
+    typedef std::vector<ConstBuffer> Elements;
+    Elements _elements; ///< Path elements.
+  };
+public:
+  typedef Path self; ///< Self reference type.
+
+  Path(); ///< Default constructor.
+
+  /// Append a string tag to the path.
+  self& append(
+    ConstBuffer const& tag ///< Text of tag.
+  );
+  /// Append a numeric index to the path.
+  self& append(
+    size_t idx ///< Index.
+  );
+  /// Reset to default constructed state.
+  self& reset();
+
+  /// Get the number of elements in this path.
+  size_t count() const;
+
+  /// Access an element by @a index.
+  ConstBuffer const& operator [] (
+    size_t index ///< Element index.
+  ) const;
+
+  /** Parser for path text.
+      This is restartable so a path can be parsed in pieces.
+      @internal Sadly, FLEX is just too much overhead to be useful here.
+  */
+  class Parser {
+  public:
+    typedef Parser self; ///< Self reference type.
+
+    Parser(); ///< Default constructor.
+    /** Construct with input.
+
+        This default constructs the Parser then calls @c setInput with
+        @a text. It is provided as a convenience as that will be the
+        common use case.
+
+        @see setInput.
+    */
+    Parser(
+      ConstBuffer const& text ///< Input text.
+    );
+
+    /** Set the input @a text.
+        Parsing state is reset and the next parsing call will
+        start at the beginning of @a text.
+    */
+    self& setInput(
+      ConstBuffer const& text ///< Input buffer.
+    );
+
+    /// Parsing result.
+    enum Result {
+      ERROR, ///< Bad input.
+      TAG, ///< Path tag.
+      INDEX, ///< Path index.
+      EOP, ///< End Of Path.
+    };
+
+    /** Parse the next element in the path.
+
+        @a cbuff may be @c NULL in which case no data about elements
+        is available.  In general this should be called until @c EOP
+        or @c ERROR is returned, each call returning the next element.
+
+        @return A parse @c Result.
+        - TAG: A tag was found. The start and length are stored in @a cbuff.
+        - INDEX: An index was found. The value is in @a cbuff._size.
+        - EOP: No more path elements were found. Do not continue parsing.
+        - ERROR: A syntax error was encountered. See the errata for detail. Do not continue parsing.
+    */
+    Rv<Result> parse(
+      ConstBuffer* cbuff = 0 ///< [out] Parsed path element.
+    );
+
+    /// Check if input is available.
+    bool hasInput() const;
+
+  protected:
+    ConstBuffer _input; ///< Current input buffer.
+    char const* _c; ///< Next input character.
+  };
+protected:
+  typedef IntrusivePtr<ImplType> ImplPtr; ///< Smart pointer to implementation.
+  ImplPtr _ptr; ///< Our instance.
+  /// Force an implementation instance and return a pointer to it.
+  ImplType* instance();
+};
+
+namespace detail {
+  /// Null buffer, handy in several places.
+  extern Buffer const NULL_BUFFER;
+  /// Null buffer, handy in several places.
+  extern ConstBuffer const NULL_CONST_BUFFER;
+  /// Index type for value items in the global table.
+  typedef NumericType<size_t, struct ValueIndexTag> ValueIndex;
+  /// Index value that presents NULL (invalid value).
+  static ValueIndex const NULL_VALUE_INDEX = static_cast<ValueIndex::raw_type>(-1);
+  /// Numeric type for configuration generation.
+  typedef NumericType<size_t, struct GenerationTag> Generation;
+
+  /** Value type properties.
+      These are used as bit masks on elements of an array.
+  */
+  static unsigned int const IS_VALID = 1;
+  static unsigned int const IS_LITERAL = 1<<1;
+  static unsigned int const IS_CONTAINER = 1<<2;
+
+  /// Value type property table.
+  extern unsigned int const Type_Property[N_VALUE_TYPES];
+
+  /** A value in the configuration.
+      This is used in a global table so it handles all types of Values.
+      Members that are not used for scalars are designed to be @c NULL
+      pointers in that case.
+  */
+  class ValueItem {
+    // Apparently the C++ standard, 7.3.1.2, states that unqualified
+    // friend classes only considers the current namespace, not any
+    // outer ones. So we have to fully qualify this. Blech.
+    friend class ts::config::Value;
+    friend class ValueTable;
+  public:
+    /// Default constructor.
+    ValueItem();
+    /// Construct empty item of a specific type.
+    ValueItem(ValueType type);
+    /// Get item type.
+    ValueType getType() const;
+  protected:
+    /// Type of value.
+    ValueType _type;
+    /// Index of parent value.
+    ValueIndex _parent;
+    /// Text of value (if scalar).
+    ConstBuffer _text;
+    /// Local name of value, if available.
+    ConstBuffer _name;
+    /// Container for children of this item.
+    typedef std::vector<ValueIndex> ChildGroup;
+    /// Child items of this item.
+    ChildGroup _children;
+    /// Path if present.
+    Path _path;
+
+    // This is for optimizing named access at some point in the future.
+    /// Hold a child item name in a table for fast lookup.
+    struct Name {
+      ConstBuffer _text; ///< Text of name.
+      ValueIndex _index; ///< Index of child.
+    };
+    /// Container for child names.
+    typedef std::vector<Name> NameGroup;
+    /** Child names, if appropriate.
+        This is faulted in when needed, if this value is an aggregate with
+        named children. The list must be sorted on name so that it can be binary
+        searched for performance.
+    */
+    NameGroup _names;
+  };
+
+  class ValueTable;
+
+  /** Table of configuration values.
+      This holds all the values for a specific configuration.
+  */
+  class ValueTableImpl : public IntrusivePtrCounter {
+    friend class ValueTable;
+  public:
+    typedef ValueTableImpl self; ///< Self reference type.
+
+    ValueTableImpl(); ///< Constructor.
+    ~ValueTableImpl(); ///< Destructor.
+  protected:
+    /// Container for value items.
+    typedef std::vector<ValueItem> ItemTable;
+    ItemTable _values; ///< All configuration values.
+    Generation _generation; ///< Generation number of configuration.
+    /// A group of buffers.
+    typedef std::vector<Buffer> BufferGroup;
+    /** Locally allocated buffers.
+        These are freed when this object is destroyed.
+    */
+    BufferGroup _buffers;
+
+    static ValueItem NULL_ITEM; ///< Null item for invalid access return.
+  };
+
+  /** Wrapper class for a table of configuration values.
+      @internal Really, this should be merged in to Configuration. The original
+      differences have evolved out of the implementation.
+  */
+  class ValueTable {
+  public:
+    typedef ValueTable self; ///< Self reference type.
+    typedef ValueTableImpl ImplType; ///< Implementation type.
+
+    /// Table size.
+    /// @return The number of value items in the table.
+    size_t size() const;
+    /// Generation.
+    /// @return The generation number.
+    Generation generation() const;
+
+    /// Const access by index.
+    /// @return The value item at index @a idx.
+    ValueItem const& operator [] (
+      ValueIndex idx ///< Index of item.
+    ) const;
+    /// Access by index.
+    /// @return The value item at index @a idx.
+    ValueItem& operator [] (
+      ValueIndex idx ///< Index of item.
+    );
+
+    /// Force the existence of the root item in the table.
+    /// @return @c this object.
+    self& forceRootItem();
+    /** Create a new item (value) with optional @a name
+        The table must contain @a parent. If @a name is omitted, the item
+        has an empty name.
+        @return Index of the new value item.
+    */
+    Rv<ValueIndex> make(
+      ValueIndex parent, ///< Index of parent for item.
+      ValueType type, ///< Type of item.
+      ConstBuffer const& name = NULL_BUFFER ///< Name (may be empty).
+    );
+
+    /// Test for not table existence.
+    /// @return @c false if the implementation instance exists, @c true if not.
+    bool operator ! () const;
+    /// Test for table existence.
+    /// @return @c true if the implementation instance exists, @c false if not.
+    operator PseudoBool::Type() const;
+    /// Reset to default constructed state.
+    /// @return @c this object.
+    self& reset();
+
+    /** Allocate a local buffer.
+        This buffer will persist until the implementation instance
+        is destoyed.
+        @return The allocated buffer.
+    */
+    Buffer alloc(size_t n);
+  protected:
+    typedef IntrusivePtr<ImplType> ImplPtr; ///< Smart pointer to implementation instance.
+    ImplPtr _ptr; ///< Implementation instance.
+
+    /// Force an implementation instance and return a pointer to it.
+    ImplType* instance();
+  };
+} // namespace detail
+
+/** Container for a configuration.
+    This is a wrapper class that holds a shared reference to a configuration.
+*/
+class Configuration {
+  friend class Value;
+public:
+  typedef Configuration self; ///< Self reference type.
+
+  /** Check if configuration is (not) valid.
+      @return @c true if this configuration is invalid, @c false otherwise.
+  */
+  bool operator ! () const;
+  /** Check if the configuration is valid.
+      @return The equivalent of @c true if this does @b not contain a value,
+      the equivalent of @c false if it does.
+  */
+  operator detail::PseudoBool::Type () const;
+  /** Get the root @c Value of the configuration.
+      The root is always a group and has no name.
+      @return The root value.
+  */
+  Value getRoot();
+
+  /** Find a value.
+      @return The value if found, an void valid if not.
+  */
+  Value find(
+    char const* path ///< configuration path to value.
+  );
+  /** Load a configuration from a file.
+
+      @note Check the returned errata for problems during configuration
+      load. It is probably not a good idea to use the configuration in
+      any error are reported.
+      @return A new @c Configuration and errata.
+  */
+  static Rv<self> loadFromPath(
+    char const* path ///< file system path.
+  );
+  /** Allocate a local buffer of size @a n.
+      This buffer will persist until the implementation instance
+      is destroyed.
+      @return The allocated buffer.
+  */
+  Buffer alloc(
+    size_t n ///< requested size of buffer.
+  );
+protected:
+  detail::ValueTable _table; ///< Table of values from the configuration.
+};
+
+/** This holds a value from the configuration.
+
+    @internal It is critical that none of the type specific subclasses define any data members
+    so that instances can be freely converted to and from this base class.
+*/
+class Value {
+  friend class Configuration;
+public:
+  typedef Value self; ///< Self reference type.
+  /// Default constructors.
+  /// Creates an @c NULL instance.
+  Value();
+  /// Destructor.
+  ~Value();
+
+  /// Get the type of value.
+  ValueType getType() const;
+  /// Test if this is a valid value.
+  /// @return @c true if this contains a value, @c false otherwise.
+  bool hasValue() const;
+  /** Operator form of @c hasValue.
+      @see hasValue
+      @return @c true if this does @b not contain a value, @c false if it does.
+  */
+  bool operator ! () const;
+  /** Logical form of @c hasValue for use in logical expressions.
+      @see hasValue
+      @return The equivalent of @c true if this does @b not contain a value,
+      the equivalent of @c false if it does.
+  */
+  operator detail::PseudoBool::Type () const;
+
+  /** Get the value text.
+      @return The text in the configuration file for this item if the item
+      is a scalar, an empty buffer otherwise.
+  */
+  ConstBuffer const& getText() const;
+  /// Set the @a text for this value.
+  self& setText(
+    ConstBuffer const& text
+  );
+
+  /// Test for a literal value.
+  /// @return @c true if the value is a literal, @c false if it is a container or invalid.
+  bool isLiteral() const;
+  /// Test for value container.
+  /// @return @c true if the value is a container (can have child values), @c false otherwise.
+  bool isContainer() const;
+  /// Get the parent value.
+  Value getParent() const;
+  /// Test if this is the root value for the configuration.
+  bool isRoot() const;
+
+  /// Get the number of child values.
+  size_t childCount() const;
+  /** Child access by @a index
+      @return The child or a @c Void value if there is no child with @a name.
+  */
+  Value operator [] (
+    size_t idx ///< Index of child value.
+  );
+  /** Child access by @a name.
+      @return The child or a @c Void value if there is no child with @a name.
+  */
+  Value operator [] (
+    ConstBuffer const& name
+  );
+  /** Child access by @a name.
+      @return The child or a @c Void value if there is no child with @a name.
+  */
+  Value operator [] (
+    char const* name ///< Null terminated string.
+  );
+
+  /** Creating child values.
+
+      These methods all take an optional @a name argument. This is required if @c this
+      is a @c Group and ignored if @c this is a @c List.
+
+
+      These methods will fail if
+      - @c this is not a container.
+      - @c this is a @c Group and no @a name is provided.
+
+      @note Currently for groups, duplicate names are not detected. The duplicates
+      will be inaccessible by name but can still be found by index. This is a problem
+      but I am still pondering the appropriate solution.
+
+      @see isContainer
+      @return The new value, or an invalid value plus errata on failure.
+
+      @internal I original had this as a single method, but changed to separate per type.
+      Overall less ugly because we can get the arguments more useful.
+  */
+  //@{
+  /// Create a @c String value.
+  Rv<Value> makeString(
+    ConstBuffer const& text, ///< String content.
+    ConstBuffer const& name = detail::NULL_BUFFER///< Optional name of value.
+  );
+  /// Create an @c Integer value.
+  Rv<Value> makeInteger(
+    ConstBuffer const& text, ///< Text of number.
+    ConstBuffer const& name = detail::NULL_BUFFER///< Optional name of value.
+  );
+  /// Create a @c Group value.
+  Rv<Value> makeGroup(
+    ConstBuffer const& name = detail::NULL_BUFFER///< Optional name of value.
+  );
+  /// Create a @c List value.
+  Rv<Value> makeList(
+    ConstBuffer const& name = detail::NULL_BUFFER///< Optional name of value.
+  );
+  /// Create a @c Path value.
+  Rv<Value> makePath(
+    Path const& path, ///< Path.
+    ConstBuffer const& name = detail::NULL_BUFFER///< Optional name of value.
+  );
+  /// Create a child by type.
+  /// Client must fill in any other required elements.
+  Rv<Value> makeChild(
+    ValueType type, ///< Type of child.
+    ConstBuffer const& name = detail::NULL_BUFFER///< Optional name of value.
+  );
+  //@}
+
+  /** Find a value.
+      @return The value if found, an void valid if not.
+  */
+  Value find(
+    ConstBuffer const& path ///< Path relative to this value.
+  );
+  /** Find a value.
+      @return The value if found, an void valid if not.
+  */
+  Value find(
+    char const* path ///< Path relative to this value.
+  );
+  /** Find a value using a precondensed path.
+      @return The value if found, an void valid if not.
+  */
+  Value find(
+    Path const& path ///< Path relative to this value.
+  );
+
+  /** Reset to default constructed state.
+      @note This wrapper is reset, the value in the configuration is unchanged.
+      @return @c this object.
+  */
+  self& reset();
+
+protected:
+  // Note: We store an index and not a pointer because a pointer will go stale
+  // if any items are added or removed from the underlying table.
+  // Also, by storing the configuration, we hold it in memory as long as a Value
+  // is in client hands.
+  Configuration _config; ///< The configuration for this value.
+  detail::ValueIndex _vidx; ///< Index of item.
+
+  static Buffer const NULL_BUFFER; ///< Empty buffer to return on method failures.
+
+  /// Construct from raw data.
+  Value(
+    Configuration cfg, ///< Source configuration.
+    detail::ValueIndex vidx  ///< Index of value.
+  );
+
+  /** Get raw item pointer.
+      @note This pointer is unstable and must be recomputed on each method invocation.
+      @return The item pointer or @c NULL if this value is invalid.
+  */
+  detail::ValueItem* item();
+  /** Get constant raw item pointer.
+      @note This pointer is unstable and must be recomputed on each method invocation.
+      @return The item pointer or @c NULL if this value is invalid.
+  */
+  detail::ValueItem const* item() const;
+};
+
+// Inline methods.
+namespace detail {
+  inline bool ValueTable::operator ! () const { return ! _ptr; }
+  inline ValueTable::operator PseudoBool::Type () const { return _ptr ? PseudoBool::TRUE : PseudoBool::FALSE; }
+  inline size_t ValueTable::size() const { return _ptr ? _ptr->_values.size() : 0; }
+  inline Generation ValueTable::generation() const { return _ptr ? _ptr->_generation : Generation(0); }
+  inline ValueItem const& ValueTable::operator [] (ValueIndex idx) const { return const_cast<self*>(this)->operator [] (idx); }
+  inline ValueTable& ValueTable::reset() { _ptr = 0; return *this; }
+
+  inline ValueItem::ValueItem() : _type(VoidValue), _text(0,0), _name(0,0) {}
+  inline ValueItem::ValueItem(ValueType type) : _type(type), _text(0,0), _name(0,0) {}
+  inline ValueType ValueItem::getType() const { return _type; }
+}
+
+inline Value::~Value() { }
+inline Value::Value() : _vidx(detail::NULL_VALUE_INDEX) {}
+inline Value::Value(Configuration cfg, detail::ValueIndex vidx) : _config(cfg), _vidx(vidx) { }
+inline bool Value::hasValue() const { return _config && _vidx != detail::NULL_VALUE_INDEX; }
+inline Value::operator detail::PseudoBool::Type () const { return this->hasValue() ? detail::PseudoBool::TRUE : detail::PseudoBool::FALSE; }
+inline bool Value::operator ! () const { return ! this->hasValue(); }
+inline ValueType Value::getType() const { return this->hasValue() ? _config._table[_vidx]._type : VoidValue; }
+inline ConstBuffer const& Value::getText() const {
+  return this->hasValue() ? _config._table[_vidx]._name : detail::NULL_CONST_BUFFER;
+}
+inline Value& Value::setText(ConstBuffer const& text) { if (this->hasValue()) _config._table[_vidx]._text = text; return *this; }
+inline bool Value::isLiteral() const { return 0 != (detail::IS_LITERAL & detail::Type_Property[this->getType()]); }
+inline bool Value::isContainer() const { return 0 != (detail::IS_CONTAINER & detail::Type_Property[this->getType()]); }
+inline Value Value::getParent() const { return this->hasValue() ? Value(_config, _config._table[_vidx]._parent) : Value(); }
+inline bool Value::isRoot() const { return this->hasValue() && _vidx == 0; }
+inline Value& Value::reset() { _config = Configuration(); _vidx = detail::NULL_VALUE_INDEX; return *this; }
+inline detail::ValueItem* Value::item() { return this->hasValue() ? &(_config._table[_vidx]) : 0; }
+inline detail::ValueItem const* Value::item() const { return const_cast<self*>(this)->item(); }
+inline Value Value::operator [] (char const* name) { return (*this)[ConstBuffer(name, strlen(name))]; }
+inline Value Value::find(char const* path) { return this->find(ConstBuffer(path, strlen(path))); }
+
+inline Path::ImplType::ImplType() { }
+
+inline Path::Path() { }
+inline Path::ImplType* Path::instance() { if (!_ptr) _ptr = new ImplType; return _ptr.get(); }
+inline Path& Path::append(ConstBuffer const& tag) { this->instance()->_elements.push_back(tag); return *this; }
+inline Path& Path::append(size_t index) { this->instance()->_elements.push_back(ConstBuffer(0, index)); return *this; }
+inline size_t Path::count() const { return _ptr ? _ptr->_elements.size() : 0; }
+inline ConstBuffer const& Path::operator [] (size_t idx) const { return _ptr ? _ptr->_elements[idx] : detail::NULL_CONST_BUFFER; }
+
+inline Path::Parser::Parser() : _input(0,0), _c(0) { }
+inline Path::Parser::Parser( ConstBuffer const& text ) : _input(text), _c(text._ptr) { }
+inline bool Path::Parser::hasInput() const { return _input._ptr && _input._ptr + _input._size > _c; }
+
+inline bool Configuration::operator ! () const { return ! _table; }
+inline Configuration::operator detail::PseudoBool::Type() const { return _table.operator detail::PseudoBool::Type(); }
+inline Value Configuration::find( char const* path ) { return this->getRoot().find(path); }
+inline Buffer Configuration::alloc(size_t n) { return _table.alloc(n);  }
+
+}} // namespace ts::config
+
+# endif