Parser.cpp

Go to the documentation of this file.
00001 /* Copyright (C) 2003 MySQL AB
00002 
00003    This program is free software; you can redistribute it and/or modify
00004    it under the terms of the GNU General Public License as published by
00005    the Free Software Foundation; either version 2 of the License, or
00006    (at your option) any later version.
00007 
00008    This program is distributed in the hope that it will be useful,
00009    but WITHOUT ANY WARRANTY; without even the implied warranty of
00010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011    GNU General Public License for more details.
00012 
00013    You should have received a copy of the GNU General Public License
00014    along with this program; if not, write to the Free Software
00015    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
00016 
00017 
00018 #include <ndb_global.h>
00019 
00020 #include "Parser.hpp"
00021 #include <NdbOut.hpp>
00022 #include <Properties.hpp>
00023 #include <Base64.hpp>
00024 
00025 #undef DEBUG
00026 #define DEBUG(x) ndbout << x << endl;
00027 
00028 static void trim(char * str);
00029 
00030 class ParseInputStream : public InputStream {
00031 public:
00032   ParseInputStream(InputStream & in, bool trim = true, char eofComment = '#');
00033   
00034   char* gets(char * buf, int bufLen); 
00035   void push_back(const char *);
00036 private:
00037   InputStream & in;
00038   char * buffer;
00039 };
00040 
00041 ParseInputStream::ParseInputStream(InputStream & _in, 
00042                                    bool /* unused */, 
00043                                    char /* unused */)
00044   : in(_in){
00045   buffer = 0;
00046 }
00047 
00048 char*
00049 ParseInputStream::gets(char * buf, int bufLen){
00050   if(buffer != 0){
00051     strncpy(buf, buffer, bufLen);
00052     free(buffer);
00053     buffer = 0;
00054     return buf;
00055   }
00056   char *t = in.gets(buf, bufLen);
00057   return t;
00058 }
00059 
00060 void
00061 ParseInputStream::push_back(const char * str){
00062   if(buffer != 0)
00063     abort();
00064   buffer = strdup(str);
00065 }
00066 
00067 ParserImpl::ParserImpl(const DummyRow * rows, InputStream & in,
00068                        bool b_cmd, bool b_empty, bool b_iarg) 
00069   : m_rows(rows), input(* new ParseInputStream(in))
00070 {
00071   m_breakOnCmd = b_cmd;
00072   m_breakOnEmpty = b_empty;
00073   m_breakOnInvalidArg = b_iarg;
00074 }
00075 
00076 ParserImpl::~ParserImpl(){
00077   delete & input;
00078 }
00079 
00080 static
00081 bool
00082 Empty(const char * str){
00083   if(str == 0)
00084     return true;
00085   const int len = strlen(str);
00086   if(len == 0)
00087     return false;
00088   for(int i = 0; i<len; i++)
00089     if(str[i] != ' ' && str[i] != '\t' && str[i] != '\n')
00090       return false;
00091   return true;
00092 }
00093 
00094 static
00095 bool
00096 Eof(const char * str) { return str == 0;}
00097 
00098 static
00099 void
00100 trim(char * str){
00101   if(str == NULL)
00102     return;
00103   int len = strlen(str);
00104   for(len--; str[len] == '\n' || str[len] == ' ' || str[len] == '\t'; len--)
00105     str[len] = 0;
00106   
00107   int pos = 0;
00108   while(str[pos] == ' ' || str[pos] == '\t')
00109     pos++;
00110   
00111   if(str[pos] == '\"' && str[len] == '\"') {
00112     pos++;
00113     str[len] = 0;
00114     len--;
00115   }
00116   
00117   memmove(str, &str[pos], len - pos + 2);
00118 }
00119 
00120 static
00121 bool
00122 split(char * buf, char ** name, char ** value){
00123   
00124   * value = strchr(buf, ':');
00125   if(* value == 0)
00126     * value = strchr(buf, '=');
00127 
00128 
00129   if(* value == 0){
00130     return false;
00131   }
00132   (* value)[0] = 0;
00133   * value = (* value + 1);
00134   * name = buf;
00135   
00136   trim(* name);
00137   trim(* value);
00138 
00139   return true;
00140 }
00141 
00142 bool
00143 ParserImpl::run(Context * ctx, const class Properties ** pDst,
00144                 volatile bool * stop) const {
00145   * pDst = 0;
00146   bool ownStop = false;
00147   if(stop == 0)
00148     stop = &ownStop;
00149   
00150   ctx->m_aliasUsed.clear();
00151   
00152   const unsigned sz = sizeof(ctx->m_tokenBuffer);
00153   ctx->m_currentToken = input.gets(ctx->m_tokenBuffer, sz);
00154   if(Eof(ctx->m_currentToken)){
00155     ctx->m_status = Parser<Dummy>::Eof;
00156     return false;
00157   }
00158   
00159   if(ctx->m_currentToken[0] == 0){
00160     ctx->m_status = Parser<Dummy>::NoLine;
00161     return false;
00162   }
00163   
00164   if(Empty(ctx->m_currentToken)){
00165     ctx->m_status = Parser<Dummy>::EmptyLine;
00166     return false;
00167   }
00168 
00169   trim(ctx->m_currentToken);
00170   ctx->m_currentCmd = matchCommand(ctx, ctx->m_currentToken, m_rows);
00171   if(ctx->m_currentCmd == 0){
00172     ctx->m_status = Parser<Dummy>::UnknownCommand;
00173     return false;
00174   }
00175   
00176   Properties * p = new Properties();
00177   
00178   bool invalidArgument = false;
00179   ctx->m_currentToken = input.gets(ctx->m_tokenBuffer, sz);
00180   
00181   while((! * stop) && 
00182         !Eof(ctx->m_currentToken) && 
00183         !Empty(ctx->m_currentToken)){
00184     if(ctx->m_currentToken[0] != 0){
00185       trim(ctx->m_currentToken);
00186       if(!parseArg(ctx, ctx->m_currentToken, ctx->m_currentCmd + 1, p)){
00187         delete p;
00188         invalidArgument = true;
00189         break;
00190       }
00191     }
00192     ctx->m_currentToken = input.gets(ctx->m_tokenBuffer, sz);
00193   }
00194   
00195   if(invalidArgument){
00196     char buf[sz];
00197     char * tmp;
00198     if(!m_breakOnInvalidArg){
00199       do {
00200         tmp = input.gets(buf, sz);
00201       } while((! * stop) && !Eof(tmp) && !Empty(tmp));
00202     }
00203     return false;
00204   }
00205   
00206   if(* stop){
00207     delete p;
00208     ctx->m_status = Parser<Dummy>::ExternalStop;
00209     return false;
00210   }
00211   
00212   if(!checkMandatory(ctx, p)){
00213     ctx->m_status = Parser<Dummy>::MissingMandatoryArgument;
00214     delete p;
00215     return false;
00216   }
00217 
00221   for(unsigned i = 0; i<ctx->m_aliasUsed.size(); i++){
00222     const ParserRow<Dummy> * alias = ctx->m_aliasUsed[i];
00223     Properties tmp;
00224     tmp.put("name", alias->name);
00225     tmp.put("realName", alias->realName);
00226     p->put("$ALIAS", i, &tmp);
00227   }    
00228   p->put("$ALIAS", ctx->m_aliasUsed.size());
00229   
00230   ctx->m_status = Parser<Dummy>::Ok;
00231   * pDst = p;
00232   return true;
00233 }
00234 
00235 const ParserImpl::DummyRow* 
00236 ParserImpl::matchCommand(Context* ctx, const char* buf, const DummyRow rows[]){
00237   const char * name = buf;
00238   const DummyRow * tmp = &rows[0];
00239   while(tmp->name != 0 && name != 0){
00240     if(strcmp(tmp->name, name) == 0){
00241       if(tmp->type == DummyRow::Cmd)
00242         return tmp;
00243       if(tmp->type == DummyRow::CmdAlias){
00244         if(ctx != 0)
00245           ctx->m_aliasUsed.push_back(tmp);
00246         name = tmp->realName;
00247         tmp = &rows[0];
00248         continue;
00249       }
00250     }
00251     tmp++;
00252   }
00253   return 0;
00254 }
00255 
00256 const ParserImpl::DummyRow* 
00257 ParserImpl::matchArg(Context* ctx, const char * buf, const DummyRow rows[]){
00258   const char * name = buf;
00259   const DummyRow * tmp = &rows[0];
00260   while(tmp->name != 0){
00261     const DummyRow::Type t = tmp->type;
00262     if(t != DummyRow::Arg && t != DummyRow::ArgAlias && t !=DummyRow::CmdAlias)
00263       break;
00264     if(t !=DummyRow::CmdAlias && strcmp(tmp->name, name) == 0){
00265       if(tmp->type == DummyRow::Arg){
00266         return tmp;
00267       }
00268       if(tmp->type == DummyRow::ArgAlias){
00269         if(ctx != 0)
00270           ctx->m_aliasUsed.push_back(tmp);
00271         name = tmp->realName;
00272         tmp = &rows[0];
00273         continue;
00274       }
00275     }
00276     tmp++;
00277   }
00278   return 0;
00279 }
00280 
00281 bool
00282 ParserImpl::parseArg(Context * ctx,
00283                      char * buf, 
00284                      const DummyRow * rows,
00285                      Properties * p){
00286   char * name;
00287   char * value;
00288   if(!split(buf, &name, &value)){
00289     ctx->m_status = Parser<Dummy>::InvalidArgumentFormat;
00290     return false;
00291   }
00292   const DummyRow * arg = matchArg(ctx, name, rows);
00293   if(arg == 0){
00294     ctx->m_status = Parser<Dummy>::UnknownArgument;
00295     return false;
00296   }
00297   
00298   switch(arg->argType){
00299   case DummyRow::String:
00300     if(p->put(arg->name, value))
00301       return true;
00302     break;
00303   case DummyRow::Int:{
00304     Uint32 i;
00305     int c = sscanf(value, "%u", &i);
00306     if(c != 1){
00307       ctx->m_status = Parser<Dummy>::TypeMismatch;
00308       return false;
00309     }
00310     if(p->put(arg->name, i))
00311       return true;
00312     break;
00313   }
00314 
00315   case DummyRow::Properties: {
00316     Properties *sp = new Properties();
00317     BaseString v(value);
00318     UtilBuffer b;
00319     base64_decode(v, b);
00320     sp->unpack((const Uint32 *)b.get_data(), b.length());
00321     break;
00322   }
00323   default:
00324     ctx->m_status = Parser<Dummy>::UnknownArgumentType;
00325     return false;
00326   }
00327   if(p->getPropertiesErrno() == E_PROPERTIES_ELEMENT_ALREADY_EXISTS){
00328     ctx->m_status = Parser<Dummy>::ArgumentGivenTwice;
00329     return false;
00330   }
00331 
00332   abort();
00333 }
00334 
00335 bool
00336 ParserImpl::checkMandatory(Context* ctx, const Properties* props){
00337   const DummyRow * tmp = &ctx->m_currentCmd[1];
00338   while(tmp->name != 0 && tmp->type == DummyRow::Arg){
00339     if(tmp->argRequired == ParserRow<Dummy>::Mandatory &&
00340        !props->contains(tmp->name)){
00341       ctx->m_status = Parser<Dummy>::MissingMandatoryArgument;
00342       ctx->m_currentArg = tmp;
00343       return false;
00344     }
00345     tmp++;
00346   }
00347   return true;
00348 }
00349 
00350 template class Vector<const ParserRow<ParserImpl::Dummy>*>;

Generated on Wed Jul 20 21:05:12 2005 for MySQL 5.0.9 Beta by  doxygen 1.4.3