summaryrefslogtreecommitdiff
path: root/ndb/include/util/Parser.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'ndb/include/util/Parser.hpp')
-rw-r--r--ndb/include/util/Parser.hpp290
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