summaryrefslogtreecommitdiff
path: root/storage/ndb/src/common/util/Parser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'storage/ndb/src/common/util/Parser.cpp')
-rw-r--r--storage/ndb/src/common/util/Parser.cpp350
1 files changed, 350 insertions, 0 deletions
diff --git a/storage/ndb/src/common/util/Parser.cpp b/storage/ndb/src/common/util/Parser.cpp
new file mode 100644
index 00000000000..dea128ccf66
--- /dev/null
+++ b/storage/ndb/src/common/util/Parser.cpp
@@ -0,0 +1,350 @@
+/* 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 */
+
+
+#include <ndb_global.h>
+
+#include "Parser.hpp"
+#include <NdbOut.hpp>
+#include <Properties.hpp>
+#include <Base64.hpp>
+
+#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; i<len; i++)
+ if(str[i] != ' ' && str[i] != '\t' && str[i] != '\n')
+ return false;
+ return true;
+}
+
+static
+bool
+Eof(const char * str) { return str == 0;}
+
+static
+void
+trim(char * str){
+ if(str == NULL)
+ return;
+ int len = strlen(str);
+ for(len--; str[len] == '\n' || str[len] == ' ' || str[len] == '\t'; len--)
+ str[len] = 0;
+
+ int pos = 0;
+ while(str[pos] == ' ' || str[pos] == '\t')
+ pos++;
+
+ if(str[pos] == '\"' && str[len] == '\"') {
+ pos++;
+ str[len] = 0;
+ len--;
+ }
+
+ memmove(str, &str[pos], len - pos + 2);
+}
+
+static
+bool
+split(char * buf, char ** name, char ** value){
+
+ * value = strchr(buf, ':');
+ if(* value == 0)
+ * value = strchr(buf, '=');
+
+
+ if(* value == 0){
+ return false;
+ }
+ (* value)[0] = 0;
+ * value = (* value + 1);
+ * name = buf;
+
+ trim(* name);
+ trim(* value);
+
+ return true;
+}
+
+bool
+ParserImpl::run(Context * ctx, const class Properties ** pDst,
+ volatile bool * stop) const {
+ * pDst = 0;
+ bool ownStop = false;
+ if(stop == 0)
+ stop = &ownStop;
+
+ ctx->m_aliasUsed.clear();
+
+ const unsigned sz = sizeof(ctx->m_tokenBuffer);
+ ctx->m_currentToken = input.gets(ctx->m_tokenBuffer, sz);
+ if(Eof(ctx->m_currentToken)){
+ ctx->m_status = Parser<Dummy>::Eof;
+ return false;
+ }
+
+ if(ctx->m_currentToken[0] == 0){
+ ctx->m_status = Parser<Dummy>::NoLine;
+ return false;
+ }
+
+ if(Empty(ctx->m_currentToken)){
+ ctx->m_status = Parser<Dummy>::EmptyLine;
+ 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<Dummy>::UnknownCommand;
+ 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));
+ }
+ return false;
+ }
+
+ if(* stop){
+ delete p;
+ ctx->m_status = Parser<Dummy>::ExternalStop;
+ return false;
+ }
+
+ if(!checkMandatory(ctx, p)){
+ ctx->m_status = Parser<Dummy>::MissingMandatoryArgument;
+ delete p;
+ return false;
+ }
+
+ /**
+ * Add alias to properties
+ */
+ for(unsigned i = 0; i<ctx->m_aliasUsed.size(); i++){
+ const ParserRow<Dummy> * 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<Dummy>::Ok;
+ * pDst = p;
+ 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<Dummy>::InvalidArgumentFormat;
+ return false;
+ }
+ const DummyRow * arg = matchArg(ctx, name, rows);
+ if(arg == 0){
+ ctx->m_status = Parser<Dummy>::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<Dummy>::TypeMismatch;
+ return false;
+ }
+ if(p->put(arg->name, i))
+ return true;
+ break;
+ }
+
+ case DummyRow::Properties: {
+ Properties *sp = new Properties();
+ BaseString v(value);
+ UtilBuffer b;
+ base64_decode(v, b);
+ sp->unpack((const Uint32 *)b.get_data(), b.length());
+ break;
+ }
+ default:
+ ctx->m_status = Parser<Dummy>::UnknownArgumentType;
+ return false;
+ }
+ if(p->getPropertiesErrno() == E_PROPERTIES_ELEMENT_ALREADY_EXISTS){
+ ctx->m_status = Parser<Dummy>::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<Dummy>::Mandatory &&
+ !props->contains(tmp->name)){
+ ctx->m_status = Parser<Dummy>::MissingMandatoryArgument;
+ ctx->m_currentArg = tmp;
+ return false;
+ }
+ tmp++;
+ }
+ return true;
+}
+
+template class Vector<const ParserRow<ParserImpl::Dummy>*>;