~vlad-lesin/percona-server/mysql-5.0.33-original

« back to all changes in this revision

Viewing changes to ndb/src/common/util/Parser.cpp

  • Committer: Vlad Lesin
  • Date: 2012-07-31 09:21:34 UTC
  • Revision ID: vladislav.lesin@percona.com-20120731092134-zfodx022b7992wsi
VirginĀ 5.0.33

Show diffs side-by-side

added added

removed removed

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