mariadb/ndb/include/util/Parser.hpp
tomas@poseidon.ndb.mysql.com d3543b7a6a removed myVector from ndb restore
2004-06-10 12:01:47 +00:00

291 lines
6.6 KiB
C++

/* 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(){
delete impl;
}
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