Parser.cpp
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:8k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2003 MySQL AB
  2.    This program is free software; you can redistribute it and/or modify
  3.    it under the terms of the GNU General Public License as published by
  4.    the Free Software Foundation; either version 2 of the License, or
  5.    (at your option) any later version.
  6.    This program is distributed in the hope that it will be useful,
  7.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  8.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  9.    GNU General Public License for more details.
  10.    You should have received a copy of the GNU General Public License
  11.    along with this program; if not, write to the Free Software
  12.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  13. #include <ndb_global.h>
  14. #include "Parser.hpp"
  15. #include <NdbOut.hpp>
  16. #include <Properties.hpp>
  17. #include <Base64.hpp>
  18. #undef DEBUG
  19. #define DEBUG(x) ndbout << x << endl;
  20. static void trim(char * str);
  21. class ParseInputStream : public InputStream {
  22. public:
  23.   ParseInputStream(InputStream & in, bool trim = true, char eofComment = '#');
  24.   
  25.   char* gets(char * buf, int bufLen); 
  26.   void push_back(const char *);
  27. private:
  28.   InputStream & in;
  29.   char * buffer;
  30. };
  31. ParseInputStream::ParseInputStream(InputStream & _in, 
  32.    bool /* unused */, 
  33.    char /* unused */)
  34.   : in(_in){
  35.   buffer = 0;
  36. }
  37. char*
  38. ParseInputStream::gets(char * buf, int bufLen){
  39.   if(buffer != 0){
  40.     strncpy(buf, buffer, bufLen);
  41.     free(buffer);
  42.     buffer = 0;
  43.     return buf;
  44.   }
  45.   char *t = in.gets(buf, bufLen);
  46.   return t;
  47. }
  48. void
  49. ParseInputStream::push_back(const char * str){
  50.   if(buffer != 0)
  51.     abort();
  52.   buffer = strdup(str);
  53. }
  54. ParserImpl::ParserImpl(const DummyRow * rows, InputStream & in,
  55.        bool b_cmd, bool b_empty, bool b_iarg) 
  56.   : m_rows(rows), input(* new ParseInputStream(in))
  57. {
  58.   m_breakOnCmd = b_cmd;
  59.   m_breakOnEmpty = b_empty;
  60.   m_breakOnInvalidArg = b_iarg;
  61. }
  62. ParserImpl::~ParserImpl(){
  63.   delete & input;
  64. }
  65. static
  66. bool
  67. Empty(const char * str){
  68.   if(str == 0)
  69.     return true;
  70.   const int len = strlen(str);
  71.   if(len == 0)
  72.     return false;
  73.   for(int i = 0; i<len; i++)
  74.     if(str[i] != ' ' && str[i] != 't' && str[i] != 'n')
  75.       return false;
  76.   return true;
  77. }
  78. static
  79. bool
  80. Eof(const char * str) { return str == 0;}
  81. static
  82. void
  83. trim(char * str){
  84.   if(str == NULL)
  85.     return;
  86.   int len = strlen(str);
  87.   for(len--; str[len] == 'n' || str[len] == ' ' || str[len] == 't'; len--)
  88.     str[len] = 0;
  89.   
  90.   int pos = 0;
  91.   while(str[pos] == ' ' || str[pos] == 't')
  92.     pos++;
  93.   
  94.   if(str[pos] == '"' && str[len] == '"') {
  95.     pos++;
  96.     str[len] = 0;
  97.     len--;
  98.   }
  99.   
  100.   memmove(str, &str[pos], len - pos + 2);
  101. }
  102. static
  103. bool
  104. split(char * buf, char ** name, char ** value){
  105.   
  106.   * value = strchr(buf, ':');
  107.   if(* value == 0)
  108.     * value = strchr(buf, '=');
  109.   if(* value == 0){
  110.     return false;
  111.   }
  112.   (* value)[0] = 0;
  113.   * value = (* value + 1);
  114.   * name = buf;
  115.   
  116.   trim(* name);
  117.   trim(* value);
  118.   return true;
  119. }
  120. bool
  121. ParserImpl::run(Context * ctx, const class Properties ** pDst,
  122. volatile bool * stop) const
  123. {
  124.   DBUG_ENTER("ParserImpl::run");
  125.   * pDst = 0;
  126.   bool ownStop = false;
  127.   if(stop == 0)
  128.     stop = &ownStop;
  129.   
  130.   ctx->m_aliasUsed.clear();
  131.   
  132.   const unsigned sz = sizeof(ctx->m_tokenBuffer);
  133.   ctx->m_currentToken = input.gets(ctx->m_tokenBuffer, sz);
  134.   if(Eof(ctx->m_currentToken)){
  135.     ctx->m_status = Parser<Dummy>::Eof;
  136.     DBUG_RETURN(false);
  137.   }
  138.   
  139.   if(ctx->m_currentToken[0] == 0){
  140.     ctx->m_status = Parser<Dummy>::NoLine;
  141.     DBUG_RETURN(false);
  142.   }
  143.   
  144.   if(Empty(ctx->m_currentToken)){
  145.     ctx->m_status = Parser<Dummy>::EmptyLine;
  146.     DBUG_RETURN(false);
  147.   }
  148.   trim(ctx->m_currentToken);
  149.   ctx->m_currentCmd = matchCommand(ctx, ctx->m_currentToken, m_rows);
  150.   if(ctx->m_currentCmd == 0){
  151.     ctx->m_status = Parser<Dummy>::UnknownCommand;
  152.     DBUG_RETURN(false);
  153.   }
  154.   
  155.   Properties * p = new Properties();
  156.   
  157.   bool invalidArgument = false;
  158.   ctx->m_currentToken = input.gets(ctx->m_tokenBuffer, sz);
  159.   
  160.   while((! * stop) && 
  161. !Eof(ctx->m_currentToken) && 
  162. !Empty(ctx->m_currentToken)){
  163.     if(ctx->m_currentToken[0] != 0){
  164.       trim(ctx->m_currentToken);
  165.       if(!parseArg(ctx, ctx->m_currentToken, ctx->m_currentCmd + 1, p)){
  166. delete p;
  167. invalidArgument = true;
  168. break;
  169.       }
  170.     }
  171.     ctx->m_currentToken = input.gets(ctx->m_tokenBuffer, sz);
  172.   }
  173.   
  174.   if(invalidArgument){
  175.     char buf[sz];
  176.     char * tmp;
  177.     if(!m_breakOnInvalidArg){
  178.       do {
  179. tmp = input.gets(buf, sz);
  180.       } while((! * stop) && !Eof(tmp) && !Empty(tmp));
  181.     }
  182.     DBUG_RETURN(false);
  183.   }
  184.   
  185.   if(* stop){
  186.     delete p;
  187.     ctx->m_status = Parser<Dummy>::ExternalStop;
  188.     DBUG_RETURN(false);
  189.   }
  190.   
  191.   if(!checkMandatory(ctx, p)){
  192.     ctx->m_status = Parser<Dummy>::MissingMandatoryArgument;
  193.     delete p;
  194.     DBUG_RETURN(false);
  195.   }
  196.   /**
  197.    * Add alias to properties
  198.    */
  199.   for(unsigned i = 0; i<ctx->m_aliasUsed.size(); i++){
  200.     const ParserRow<Dummy> * alias = ctx->m_aliasUsed[i];
  201.     Properties tmp;
  202.     tmp.put("name", alias->name);
  203.     tmp.put("realName", alias->realName);
  204.     p->put("$ALIAS", i, &tmp);
  205.   }    
  206.   p->put("$ALIAS", ctx->m_aliasUsed.size());
  207.   
  208.   ctx->m_status = Parser<Dummy>::Ok;
  209.   * pDst = p;
  210.   DBUG_RETURN(true);
  211. }
  212. const ParserImpl::DummyRow* 
  213. ParserImpl::matchCommand(Context* ctx, const char* buf, const DummyRow rows[]){
  214.   const char * name = buf;
  215.   const DummyRow * tmp = &rows[0];
  216.   while(tmp->name != 0 && name != 0){
  217.     if(strcmp(tmp->name, name) == 0){
  218.       if(tmp->type == DummyRow::Cmd)
  219. return tmp;
  220.       if(tmp->type == DummyRow::CmdAlias){
  221. if(ctx != 0)
  222.   ctx->m_aliasUsed.push_back(tmp);
  223. name = tmp->realName;
  224. tmp = &rows[0];
  225. continue;
  226.       }
  227.     }
  228.     tmp++;
  229.   }
  230.   return 0;
  231. }
  232. const ParserImpl::DummyRow* 
  233. ParserImpl::matchArg(Context* ctx, const char * buf, const DummyRow rows[]){
  234.   const char * name = buf;
  235.   const DummyRow * tmp = &rows[0];
  236.   while(tmp->name != 0){
  237.     const DummyRow::Type t = tmp->type;
  238.     if(t != DummyRow::Arg && t != DummyRow::ArgAlias && t !=DummyRow::CmdAlias)
  239.       break;
  240.     if(t !=DummyRow::CmdAlias && strcmp(tmp->name, name) == 0){
  241.       if(tmp->type == DummyRow::Arg){
  242. return tmp;
  243.       }
  244.       if(tmp->type == DummyRow::ArgAlias){
  245. if(ctx != 0)
  246.   ctx->m_aliasUsed.push_back(tmp);
  247. name = tmp->realName;
  248. tmp = &rows[0];
  249. continue;
  250.       }
  251.     }
  252.     tmp++;
  253.   }
  254.   return 0;
  255. }
  256. bool
  257. ParserImpl::parseArg(Context * ctx,
  258.      char * buf, 
  259.      const DummyRow * rows,
  260.      Properties * p){
  261.   char * name;
  262.   char * value;
  263.   if(!split(buf, &name, &value)){
  264.     ctx->m_status = Parser<Dummy>::InvalidArgumentFormat;
  265.     return false;
  266.   }
  267.   const DummyRow * arg = matchArg(ctx, name, rows);
  268.   if(arg == 0){
  269.     ctx->m_status = Parser<Dummy>::UnknownArgument;
  270.     return false;
  271.   }
  272.   
  273.   switch(arg->argType){
  274.   case DummyRow::String:
  275.     if(p->put(arg->name, value))
  276.       return true;
  277.     break;
  278.   case DummyRow::Int:{
  279.     Uint32 i;
  280.     int c = sscanf(value, "%u", &i);
  281.     if(c != 1){
  282.       ctx->m_status = Parser<Dummy>::TypeMismatch;
  283.       return false;
  284.     }
  285.     if(p->put(arg->name, i))
  286.       return true;
  287.     break;
  288.   }
  289.   case DummyRow::Properties: {
  290.     Properties *sp = new Properties();
  291.     BaseString v(value);
  292.     UtilBuffer b;
  293.     base64_decode(v, b);
  294.     sp->unpack((const Uint32 *)b.get_data(), b.length());
  295.     break;
  296.   }
  297.   default:
  298.     ctx->m_status = Parser<Dummy>::UnknownArgumentType;
  299.     return false;
  300.   }
  301.   if(p->getPropertiesErrno() == E_PROPERTIES_ELEMENT_ALREADY_EXISTS){
  302.     ctx->m_status = Parser<Dummy>::ArgumentGivenTwice;
  303.     return false;
  304.   }
  305.   abort();
  306. }
  307. bool
  308. ParserImpl::checkMandatory(Context* ctx, const Properties* props){
  309.   const DummyRow * tmp = &ctx->m_currentCmd[1];
  310.   while(tmp->name != 0 && tmp->type == DummyRow::Arg){
  311.     if(tmp->argRequired == ParserRow<Dummy>::Mandatory &&
  312.        !props->contains(tmp->name)){
  313.       ctx->m_status = Parser<Dummy>::MissingMandatoryArgument;
  314.       ctx->m_currentArg = tmp;
  315.       return false;
  316.     }
  317.     tmp++;
  318.   }
  319.   return true;
  320. }
  321. template class Vector<const ParserRow<ParserImpl::Dummy>*>;