00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
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 ,
00043 char )
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>*>;