~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
ImportĀ upstreamĀ versionĀ 5.1.45

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; version 2 of the License.
 
6
 
 
7
   This program is distributed in the hope that it will be useful,
 
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
10
   GNU General Public License for more details.
 
11
 
 
12
   You should have received a copy of the GNU General Public License
 
13
   along with this program; if not, write to the Free Software
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
15
 
 
16
 
 
17
#include <ndb_global.h>
 
18
 
 
19
#include "Parser.hpp"
 
20
#include <NdbOut.hpp>
 
21
#include <Properties.hpp>
 
22
 
 
23
#undef DEBUG
 
24
#define DEBUG(x) ndbout << x << endl;
 
25
 
 
26
static void trim(char * str);
 
27
 
 
28
class ParseInputStream : public InputStream {
 
29
public:
 
30
  ParseInputStream(InputStream & in, bool trim = true, char eofComment = '#');
 
31
  
 
32
  char* gets(char * buf, int bufLen); 
 
33
  void push_back(const char *);
 
34
  void set_mutex(NdbMutex *m) { in.set_mutex(m); };
 
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
  input.set_mutex(ctx->m_mutex);
 
148
 
 
149
  * pDst = 0;
 
150
  bool ownStop = false;
 
151
  if(stop == 0)
 
152
    stop = &ownStop;
 
153
 
 
154
  ctx->m_aliasUsed.clear();
 
155
 
 
156
  const unsigned sz = sizeof(ctx->m_tokenBuffer);
 
157
  ctx->m_currentToken = input.gets(ctx->m_tokenBuffer, sz);
 
158
  if(Eof(ctx->m_currentToken)){
 
159
    ctx->m_status = Parser<Dummy>::Eof;
 
160
    DBUG_RETURN(false);
 
161
  }
 
162
 
 
163
  int last= strlen(ctx->m_currentToken);
 
164
  if(last>0)
 
165
    last--;
 
166
 
 
167
  if(ctx->m_currentToken[last] !='\n'){
 
168
    ctx->m_status = Parser<Dummy>::NoLine;
 
169
    ctx->m_tokenBuffer[0]= '\0';
 
170
    DBUG_RETURN(false);
 
171
  }
 
172
 
 
173
  if(Empty(ctx->m_currentToken)){
 
174
    ctx->m_status = Parser<Dummy>::EmptyLine;
 
175
    DBUG_RETURN(false);
 
176
  }
 
177
 
 
178
  trim(ctx->m_currentToken);
 
179
  ctx->m_currentCmd = matchCommand(ctx, ctx->m_currentToken, m_rows);
 
180
  if(ctx->m_currentCmd == 0){
 
181
    ctx->m_status = Parser<Dummy>::UnknownCommand;
 
182
    DBUG_RETURN(false);
 
183
  }
 
184
 
 
185
  Properties * p = new Properties();
 
186
 
 
187
  bool invalidArgument = false;
 
188
  ctx->m_currentToken = input.gets(ctx->m_tokenBuffer, sz);
 
189
 
 
190
  while((! * stop) &&
 
191
        !Eof(ctx->m_currentToken) &&
 
192
        !Empty(ctx->m_currentToken)){
 
193
    if(ctx->m_currentToken[0] != 0){
 
194
      trim(ctx->m_currentToken);
 
195
      if(!parseArg(ctx, ctx->m_currentToken, ctx->m_currentCmd + 1, p)){
 
196
        delete p;
 
197
        invalidArgument = true;
 
198
        break;
 
199
      }
 
200
    }
 
201
    ctx->m_currentToken = input.gets(ctx->m_tokenBuffer, sz);
 
202
  }
 
203
 
 
204
  if(invalidArgument){
 
205
    char buf[sz];
 
206
    char * tmp;
 
207
    if(!m_breakOnInvalidArg){
 
208
      do {
 
209
        tmp = input.gets(buf, sz);
 
210
      } while((! * stop) && !Eof(tmp) && !Empty(tmp));
 
211
    }
 
212
    DBUG_RETURN(false);
 
213
  }
 
214
 
 
215
  if(* stop){
 
216
    delete p;
 
217
    ctx->m_status = Parser<Dummy>::ExternalStop;
 
218
    DBUG_RETURN(false);
 
219
  }
 
220
 
 
221
  if(!checkMandatory(ctx, p)){
 
222
    ctx->m_status = Parser<Dummy>::MissingMandatoryArgument;
 
223
    delete p;
 
224
    DBUG_RETURN(false);
 
225
  }
 
226
 
 
227
  /**
 
228
   * Add alias to properties
 
229
   */
 
230
  for(unsigned i = 0; i<ctx->m_aliasUsed.size(); i++){
 
231
    const ParserRow<Dummy> * alias = ctx->m_aliasUsed[i];
 
232
    Properties tmp;
 
233
    tmp.put("name", alias->name);
 
234
    tmp.put("realName", alias->realName);
 
235
    p->put("$ALIAS", i, &tmp);
 
236
  }
 
237
  p->put("$ALIAS", ctx->m_aliasUsed.size());
 
238
 
 
239
  ctx->m_status = Parser<Dummy>::Ok;
 
240
  * pDst = p;
 
241
  DBUG_RETURN(true);
 
242
}
 
