/* 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; version 2 of the License. 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 */ #include #include "Parser.hpp" #include #include #undef DEBUG #define DEBUG(x) ndbout << x << endl; static void trim(char * str); class ParseInputStream : public InputStream { public: ParseInputStream(InputStream & in, bool trim = true, char eofComment = '#'); char* gets(char * buf, int bufLen); void push_back(const char *); private: InputStream & in; char * buffer; }; ParseInputStream::ParseInputStream(InputStream & _in, bool /* unused */, char /* unused */) : in(_in){ buffer = 0; } char* ParseInputStream::gets(char * buf, int bufLen){ if(buffer != 0){ strncpy(buf, buffer, bufLen); free(buffer); buffer = 0; return buf; } char *t = in.gets(buf, bufLen); return t; } void ParseInputStream::push_back(const char * str){ if(buffer != 0) abort(); buffer = strdup(str); } ParserImpl::ParserImpl(const DummyRow * rows, InputStream & in, bool b_cmd, bool b_empty, bool b_iarg) : m_rows(rows), input(* new ParseInputStream(in)) { m_breakOnCmd = b_cmd; m_breakOnEmpty = b_empty; m_breakOnInvalidArg = b_iarg; } ParserImpl::~ParserImpl(){ delete & input; } static bool Empty(const char * str){ if(str == 0) return true; const int len = strlen(str); if(len == 0) return false; for(int i = 0; im_status = Parser::NoLine; ctx->m_tokenBuffer[0]= '\0'; DBUG_RETURN(false); } if(Empty(ctx->m_currentToken)){ ctx->m_status = Parser::EmptyLine; DBUG_RETURN(false); } trim(ctx->m_currentToken); ctx->m_currentCmd = matchCommand(ctx, ctx->m_currentToken, m_rows); if(ctx->m_currentCmd == 0){ ctx->m_status = Parser::UnknownCommand; DBUG_RETURN(false); } Properties * p = new Properties(); bool invalidArgument = false; ctx->m_currentToken = input.gets(ctx->m_tokenBuffer, sz); while((! * stop) && !Eof(ctx->m_currentToken) && !Empty(ctx->m_currentToken)){ if(ctx->m_currentToken[0] != 0){ trim(ctx->m_currentToken); if(!parseArg(ctx, ctx->m_currentToken, ctx->m_currentCmd + 1, p)){ delete p; invalidArgument = true; break; } } ctx->m_currentToken = input.gets(ctx->m_tokenBuffer, sz); } if(invalidArgument){ char buf[sz]; char * tmp; if(!m_breakOnInvalidArg){ do { tmp = input.gets(buf, sz); } while((! * stop) && !Eof(tmp) && !Empty(tmp)); } DBUG_RETURN(false); } if(* stop){ delete p; ctx->m_status = Parser::ExternalStop; DBUG_RETURN(false); } if(!checkMandatory(ctx, p)){ ctx->m_status = Parser::MissingMandatoryArgument; delete p; DBUG_RETURN(false); } /** * Add alias to properties */ for(unsigned i = 0; im_aliasUsed.size(); i++){ const ParserRow * alias = ctx->m_aliasUsed[i]; Properties tmp; tmp.put("name", alias->name); tmp.put("realName", alias->realName); p->put("$ALIAS", i, &tmp); } p->put("$ALIAS", ctx->m_aliasUsed.size()); ctx->m_status = Parser::Ok; * pDst = p; DBUG_RETURN(true); } const ParserImpl::DummyRow* ParserImpl::matchCommand(Context* ctx, const char* buf, const DummyRow rows[]){ const char * name = buf; const DummyRow * tmp = &rows[0]; while(tmp->name != 0 && name != 0){ if(strcmp(tmp->name, name) == 0){ if(tmp->type == DummyRow::Cmd) return tmp; if(tmp->type == DummyRow::CmdAlias){ if(ctx != 0) ctx->m_aliasUsed.push_back(tmp); name = tmp->realName; tmp = &rows[0]; continue; } } tmp++; } return 0; } const ParserImpl::DummyRow* ParserImpl::matchArg(Context* ctx, const char * buf, const DummyRow rows[]){ const char * name = buf; const DummyRow * tmp = &rows[0]; while(tmp->name != 0){ const DummyRow::Type t = tmp->type; if(t != DummyRow::Arg && t != DummyRow::ArgAlias && t !=DummyRow::CmdAlias) break; if(t !=DummyRow::CmdAlias && strcmp(tmp->name, name) == 0){ if(tmp->type == DummyRow::Arg){ return tmp; } if(tmp->type == DummyRow::ArgAlias){ if(ctx != 0) ctx->m_aliasUsed.push_back(tmp); name = tmp->realName; tmp = &rows[0]; continue; } } tmp++; } return 0; } bool ParserImpl::parseArg(Context * ctx, char * buf, const DummyRow * rows, Properties * p){ char * name; char * value; if(!split(buf, &name, &value)){ ctx->m_status = Parser::InvalidArgumentFormat; return false; } const DummyRow * arg = matchArg(ctx, name, rows); if(arg == 0){ ctx->m_status = Parser::UnknownArgument; return false; } switch(arg->argType){ case DummyRow::String: if(p->put(arg->name, value)) return true; break; case DummyRow::Int:{ Uint32 i; int c = sscanf(value, "%u", &i); if(c != 1){ ctx->m_status = Parser::TypeMismatch; return false; } if(p->put(arg->name, i)) return true; break; } case DummyRow::Properties: { abort(); break; } default: ctx->m_status = Parser::UnknownArgumentType; return false; } if(p->getPropertiesErrno() == E_PROPERTIES_ELEMENT_ALREADY_EXISTS){ ctx->m_status = Parser::ArgumentGivenTwice; return false; } abort(); } bool ParserImpl::checkMandatory(Context* ctx, const Properties* props){ const DummyRow * tmp = &ctx->m_currentCmd[1]; while(tmp->name != 0 && tmp->type == DummyRow::Arg){ if(tmp->argRequired == ParserRow::Mandatory && !props->contains(tmp->name)){ ctx->m_status = Parser::MissingMandatoryArgument; ctx->m_currentArg = tmp; return false; } tmp++; } return true; } template class Vector*>;