mySQL 5.0.11 sources for tomato
[tomato.git] / release / src / router / mysql / server-tools / instance-manager / parse.cc
blobe54eb2a00e81ed1af805a37456704fb3a76d0d3f
1 /*
2 Copyright (c) 2004-2007 MySQL AB, 2009 Sun Microsystems, Inc.
3 Use is subject to license terms.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; version 2 of the License.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 #include "parse.h"
20 #include "commands.h"
23 enum Token
25 TOK_CREATE= 0,
26 TOK_DROP,
27 TOK_ERROR, /* Encodes the "ERROR" word, it doesn't indicate error. */
28 TOK_FILES,
29 TOK_FLUSH,
30 TOK_GENERAL,
31 TOK_INSTANCE,
32 TOK_INSTANCES,
33 TOK_LOG,
34 TOK_OPTIONS,
35 TOK_SET,
36 TOK_SLOW,
37 TOK_START,
38 TOK_STATUS,
39 TOK_STOP,
40 TOK_SHOW,
41 TOK_UNSET,
42 TOK_NOT_FOUND, // must be after all tokens
43 TOK_END
47 struct tokens_st
49 uint length;
50 const char *tok_name;
54 static struct tokens_st tokens[]= {
55 {6, "CREATE"},
56 {4, "DROP"},
57 {5, "ERROR"},
58 {5, "FILES"},
59 {5, "FLUSH"},
60 {7, "GENERAL"},
61 {8, "INSTANCE"},
62 {9, "INSTANCES"},
63 {3, "LOG"},
64 {7, "OPTIONS"},
65 {3, "SET"},
66 {4, "SLOW"},
67 {5, "START"},
68 {6, "STATUS"},
69 {4, "STOP"},
70 {4, "SHOW"},
71 {5, "UNSET"}
74 /************************************************************************/
76 Named_value_arr::Named_value_arr() :
77 initialized(FALSE)
82 bool Named_value_arr::init()
84 if (my_init_dynamic_array(&arr, sizeof(Named_value), 0, 32))
85 return TRUE;
87 initialized= TRUE;
89 return FALSE;
93 Named_value_arr::~Named_value_arr()
95 if (!initialized)
96 return;
98 for (int i= 0; i < get_size(); ++i)
99 get_element(i).free();
101 delete_dynamic(&arr);
104 /************************************************************************/
107 Returns token no if word corresponds to some token, otherwise returns
108 TOK_NOT_FOUND
111 inline Token find_token(const char *word, size_t word_len)
113 int i= 0;
116 if (my_strnncoll(default_charset_info, (const uchar *) tokens[i].tok_name,
117 tokens[i].length, (const uchar *) word, word_len) == 0)
118 break;
120 while (++i < TOK_NOT_FOUND);
121 return (Token) i;
125 Token get_token(const char **text, size_t *word_len)
127 get_word(text, word_len);
128 if (*word_len)
129 return find_token(*text, *word_len);
130 return TOK_END;
134 Token shift_token(const char **text, size_t *word_len)
136 Token save= get_token(text, word_len);
137 (*text)+= *word_len;
138 return save;
142 int get_text_id(const char **text, LEX_STRING *token)
144 get_word(text, &token->length);
145 if (token->length == 0)
146 return 1;
147 token->str= (char *) *text;
148 return 0;
152 static bool parse_long(const LEX_STRING *token, long *value)
154 int err_code;
155 char *end_ptr= token->str + token->length;
157 *value= (long)my_strtoll10(token->str, &end_ptr, &err_code);
159 return err_code != 0;
163 bool parse_option_value(const char *text, size_t *text_len, char **value)
165 char beginning_quote;
166 const char *text_start_ptr;
167 char *v;
168 bool escape_mode= FALSE;
170 if (!*text || (*text != '\'' && *text != '"'))
171 return TRUE; /* syntax error: string expected. */
173 beginning_quote= *text;
175 ++text; /* skip the beginning quote. */
177 text_start_ptr= text;
179 if (!(v= Named_value::alloc_str(text)))
180 return TRUE;
182 *value= v;
184 while (TRUE)
186 if (!*text)
188 Named_value::free_str(value);
189 return TRUE; /* syntax error: missing terminating ' character. */
192 if (*text == '\n' || *text == '\r')
194 Named_value::free_str(value);
195 return TRUE; /* syntax error: option value should be a single line. */
198 if (!escape_mode && *text == beginning_quote)
199 break;
201 if (escape_mode)
203 switch (*text)
205 case 'b': /* \b -- backspace */
206 if (v > *value)
207 --v;
208 break;
210 case 't': /* \t -- tab */
211 *v= '\t';
212 ++v;
213 break;
215 case 'n': /* \n -- newline */
216 *v= '\n';
217 ++v;
218 break;
220 case 'r': /* \r -- carriage return */
221 *v= '\r';
222 ++v;
223 break;
225 case '\\': /* \\ -- back slash */
226 *v= '\\';
227 ++v;
228 break;
230 case 's': /* \s -- space */
231 *v= ' ';
232 ++v;
233 break;
235 default: /* Unknown escape sequence. Treat as error. */
236 Named_value::free_str(value);
237 return TRUE;
240 escape_mode= FALSE;
242 else
244 if (*text == '\\')
246 escape_mode= TRUE;
248 else
250 *v= *text;
251 ++v;
255 ++text;
258 *v= 0;
260 /* "2" below stands for beginning and ending quotes. */
261 *text_len= text - text_start_ptr + 2;
263 return FALSE;
267 void skip_spaces(const char **text)
269 while (**text && my_isspace(default_charset_info, **text))
270 ++(*text);
274 Command *parse_command(const char *text)
276 size_t word_len;
277 LEX_STRING instance_name;
278 Command *command= 0;
280 Token tok1= shift_token(&text, &word_len);
282 switch (tok1) {
283 case TOK_START: // fallthrough
284 case TOK_STOP:
285 case TOK_CREATE:
286 case TOK_DROP:
287 if (shift_token(&text, &word_len) != TOK_INSTANCE)
288 goto syntax_error;
289 get_word(&text, &word_len);
290 if (word_len == 0)
291 goto syntax_error;
292 instance_name.str= (char *) text;
293 instance_name.length= word_len;
294 text+= word_len;
296 if (tok1 == TOK_CREATE)
298 Create_instance *cmd= new Create_instance(&instance_name);
300 if (!cmd)
301 return NULL; /* Report ER_OUT_OF_RESOURCES. */
303 if (cmd->init(&text))
305 delete cmd;
306 goto syntax_error;
309 command= cmd;
311 else
313 /* it should be the end of command */
314 get_word(&text, &word_len, NONSPACE);
315 if (word_len)
316 goto syntax_error;
319 switch (tok1) {
320 case TOK_START:
321 command= new Start_instance(&instance_name);
322 break;
323 case TOK_STOP:
324 command= new Stop_instance(&instance_name);
325 break;
326 case TOK_CREATE:
327 ; /* command already initialized. */
328 break;
329 case TOK_DROP:
330 command= new Drop_instance(&instance_name);
331 break;
332 default: /* this is impossible, but nevertheless... */
333 DBUG_ASSERT(0);
335 break;
336 case TOK_FLUSH:
337 if (shift_token(&text, &word_len) != TOK_INSTANCES)
338 goto syntax_error;
340 get_word(&text, &word_len, NONSPACE);
341 if (word_len)
342 goto syntax_error;
344 command= new Flush_instances();
345 break;
346 case TOK_UNSET:
347 case TOK_SET:
349 Abstract_option_cmd *cmd;
351 if (tok1 == TOK_SET)
352 cmd= new Set_option();
353 else
354 cmd= new Unset_option();
356 if (!cmd)
357 return NULL; /* Report ER_OUT_OF_RESOURCES. */
359 if (cmd->init(&text))
361 delete cmd;
362 goto syntax_error;
365 command= cmd;
367 break;
369 case TOK_SHOW:
370 switch (shift_token(&text, &word_len)) {
371 case TOK_INSTANCES:
372 get_word(&text, &word_len, NONSPACE);
373 if (word_len)
374 goto syntax_error;
375 command= new Show_instances();
376 break;
377 case TOK_INSTANCE:
378 switch (Token tok2= shift_token(&text, &word_len)) {
379 case TOK_OPTIONS:
380 case TOK_STATUS:
381 if (get_text_id(&text, &instance_name))
382 goto syntax_error;
383 text+= instance_name.length;
384 /* check that this is the end of the command */
385 get_word(&text, &word_len, NONSPACE);
386 if (word_len)
387 goto syntax_error;
388 if (tok2 == TOK_STATUS)
389 command= new Show_instance_status(&instance_name);
390 else
391 command= new Show_instance_options(&instance_name);
392 break;
393 default:
394 goto syntax_error;
396 break;
397 default:
398 instance_name.str= (char *) text - word_len;
399 instance_name.length= word_len;
400 if (instance_name.length)
402 Log_type log_type;
404 long log_size;
405 LEX_STRING log_size_str;
407 long log_offset= 0;
408 LEX_STRING log_offset_str= { NULL, 0 };
410 switch (shift_token(&text, &word_len)) {
411 case TOK_LOG:
412 switch (Token tok3= shift_token(&text, &word_len)) {
413 case TOK_FILES:
414 get_word(&text, &word_len, NONSPACE);
415 /* check that this is the end of the command */
416 if (word_len)
417 goto syntax_error;
418 command= new Show_instance_log_files(&instance_name);
419 break;
420 case TOK_ERROR:
421 case TOK_GENERAL:
422 case TOK_SLOW:
423 /* define a log type */
424 switch (tok3) {
425 case TOK_ERROR:
426 log_type= IM_LOG_ERROR;
427 break;
428 case TOK_GENERAL:
429 log_type= IM_LOG_GENERAL;
430 break;
431 case TOK_SLOW:
432 log_type= IM_LOG_SLOW;
433 break;
434 default:
435 goto syntax_error;
437 /* get the size of the log we want to retrieve */
438 if (get_text_id(&text, &log_size_str))
439 goto syntax_error;
440 text+= log_size_str.length;
442 /* this parameter is required */
443 if (!log_size_str.length)
444 goto syntax_error;
446 /* the next token should be comma, or nothing */
447 get_word(&text, &word_len);
448 switch (*text) {
449 case ',':
450 text++; /* swallow the comma */
451 /* read the next word */
452 get_word(&text, &word_len);
453 if (!word_len)
454 goto syntax_error;
455 log_offset_str.str= (char *) text;
456 log_offset_str.length= word_len;
457 text+= word_len;
458 get_word(&text, &word_len, NONSPACE);
459 /* check that this is the end of the command */
460 if (word_len)
461 goto syntax_error;
462 break;
463 case '\0':
464 break; /* this is ok */
465 default:
466 goto syntax_error;
469 /* Parse size parameter. */
471 if (parse_long(&log_size_str, &log_size))
472 goto syntax_error;
474 if (log_size <= 0)
475 goto syntax_error;
477 /* Parse offset parameter (if specified). */
479 if (log_offset_str.length)
481 if (parse_long(&log_offset_str, &log_offset))
482 goto syntax_error;
484 if (log_offset <= 0)
485 goto syntax_error;
488 command= new Show_instance_log(&instance_name,
489 log_type, log_size, log_offset);
490 break;
491 default:
492 goto syntax_error;
494 break;
495 default:
496 goto syntax_error;
499 else
500 goto syntax_error;
501 break;
503 break;
504 default:
505 syntax_error:
506 command= new Syntax_error();
509 DBUG_ASSERT(command);
511 return command;