2004-04-14 10:53:21 +02:00
|
|
|
/* 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
|
2006-12-23 20:17:15 +01:00
|
|
|
the Free Software Foundation; version 2 of the License.
|
2004-04-14 10:53:21 +02:00
|
|
|
|
|
|
|
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;
|
2004-11-10 00:13:26 +01:00
|
|
|
template<class T> struct ParserRow;
|
2004-04-14 10:53:21 +02:00
|
|
|
|
|
|
|
//#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
|
|
|
|
*/
|
2006-10-03 18:38:31 +02:00
|
|
|
class Context {
|
|
|
|
public:
|
|
|
|
Context() { m_mutex= NULL; };
|
2004-04-14 10:53:21 +02:00
|
|
|
ParserStatus m_status;
|
|
|
|
const ParserRow<T> * m_currentCmd;
|
|
|
|
const ParserRow<T> * m_currentArg;
|
|
|
|
char * m_currentToken;
|
|
|
|
char m_tokenBuffer[512];
|
2006-10-03 18:38:31 +02:00
|
|
|
NdbMutex *m_mutex;
|
2004-04-14 10:53:21 +02:00
|
|
|
|
|
|
|
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 {
|
2004-11-10 00:13:26 +01:00
|
|
|
public:
|
2004-04-14 10:53:21 +02:00
|
|
|
class Dummy {};
|
|
|
|
typedef ParserRow<Dummy> DummyRow;
|
|
|
|
typedef Parser<Dummy>::Context Context;
|
2004-11-10 00:13:26 +01:00
|
|
|
|
2004-04-14 10:53:21 +02:00
|
|
|
|
|
|
|
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(){
|
2004-06-10 14:01:47 +02:00
|
|
|
delete impl;
|
2004-04-14 10:53:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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){
|
2005-09-12 14:03:23 +02:00
|
|
|
impl->m_breakOnInvalidArg = v;
|
2004-04-14 10:53:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|