243
 
 
244
const ParserImpl::DummyRow* 
 
245
ParserImpl::matchCommand(Context* ctx, const char* buf, const DummyRow rows[]){
 
246
  const char * name = buf;
 
247
  const DummyRow * tmp = &rows[0];
 
248
  while(tmp->name != 0 && name != 0){
 
249
    if(strcmp(tmp->name, name) == 0){
 
250
      if(tmp->type == DummyRow::Cmd)
 
251
        return tmp;
 
252
      if(tmp->type == DummyRow::CmdAlias){
 
253
        if(ctx != 0)
 
254
          ctx->m_aliasUsed.push_back(tmp);
 
255
        name = tmp->realName;
 
256
        tmp = &rows[0];
 
257
        continue;
 
258
      }
 
259
    }
 
260
    tmp++;
 
261
  }
 
262
  return 0;
 
263
}
 
264
 
 
265
const ParserImpl::DummyRow* 
 
266
ParserImpl::matchArg(Context* ctx, const char * buf, const DummyRow rows[]){
 
267
  const char * name = buf;
 
268
  const DummyRow * tmp = &rows[0];
 
269
  while(tmp->name != 0){
 
270
    const DummyRow::Type t = tmp->type;
 
271
    if(t != DummyRow::Arg && t != DummyRow::ArgAlias && t !=DummyRow::CmdAlias)
 
272
      break;
 
273
    if(t !=DummyRow::CmdAlias && strcmp(tmp->name, name) == 0){
 
274
      if(tmp->type == DummyRow::Arg){
 
275
        return tmp;
 
276
      }
 
277
      if(tmp->type == DummyRow::ArgAlias){
 
278
        if(ctx != 0)
 
279
          ctx->m_aliasUsed.push_back(tmp);
 
280
        name = tmp->realName;
 
281
        tmp = &rows[0];
 
282
        continue;
 
283
      }
 
284
    }
 
285
    tmp++;
 
286
  }
 
287
  return 0;
 
288
}
 
289
 
 
290
bool
 
291
ParserImpl::parseArg(Context * ctx,
 
292
                     char * buf, 
 
293
                     const DummyRow * rows,
 
294
                     Properties * p){
 
295
  char * name;
 
296
  char * value;
 
297
  if(!split(buf, &name, &value)){
 
298
    ctx->m_status = Parser<Dummy>::InvalidArgumentFormat;
 
299
    return false;
 
300
  }
 
301
  const DummyRow * arg = matchArg(ctx, name, rows);
 
302
  if(arg == 0){
 
303
    ctx->m_status = Parser<Dummy>::UnknownArgument;
 
304
    return false;
 
305
  }
 
306
  
 
307
  switch(arg->argType){
 
308
  case DummyRow::String:
 
309
    if(p->put(arg->name, value))
 
310
      return true;
 
311
    break;
 
312
  case DummyRow::Int:{
 
313
    Uint32 i;
 
314
    int c = sscanf(value, "%u", &i);
 
315
    if(c != 1){
 
316
      ctx->m_status = Parser<Dummy>::TypeMismatch;
 
317
      return false;
 
318
    }
 
319
    if(p->put(arg->name, i))
 
320
      return true;
 
321
    break;
 
322
  }
 
323
 
 
324
  case DummyRow::Properties: {
 
325
    abort();
 
326
    break;
 
327
  }
 
328
  default:
 
329
    ctx->m_status = Parser<Dummy>::UnknownArgumentType;
 
330
    return false;
 
331
  }
 
332
  if(p->getPropertiesErrno() == E_PROPERTIES_ELEMENT_ALREADY_EXISTS){
 
333
    ctx->m_status = Parser<Dummy>::ArgumentGivenTwice;
 
334
    return false;
 
335
  }
 
336
 
 
337
  abort();
 
338
}
 
339
 
 
340
bool
 
341
ParserImpl::checkMandatory(Context* ctx, const Properties* props){
 
342
  const DummyRow * tmp = &ctx->m_currentCmd[1];
 
343
  while(tmp->name != 0 && tmp->type == DummyRow::Arg){
 
344
    if(tmp->argRequired == ParserRow<Dummy>::Mandatory &&
 
345
       !props->contains(tmp->name)){
 
346
      ctx->m_status = Parser<Dummy>::MissingMandatoryArgument;
 
347
      ctx->m_currentArg = tmp;
 
348
      return false;
 
349
    }
 
350
    tmp++;
 
351
  }
 
352
  return true;
 
353
}
 
354
 
 
355
template class Vector<const ParserRow<ParserImpl::Dummy>*>;