• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

TsBuilder.cc

Go to the documentation of this file.
00001 /** @file
00002 
00003     Implementation of the handler for parsing events.
00004 
00005     @section license License
00006 
00007     Licensed to the Apache Software Foundation (ASF) under one
00008     or more contributor license agreements.  See the NOTICE file
00009     distributed with this work for additional information
00010     regarding copyright ownership.  The ASF licenses this file
00011     to you under the Apache License, Version 2.0 (the
00012     "License"); you may not use this file except in compliance
00013     with the License.  You may obtain a copy of the License at
00014 
00015     http://www.apache.org/licenses/LICENSE-2.0
00016 
00017     Unless required by applicable law or agreed to in writing, software
00018     distributed under the License is distributed on an "AS IS" BASIS,
00019     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00020     See the License for the specific language governing permissions and
00021     limitations under the License.
00022  */
00023 
00024 # include "TsBuilder.h"
00025 # include "TsErrataUtil.h"
00026 # include "TsConfigLexer.h"
00027 # include "TsConfigGrammar.hpp"
00028 # include <stdlib.h>
00029 
00030 // Prefix for text of our messages.
00031 # define PRE "Configuration Parser: "
00032 
00033 namespace {
00034 /** Compress a string by removing escape characters.
00035     @return The new length of the string.
00036 */
00037 size_t unescape_string(char* text, size_t len) {
00038   size_t zret = len;
00039   // quick check - if no escape char, do nothing.
00040   char* dst = static_cast<char*>(memchr(text, '\\', len));
00041   if (dst) {
00042     char* limit = text + len;
00043     char* src = dst + 1; // skip escape char
00044     for ( *dst++ = *src++ ; src < limit ; ++src )
00045       if ('\\' != *src) *dst++ = *src;
00046       else if (++src < limit) *dst++ = *src;
00047       else *dst++ = '\\'; // trailing backslash.
00048     zret = dst - text;
00049   }
00050   return zret;
00051 }
00052 } // anon namespace
00053 
00054 namespace ts { namespace config {
00055 
00056 Builder&
00057 Builder::init() {
00058   // Fill in each element to dispatch through the static
00059   // method. Callback data is a pointer to an entry in @c dispatch
00060   // which contains pointer to this object and a pointer to the
00061   // appropriate dispatch method.
00062 
00063   // Zero everything first, just to be safe.
00064   memset(_dispatch, 0, sizeof(_dispatch));
00065 
00066   for ( size_t i = 0 ; i < TS_CONFIG_N_EVENT_TYPES ; ++i) {
00067     _dispatch[i]._ptr = this;
00068     _handlers.handler[i]._f = &self::dispatch;
00069     _handlers.handler[i]._data = &(_dispatch[i]);
00070   }
00071 
00072   _dispatch[TsConfigEventGroupOpen]._method = &self::groupOpen;
00073   _dispatch[TsConfigEventGroupName]._method = &self::groupName;
00074   _dispatch[TsConfigEventGroupClose]._method = &self::groupClose;
00075   _dispatch[TsConfigEventListOpen]._method = &self::listOpen;
00076   _dispatch[TsConfigEventListClose]._method = &self::listClose;
00077   _dispatch[TsConfigEventPathOpen]._method = &self::pathOpen;
00078   _dispatch[TsConfigEventPathTag]._method = &self::pathTag;
00079   _dispatch[TsConfigEventPathIndex]._method = &self::pathIndex;
00080   _dispatch[TsConfigEventPathClose]._method = &self::pathClose;
00081   _dispatch[TsConfigEventLiteralValue]._method = &self::literalValue;
00082   _dispatch[TsConfigEventInvalidToken]._method = &self::invalidToken;
00083 
00084   _handlers.error._data = this;
00085   _handlers.error._f = &self::syntaxErrorDispatch;
00086 
00087   return *this;
00088 }
00089 
00090 // Error messages here have to just be logged, as they effectively report that
00091 // the dispatcher can't find the builder object.
00092 void
00093 Builder::dispatch(void* data, Token* token) {
00094     if (data) {
00095         Handler* handler = reinterpret_cast<Handler*>(data);
00096         if (handler->_ptr) {
00097             if (handler->_method) {
00098                 ((handler->_ptr)->*(handler->_method))(*token);
00099             } else {
00100                 msg::logf(msg::WARN, PRE "Unable to dispatch event - no method.");
00101             }
00102         } else {
00103             msg::logf(msg::WARN, PRE "Unable to dispatch event - no builder.");
00104         }
00105     } else {
00106         msg::logf(msg::WARN, PRE "Unable to dispatch event - no handler.");
00107     }
00108 }
00109 
00110 int
00111 Builder::syntaxErrorDispatch(void* data, char const* text) {
00112     return reinterpret_cast<Builder*>(data)->syntaxError(text);
00113 }
00114 
00115 int
00116 Builder::syntaxError(char const* text) {
00117   msg::logf(_errata, msg::WARN,
00118     "Syntax error '%s' near line %d, column %d.",
00119     text, tsconfiglex_current_line(), tsconfiglex_current_col()
00120   );
00121   return 0;
00122 }
00123 
00124 Rv<Configuration>
00125 Builder::build(Buffer const& buffer) {
00126   _v = _config.getRoot(); // seed current value.
00127   _errata.clear(); // no errors yet.
00128   tsconfig_parse_buffer(&_handlers, buffer._ptr, buffer._size);
00129   return MakeRv(_config, _errata);
00130 }
00131 
00132 void
00133 Builder::groupOpen(Token const& token) {
00134     _v = _v.makeGroup(_name);
00135     _v.setSource(token._loc._line, token._loc._col);
00136 }
00137 void Builder::groupClose(Token const&) {
00138     _v = _v.getParent();
00139 }
00140 void Builder::groupName(Token const& token) {
00141     _name.set(token._s, token._n);
00142 }
00143 void Builder::listOpen(Token const& token) {
00144     _v = _v.makeList(_name);
00145     _v.setSource(token._loc._line, token._loc._col);
00146 }
00147 void Builder::listClose(Token const&) {
00148     _v = _v.getParent();
00149 }
00150 
00151 void Builder::pathOpen(Token const&) {
00152     _path.reset();
00153     _extent.reset();
00154 }
00155 void Builder::pathTag(Token const& token) {
00156     _path.append(Buffer(token._s, token._n));
00157     if (_extent._ptr) {
00158       _extent._size = token._s - _extent._ptr + token._n;
00159     } else {
00160       _extent.set(token._s, token._n);
00161       _loc = token._loc;
00162     }
00163 }
00164 void Builder::pathIndex(Token const& token){
00165     // We take advantage of the lexer - token will always be a valid
00166     // digit string that is followed by a non-digit or the FLEX
00167     // required double null at the end of the input buffer.
00168     _path.append(Buffer(0, static_cast<size_t>(atol(token._s))));
00169     if (_extent._ptr) _extent._size = token._s - _extent._ptr + token._n;
00170     else _extent.set(token._s, token._n);
00171 }
00172 
00173 void Builder::pathClose(Token const&) {
00174     Rv<Value> cv = _v.makePath(_path, _name);
00175     if (cv.isOK()) {
00176       cv.result().setText(_extent).setSource(_loc._line, _loc._col);
00177       // Terminate path. This will overwrite trailing whitespace or
00178       // the closing angle bracket, both of which are expendable.
00179       _extent._ptr[_extent._size] = 0;
00180     }
00181     _name.reset();
00182     _extent.reset();
00183 }
00184 
00185 void Builder::literalValue(Token const& token) {
00186     Rv<Value> cv;
00187     Buffer text(token._s, token._n);
00188 
00189     // It's just too painful to use these strings with standard
00190     // libraries without nul terminating. For strings we convert the
00191     // trailing quote. For integers we abuse the fact that the parser
00192     // can't reduce using this token before the lexer has read at
00193     // least one char ahead.
00194 
00195     // Note the nul is *not* included in the reported length.
00196 
00197     if (INTEGER == token._type) {
00198         cv = _v.makeInteger(text, _name);
00199         token._s[token._n] = 0;
00200     } else if (STRING == token._type) {
00201         ++text._ptr, text._size -= 2;  // Don't include the quotes.
00202         text._size = unescape_string(text._ptr, text._size);
00203         text._ptr[text._size] = 0; // OK because we have the trailing quote.
00204         cv = _v.makeString(text, _name);
00205     } else {
00206         msg::logf(_errata, msg::WARN, PRE "Unexpected literal type %d.", token._type);
00207     }
00208     if (!cv.isOK()) _errata.pull(cv.errata());
00209     if (cv.result()) cv.result().setSource(token._loc._line, token._loc._col);
00210     _name.set(0,0); // used, so clear it.
00211 }
00212 void Builder::invalidToken(Token const&) { }
00213 
00214 }} // namespace ts::config

Generated by  doxygen 1.7.1