diff options
Diffstat (limited to 'ndb/include/util/Parser.hpp')
-rw-r--r-- | ndb/include/util/Parser.hpp | 290 |
1 files changed, 290 insertions, 0 deletions
diff --git a/ndb/include/util/Parser.hpp b/ndb/include/util/Parser.hpp new file mode 100644 index 00000000000..9c2f02b6024 --- /dev/null +++ b/ndb/include/util/Parser.hpp @@ -0,0 +1,290 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef CPCD_PARSER_HPP +#define CPCD_PARSER_HPP + +#include "Vector.hpp" +#include "Properties.hpp" +#include "InputStream.hpp" +#include "NdbOut.hpp" + +class ParserImpl; +template<class T> class ParserRow; + +//#define PARSER_DEBUG +#ifdef PARSER_DEBUG +#define DEBUG(x) \ + ndbout_c("%s:%d:%s", __FILE__, __LINE__, x); +#else +#define DEBUG(x) +#endif + +/** + * A generic parser + */ +template<class T> +class Parser { +public: + /** + * Status for parser + */ + enum ParserStatus { + Ok = 0, + Eof = 1, + NoLine = 2, + EmptyLine = 3, + UnknownCommand = 4, + UnknownArgument = 5, + TypeMismatch = 6, + InvalidArgumentFormat = 7, + UnknownArgumentType = 8, + CommandWithoutFunction = 9, + ArgumentGivenTwice = 10, + ExternalStop = 11, + MissingMandatoryArgument = 12 + }; + + /** + * Context for parse + */ + struct Context { + ParserStatus m_status; + const ParserRow<T> * m_currentCmd; + const ParserRow<T> * m_currentArg; + char * m_currentToken; + char m_tokenBuffer[512]; + + Vector<const ParserRow<T> *> m_aliasUsed; + }; + + /** + * Initialize parser + */ + Parser(const ParserRow<T> rows[], class InputStream & in = Stdin, + bool breakOnCommand = false, + bool breakOnEmptyLine = true, + bool breakOnInvalidArg = false); + ~Parser(); + + /** + * Run parser + */ + bool run(Context &, T &, volatile bool * stop = 0) const; + + /** + * Parse only one entry and return Properties object representing + * the message + */ + const Properties *parse(Context &, T &); + + bool getBreakOnCommand() const; + void setBreakOnCommand(bool v); + + bool getBreakOnEmptyLine() const; + void setBreakOnEmptyLine(bool v); + + bool getBreakOnInvalidArg() const; + void setBreakOnInvalidArg(bool v); + +private: + ParserImpl * impl; +}; + +template<class T> +struct ParserRow { +public: + enum Type { Cmd, Arg, CmdAlias, ArgAlias }; + enum ArgType { String, Int, Properties }; + enum ArgRequired { Mandatory, Optional }; + enum ArgMinMax { CheckMinMax, IgnoreMinMax }; + + const char * name; + const char * realName; + Type type; + ArgType argType; + ArgRequired argRequired; + ArgMinMax argMinMax; + int minVal; + int maxVal; + void (T::* function)(typename Parser<T>::Context & ctx, + const class Properties& args); + const char * description; + void *user_value; +}; + +/** + * The void* equivalent implementation + */ +class ParserImpl { + class Dummy {}; + typedef ParserRow<Dummy> DummyRow; + typedef Parser<Dummy>::Context Context; + template<class T> friend class Parser; +private: + + ParserImpl(const DummyRow rows[], class InputStream & in, + bool b_cmd, bool b_empty, bool b_iarg); + ~ParserImpl(); + + bool run(Context *ctx, const class Properties **, volatile bool *) const ; + + static const DummyRow* matchCommand(Context*, const char*, const DummyRow*); + static const DummyRow* matchArg(Context*, const char *, const DummyRow *); + static bool parseArg(Context*, char*, const DummyRow*, Properties*); + static bool checkMandatory(Context*, const Properties*); +private: + const DummyRow * const m_rows; + class ParseInputStream & input; + bool m_breakOnEmpty; + bool m_breakOnCmd; + bool m_breakOnInvalidArg; +}; + +template<class T> +inline +Parser<T>::Parser(const ParserRow<T> rows[], class InputStream & in, + bool b_cmd, bool b_empty, bool b_iarg){ + impl = new ParserImpl((ParserImpl::DummyRow *)rows, in, + b_cmd, b_empty, b_iarg); +} + +template<class T> +inline +Parser<T>::~Parser(){ +} + +template<class T> +inline +bool +Parser<T>::run(Context & ctx, T & t, volatile bool * stop) const { + const Properties * p; + DEBUG("Executing Parser<T>::run"); + if(impl->run((ParserImpl::Context*)&ctx, &p, stop)){ + const ParserRow<T> * cmd = ctx.m_currentCmd; // Cast to correct type + if(cmd == 0){ + /** + * Should happen if run returns true + */ + abort(); + } + + for(unsigned i = 0; i<ctx.m_aliasUsed.size(); i++){ + const ParserRow<T> * alias = ctx.m_aliasUsed[i]; + if(alias->function != 0){ + /** + * Report alias usage with callback (if specified by user) + */ + DEBUG("Alias usage with callback"); + (t.* alias->function)(ctx, * p); + } + } + + if(cmd->function == 0){ + ctx.m_status = CommandWithoutFunction; + DEBUG("CommandWithoutFunction"); + delete p; + return false; + } + (t.* cmd->function)(ctx, * p); // Call the function + delete p; + return true; + } + DEBUG(""); + return false; +} + +template<class T> +inline +const Properties * +Parser<T>::parse(Context &ctx, T &t) { + const Properties * p; + volatile bool stop = false; + DEBUG("Executing Parser<T>::parse"); + + if(impl->run((ParserImpl::Context*)&ctx, &p, &stop)){ + const ParserRow<T> * cmd = ctx.m_currentCmd; // Cast to correct type + if(cmd == 0){ + /** + * Should happen if run returns true + */ + abort(); + } + + for(unsigned i = 0; i<ctx.m_aliasUsed.size(); i++){ + const ParserRow<T> * alias = ctx.m_aliasUsed[i]; + if(alias->function != 0){ + /** + * Report alias usage with callback (if specified by user) + */ + DEBUG("Alias usage with callback"); + (t.* alias->function)(ctx, * p); + } + } + + if(cmd->function == 0){ + DEBUG("CommandWithoutFunction"); + ctx.m_status = CommandWithoutFunction; + return p; + } + return p; + } + DEBUG(""); + return NULL; +} + +template<class T> +inline +bool +Parser<T>::getBreakOnCommand() const{ + return impl->m_breakOnCmd; +} + +template<class T> +inline +void +Parser<T>::setBreakOnCommand(bool v){ + impl->m_breakOnCmd = v; +} + +template<class T> +inline +bool +Parser<T>::getBreakOnEmptyLine() const{ + return impl->m_breakOnEmpty; +} +template<class T> +inline +void +Parser<T>::setBreakOnEmptyLine(bool v){ + impl->m_breakOnEmpty = v; +} + +template<class T> +inline +bool +Parser<T>::getBreakOnInvalidArg() const{ + return impl->m_breakOnInvalidArg; +} + +template<class T> +inline +void +Parser<T>::setBreakOnInvalidArg(bool v){ + impl->m_breakOnInvalidArg; +} + +#endif |