Go to the documentation of this file.00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 # include "TsBuilder.h"
00025 # include "TsErrataUtil.h"
00026 # include "TsConfigLexer.h"
00027 # include "TsConfigGrammar.hpp"
00028 # include <stdlib.h>
00029 
00030 
00031 # define PRE "Configuration Parser: "
00032 
00033 namespace {
00034 
00035 
00036 
00037 size_t unescape_string(char* text, size_t len) {
00038   size_t zret = len;
00039   
00040   char* dst = static_cast<char*>(memchr(text, '\\', len));
00041   if (dst) {
00042     char* limit = text + len;
00043     char* src = dst + 1; 
00044     for ( *dst++ = *src++ ; src < limit ; ++src )
00045       if ('\\' != *src) *dst++ = *src;
00046       else if (++src < limit) *dst++ = *src;
00047       else *dst++ = '\\'; 
00048     zret = dst - text;
00049   }
00050   return zret;
00051 }
00052 } 
00053 
00054 namespace ts { namespace config {
00055 
00056 Builder&
00057 Builder::init() {
00058   
00059   
00060   
00061   
00062 
00063   
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 
00091 
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(); 
00127   _errata.clear(); 
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     
00166     
00167     
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       
00178       
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     
00190     
00191     
00192     
00193     
00194 
00195     
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;  
00202         text._size = unescape_string(text._ptr, text._size);
00203         text._ptr[text._size] = 0; 
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); 
00211 }
00212 void Builder::invalidToken(Token const&) { }
00213 
00214 }}