/* 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 struct 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 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 * m_currentCmd; const ParserRow * m_currentArg; char * m_currentToken; char m_tokenBuffer[512]; Vector *> m_aliasUsed; }; /** * Initialize parser */ Parser(const ParserRow 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 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::Context & ctx, const class Properties& args); const char * description; void *user_value; }; /** * The void* equivalent implementation */ class ParserImpl { public: class Dummy {}; typedef ParserRow DummyRow; typedef Parser::Context Context; 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 inline Parser::Parser(const ParserRow 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 inline Parser::~Parser(){ delete impl; } template inline bool Parser::run(Context & ctx, T & t, volatile bool * stop) const { const Properties * p; DEBUG("Executing Parser::run"); if(impl->run((ParserImpl::Context*)&ctx, &p, stop)){ const ParserRow * cmd = ctx.m_currentCmd; // Cast to correct type if(cmd == 0){ /** * Should happen if run returns true */ abort(); } for(unsigned i = 0; i * 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 inline const Properties * Parser::parse(Context &ctx, T &t) { const Properties * p; volatile bool stop = false; DEBUG("Executing Parser::parse"); if(impl->run((ParserImpl::Context*)&ctx, &p, &stop)){ const ParserRow * cmd = ctx.m_currentCmd; // Cast to correct type if(cmd == 0){ /** * Should happen if run returns true */ abort(); } for(unsigned i = 0; i * 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 inline bool Parser::getBreakOnCommand() const{ return impl->m_breakOnCmd; } template inline void Parser::setBreakOnCommand(bool v){ impl->m_breakOnCmd = v; } template inline bool Parser::getBreakOnEmptyLine() const{ return impl->m_breakOnEmpty; } template inline void Parser::setBreakOnEmptyLine(bool v){ impl->m_breakOnEmpty = v; } template inline bool Parser::getBreakOnInvalidArg() const{ return impl->m_breakOnInvalidArg; } template inline void Parser::setBreakOnInvalidArg(bool v){ impl->m_breakOnInvalidArg = v; } #endif