Merge branch 'develop' into MXS-329-develop-20151111
This commit is contained in:
@ -780,7 +780,7 @@ maxinfo_add_mysql_user(SERVICE *service) {
|
||||
"maxinfo: create hex_sha1_sha1_password failed for service user %s",
|
||||
service_user)));
|
||||
users_free(service->users);
|
||||
|
||||
service->users = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,12 @@ static void exec_select(DCB *dcb, MAXINFO_TREE *tree);
|
||||
static void exec_show_variables(DCB *dcb, MAXINFO_TREE *filter);
|
||||
static void exec_show_status(DCB *dcb, MAXINFO_TREE *filter);
|
||||
static int maxinfo_pattern_match(char *pattern, char *str);
|
||||
|
||||
static void exec_flush(DCB *dcb, MAXINFO_TREE *tree);
|
||||
static void exec_set(DCB *dcb, MAXINFO_TREE *tree);
|
||||
static void exec_clear(DCB *dcb, MAXINFO_TREE *tree);
|
||||
static void exec_shutdown(DCB *dcb, MAXINFO_TREE *tree);
|
||||
static void exec_restart(DCB *dcb, MAXINFO_TREE *tree);
|
||||
void maxinfo_send_ok(DCB *dcb);
|
||||
/**
|
||||
* Execute a parse tree and return the result set or runtime error
|
||||
*
|
||||
@ -72,6 +77,23 @@ maxinfo_execute(DCB *dcb, MAXINFO_TREE *tree)
|
||||
case MAXOP_SELECT:
|
||||
exec_select(dcb, tree);
|
||||
break;
|
||||
|
||||
case MAXOP_FLUSH:
|
||||
exec_flush(dcb, tree);
|
||||
break;
|
||||
case MAXOP_SET:
|
||||
exec_set(dcb, tree);
|
||||
break;
|
||||
case MAXOP_CLEAR:
|
||||
exec_clear(dcb, tree);
|
||||
break;
|
||||
case MAXOP_SHUTDOWN:
|
||||
exec_shutdown(dcb, tree);
|
||||
break;
|
||||
case MAXOP_RESTART:
|
||||
exec_restart(dcb, tree);
|
||||
break;
|
||||
|
||||
case MAXOP_TABLE:
|
||||
case MAXOP_COLUMNS:
|
||||
case MAXOP_LITERAL:
|
||||
@ -274,6 +296,448 @@ char errmsg[120];
|
||||
LOGIF(LM, (skygw_log_write(LOGFILE_MESSAGE, errmsg)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush all logs to disk and rotate them.
|
||||
* @param dcb The DCB that connects to the client
|
||||
* @param tree The parse tree for the query
|
||||
*/
|
||||
void exec_flush_logs(DCB *dcb, MAXINFO_TREE *tree)
|
||||
{
|
||||
mxs_log_rotate();
|
||||
maxinfo_send_ok(dcb);
|
||||
}
|
||||
|
||||
/**
|
||||
* The table of flush commands that are supported
|
||||
*/
|
||||
static struct
|
||||
{
|
||||
char *name;
|
||||
void (*func)(DCB *, MAXINFO_TREE *);
|
||||
} flush_commands[] = {
|
||||
{ "logs", exec_flush_logs},
|
||||
{ NULL, NULL}
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute a flush command parse tree and return the result set or runtime error
|
||||
*
|
||||
* @param dcb The DCB that connects to the client
|
||||
* @param tree The parse tree for the query
|
||||
*/
|
||||
static void
|
||||
exec_flush(DCB *dcb, MAXINFO_TREE *tree)
|
||||
{
|
||||
int i;
|
||||
char errmsg[120];
|
||||
|
||||
for (i = 0; flush_commands[i].name; i++)
|
||||
{
|
||||
if (strcasecmp(flush_commands[i].name, tree->value) == 0)
|
||||
{
|
||||
(*flush_commands[i].func)(dcb, tree->right);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (strlen(tree->value) > 80) // Prevent buffer overrun
|
||||
{
|
||||
tree->value[80] = 0;
|
||||
}
|
||||
sprintf(errmsg, "Unsupported flush command '%s'", tree->value);
|
||||
maxinfo_send_error(dcb, 0, errmsg);
|
||||
skygw_log_write(LE, errmsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the server status.
|
||||
* @param dcb Client DCB
|
||||
* @param tree Parse tree
|
||||
*/
|
||||
void exec_set_server(DCB *dcb, MAXINFO_TREE *tree)
|
||||
{
|
||||
SERVER* server = server_find_by_unique_name(tree->value);
|
||||
char errmsg[120];
|
||||
|
||||
if (server)
|
||||
{
|
||||
int status = server_map_status(tree->right->value);
|
||||
if (status != 0)
|
||||
{
|
||||
server_set_status(server, status);
|
||||
maxinfo_send_ok(dcb);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strlen(tree->right->value) > 80) // Prevent buffer overrun
|
||||
{
|
||||
tree->right->value[80] = 0;
|
||||
}
|
||||
sprintf(errmsg, "Invalid argument '%s'", tree->right->value);
|
||||
maxinfo_send_error(dcb, 0, errmsg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strlen(tree->value) > 80) // Prevent buffer overrun
|
||||
{
|
||||
tree->value[80] = 0;
|
||||
}
|
||||
sprintf(errmsg, "Invalid argument '%s'", tree->value);
|
||||
maxinfo_send_error(dcb, 0, errmsg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The table of set commands that are supported
|
||||
*/
|
||||
static struct
|
||||
{
|
||||
char *name;
|
||||
void (*func)(DCB *, MAXINFO_TREE *);
|
||||
} set_commands[] = {
|
||||
{ "server", exec_set_server},
|
||||
{ NULL, NULL}
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute a set command parse tree and return the result set or runtime error
|
||||
*
|
||||
* @param dcb The DCB that connects to the client
|
||||
* @param tree The parse tree for the query
|
||||
*/
|
||||
static void
|
||||
exec_set(DCB *dcb, MAXINFO_TREE *tree)
|
||||
{
|
||||
int i;
|
||||
char errmsg[120];
|
||||
|
||||
for (i = 0; set_commands[i].name; i++)
|
||||
{
|
||||
if (strcasecmp(set_commands[i].name, tree->value) == 0)
|
||||
{
|
||||
(*set_commands[i].func)(dcb, tree->right);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (strlen(tree->value) > 80) // Prevent buffer overrun
|
||||
{
|
||||
tree->value[80] = 0;
|
||||
}
|
||||
sprintf(errmsg, "Unsupported set command '%s'", tree->value);
|
||||
maxinfo_send_error(dcb, 0, errmsg);
|
||||
skygw_log_write(LE, errmsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the server status.
|
||||
* @param dcb Client DCB
|
||||
* @param tree Parse tree
|
||||
*/
|
||||
void exec_clear_server(DCB *dcb, MAXINFO_TREE *tree)
|
||||
{
|
||||
SERVER* server = server_find_by_unique_name(tree->value);
|
||||
char errmsg[120];
|
||||
|
||||
if (server)
|
||||
{
|
||||
int status = server_map_status(tree->right->value);
|
||||
if (status != 0)
|
||||
{
|
||||
server_clear_status(server, status);
|
||||
maxinfo_send_ok(dcb);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strlen(tree->right->value) > 80) // Prevent buffer overrun
|
||||
{
|
||||
tree->right->value[80] = 0;
|
||||
}
|
||||
sprintf(errmsg, "Invalid argument '%s'", tree->right->value);
|
||||
maxinfo_send_error(dcb, 0, errmsg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strlen(tree->value) > 80) // Prevent buffer overrun
|
||||
{
|
||||
tree->value[80] = 0;
|
||||
}
|
||||
sprintf(errmsg, "Invalid argument '%s'", tree->value);
|
||||
maxinfo_send_error(dcb, 0, errmsg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The table of clear commands that are supported
|
||||
*/
|
||||
static struct
|
||||
{
|
||||
char *name;
|
||||
void (*func)(DCB *, MAXINFO_TREE *);
|
||||
} clear_commands[] = {
|
||||
{ "server", exec_clear_server},
|
||||
{ NULL, NULL}
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute a clear command parse tree and return the result set or runtime error
|
||||
*
|
||||
* @param dcb The DCB that connects to the client
|
||||
* @param tree The parse tree for the query
|
||||
*/
|
||||
static void
|
||||
exec_clear(DCB *dcb, MAXINFO_TREE *tree)
|
||||
{
|
||||
int i;
|
||||
char errmsg[120];
|
||||
|
||||
for (i = 0; clear_commands[i].name; i++)
|
||||
{
|
||||
if (strcasecmp(clear_commands[i].name, tree->value) == 0)
|
||||
{
|
||||
(*clear_commands[i].func)(dcb, tree->right);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (strlen(tree->value) > 80) // Prevent buffer overrun
|
||||
{
|
||||
tree->value[80] = 0;
|
||||
}
|
||||
sprintf(errmsg, "Unsupported clear command '%s'", tree->value);
|
||||
maxinfo_send_error(dcb, 0, errmsg);
|
||||
skygw_log_write(LE, errmsg);
|
||||
}
|
||||
|
||||
extern void shutdown_server();
|
||||
|
||||
/**
|
||||
* MaxScale shutdown
|
||||
* @param dcb Client DCB
|
||||
* @param tree Parse tree
|
||||
*/
|
||||
void exec_shutdown_maxscale(DCB *dcb, MAXINFO_TREE *tree)
|
||||
{
|
||||
shutdown_server();
|
||||
maxinfo_send_ok(dcb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop a monitor
|
||||
* @param dcb Client DCB
|
||||
* @param tree Parse tree
|
||||
*/
|
||||
void exec_shutdown_monitor(DCB *dcb, MAXINFO_TREE *tree)
|
||||
{
|
||||
char errmsg[120];
|
||||
if (tree && tree->value)
|
||||
{
|
||||
MONITOR* monitor = monitor_find(tree->value);
|
||||
if (monitor)
|
||||
{
|
||||
monitorStop(monitor);
|
||||
maxinfo_send_ok(dcb);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strlen(tree->value) > 80) // Prevent buffer overrun
|
||||
{
|
||||
tree->value[80] = 0;
|
||||
}
|
||||
sprintf(errmsg, "Invalid argument '%s'", tree->value);
|
||||
maxinfo_send_error(dcb, 0, errmsg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(errmsg, "Missing argument for 'SHUTDOWN MONITOR'");
|
||||
maxinfo_send_error(dcb, 0, errmsg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop a service
|
||||
* @param dcb Client DCB
|
||||
* @param tree Parse tree
|
||||
*/
|
||||
void exec_shutdown_service(DCB *dcb, MAXINFO_TREE *tree)
|
||||
{
|
||||
char errmsg[120];
|
||||
if (tree && tree->value)
|
||||
{
|
||||
SERVICE* service = service_find(tree->value);
|
||||
if (service)
|
||||
{
|
||||
serviceStop(service);
|
||||
maxinfo_send_ok(dcb);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strlen(tree->value) > 80) // Prevent buffer overrun
|
||||
{
|
||||
tree->value[80] = 0;
|
||||
}
|
||||
sprintf(errmsg, "Invalid argument '%s'", tree->value);
|
||||
maxinfo_send_error(dcb, 0, errmsg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(errmsg, "Missing argument for 'SHUTDOWN SERVICE'");
|
||||
maxinfo_send_error(dcb, 0, errmsg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The table of shutdown commands that are supported
|
||||
*/
|
||||
static struct
|
||||
{
|
||||
char *name;
|
||||
void (*func)(DCB *, MAXINFO_TREE *);
|
||||
} shutdown_commands[] = {
|
||||
{ "maxscale", exec_shutdown_maxscale},
|
||||
{ "monitor", exec_shutdown_monitor},
|
||||
{ "service", exec_shutdown_service},
|
||||
{ NULL, NULL}
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute a shutdown command parse tree and return OK or runtime error
|
||||
*
|
||||
* @param dcb The DCB that connects to the client
|
||||
* @param tree The parse tree for the query
|
||||
*/
|
||||
static void
|
||||
exec_shutdown(DCB *dcb, MAXINFO_TREE *tree)
|
||||
{
|
||||
int i;
|
||||
char errmsg[120];
|
||||
|
||||
for (i = 0; shutdown_commands[i].name; i++)
|
||||
{
|
||||
if (strcasecmp(shutdown_commands[i].name, tree->value) == 0)
|
||||
{
|
||||
(*shutdown_commands[i].func)(dcb, tree->right);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (strlen(tree->value) > 80) // Prevent buffer overrun
|
||||
{
|
||||
tree->value[80] = 0;
|
||||
}
|
||||
sprintf(errmsg, "Unsupported shutdown command '%s'", tree->value);
|
||||
maxinfo_send_error(dcb, 0, errmsg);
|
||||
skygw_log_write(LE, errmsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restart a monitor
|
||||
* @param dcb Client DCB
|
||||
* @param tree Parse tree
|
||||
*/
|
||||
void exec_restart_monitor(DCB *dcb, MAXINFO_TREE *tree)
|
||||
{
|
||||
char errmsg[120];
|
||||
if (tree && tree->value)
|
||||
{
|
||||
MONITOR* monitor = monitor_find(tree->value);
|
||||
if (monitor)
|
||||
{
|
||||
monitorStart(monitor, NULL);
|
||||
maxinfo_send_ok(dcb);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strlen(tree->value) > 80) // Prevent buffer overrun
|
||||
{
|
||||
tree->value[80] = 0;
|
||||
}
|
||||
sprintf(errmsg, "Invalid argument '%s'", tree->value);
|
||||
maxinfo_send_error(dcb, 0, errmsg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(errmsg, "Missing argument for 'RESTART MONITOR'");
|
||||
maxinfo_send_error(dcb, 0, errmsg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restart a service
|
||||
* @param dcb Client DCB
|
||||
* @param tree Parse tree
|
||||
*/
|
||||
void exec_restart_service(DCB *dcb, MAXINFO_TREE *tree)
|
||||
{
|
||||
char errmsg[120];
|
||||
if (tree && tree->value)
|
||||
{
|
||||
SERVICE* service = service_find(tree->value);
|
||||
if (service)
|
||||
{
|
||||
serviceRestart(service);
|
||||
maxinfo_send_ok(dcb);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strlen(tree->value) > 80) // Prevent buffer overrun
|
||||
{
|
||||
tree->value[80] = 0;
|
||||
}
|
||||
sprintf(errmsg, "Invalid argument '%s'", tree->value);
|
||||
maxinfo_send_error(dcb, 0, errmsg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(errmsg, "Missing argument for 'RESTART SERVICE'");
|
||||
maxinfo_send_error(dcb, 0, errmsg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The table of restart commands that are supported
|
||||
*/
|
||||
static struct
|
||||
{
|
||||
char *name;
|
||||
void (*func)(DCB *, MAXINFO_TREE *);
|
||||
} restart_commands[] = {
|
||||
{ "monitor", exec_restart_monitor},
|
||||
{ "service", exec_restart_service},
|
||||
{ NULL, NULL}
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute a restart command parse tree and return OK or runtime error
|
||||
*
|
||||
* @param dcb The DCB that connects to the client
|
||||
* @param tree The parse tree for the query
|
||||
*/
|
||||
static void
|
||||
exec_restart(DCB *dcb, MAXINFO_TREE *tree)
|
||||
{
|
||||
int i;
|
||||
char errmsg[120];
|
||||
|
||||
for (i = 0; restart_commands[i].name; i++)
|
||||
{
|
||||
if (strcasecmp(restart_commands[i].name, tree->value) == 0)
|
||||
{
|
||||
(*restart_commands[i].func)(dcb, tree->right);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (strlen(tree->value) > 80) // Prevent buffer overrun
|
||||
{
|
||||
tree->value[80] = 0;
|
||||
}
|
||||
sprintf(errmsg, "Unsupported restart command '%s'", tree->value);
|
||||
maxinfo_send_error(dcb, 0, errmsg);
|
||||
skygw_log_write(LE, errmsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current MaxScale version
|
||||
*
|
||||
@ -764,3 +1228,25 @@ extern char *strcasestr();
|
||||
return rval;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an OK packet to the client.
|
||||
* @param dcb The DCB that connects to the client
|
||||
*/
|
||||
void maxinfo_send_ok(DCB *dcb)
|
||||
{
|
||||
static const char ok_packet[] ={
|
||||
0x07, 0x00, 0x00, 0x01,
|
||||
0x00, 0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
0x00, 0x00
|
||||
};
|
||||
|
||||
GWBUF* buffer = gwbuf_alloc(sizeof(ok_packet));
|
||||
|
||||
if (buffer)
|
||||
{
|
||||
memcpy(buffer->start, ok_packet, sizeof(ok_packet));
|
||||
dcb->func.write(dcb, buffer);
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +50,8 @@ static void free_tree(MAXINFO_TREE *);
|
||||
static char *fetch_token(char *, int *, char **);
|
||||
static MAXINFO_TREE *parse_column_list(char **sql);
|
||||
static MAXINFO_TREE *parse_table_name(char **sql);
|
||||
|
||||
MAXINFO_TREE* maxinfo_parse_literals(MAXINFO_TREE *tree, int min_args, char *ptr,
|
||||
PARSE_ERROR *parse_error);
|
||||
|
||||
/**
|
||||
* Parse a SQL subset for the maxinfo plugin and return a parse tree
|
||||
@ -111,6 +112,67 @@ MAXINFO_TREE *col, *table;
|
||||
table = parse_table_name(&ptr);
|
||||
return make_tree_node(MAXOP_SELECT, NULL, col, table);
|
||||
#endif
|
||||
case LT_FLUSH:
|
||||
free(text); // not needed
|
||||
ptr = fetch_token(ptr, &token, &text);
|
||||
return make_tree_node(MAXOP_FLUSH, text, NULL, NULL);
|
||||
|
||||
case LT_SHUTDOWN:
|
||||
free(text);
|
||||
ptr = fetch_token(ptr, &token, &text);
|
||||
tree = make_tree_node(MAXOP_SHUTDOWN, text, NULL, NULL);
|
||||
|
||||
if ((ptr = fetch_token(ptr, &token, &text)) == NULL)
|
||||
{
|
||||
/** Possibly SHUTDOWN MAXSCALE */
|
||||
return tree;
|
||||
}
|
||||
tree->right = make_tree_node(MAXOP_LITERAL, text, NULL, NULL);
|
||||
|
||||
if ((ptr = fetch_token(ptr, &token, &text)) != NULL)
|
||||
{
|
||||
/** Unknown token after SHUTDOWN MONITOR|SERVICE */
|
||||
*parse_error = PARSE_SYNTAX_ERROR;
|
||||
free_tree(tree);
|
||||
return NULL;
|
||||
}
|
||||
return tree;
|
||||
|
||||
case LT_RESTART:
|
||||
free(text);
|
||||
ptr = fetch_token(ptr, &token, &text);
|
||||
tree = make_tree_node(MAXOP_RESTART, text, NULL, NULL);
|
||||
|
||||
if ((ptr = fetch_token(ptr, &token, &text)) == NULL)
|
||||
{
|
||||
/** Missing token for RESTART MONITOR|SERVICE */
|
||||
*parse_error = PARSE_SYNTAX_ERROR;
|
||||
free_tree(tree);
|
||||
return NULL;
|
||||
}
|
||||
tree->right = make_tree_node(MAXOP_LITERAL, text, NULL, NULL);
|
||||
|
||||
if ((ptr = fetch_token(ptr, &token, &text)) != NULL)
|
||||
{
|
||||
/** Unknown token after RESTART MONITOR|SERVICE */
|
||||
*parse_error = PARSE_SYNTAX_ERROR;
|
||||
free_tree(tree);
|
||||
return NULL;
|
||||
}
|
||||
return tree;
|
||||
|
||||
case LT_SET:
|
||||
free(text); // not needed
|
||||
ptr = fetch_token(ptr, &token, &text);
|
||||
tree = make_tree_node(MAXOP_SET, text, NULL, NULL);
|
||||
return maxinfo_parse_literals(tree, 2, ptr, parse_error);
|
||||
|
||||
case LT_CLEAR:
|
||||
free(text); // not needed
|
||||
ptr = fetch_token(ptr, &token, &text);
|
||||
tree = make_tree_node(MAXOP_CLEAR, text, NULL, NULL);
|
||||
return maxinfo_parse_literals(tree, 2, ptr, parse_error);
|
||||
break;
|
||||
default:
|
||||
*parse_error = PARSE_SYNTAX_ERROR;
|
||||
return NULL;
|
||||
@ -231,18 +293,24 @@ free_tree(MAXINFO_TREE *tree)
|
||||
/**
|
||||
* The set of keywords known to the tokeniser
|
||||
*/
|
||||
static struct {
|
||||
char *text;
|
||||
int token;
|
||||
static struct
|
||||
{
|
||||
char *text;
|
||||
int token;
|
||||
} keywords[] = {
|
||||
{ "show", LT_SHOW },
|
||||
{ "select", LT_SELECT },
|
||||
{ "from", LT_FROM },
|
||||
{ "like", LT_LIKE },
|
||||
{ "=", LT_EQUAL },
|
||||
{ ",", LT_COMMA },
|
||||
{ "*", LT_STAR },
|
||||
{ NULL, 0 }
|
||||
{ "show", LT_SHOW},
|
||||
{ "select", LT_SELECT},
|
||||
{ "from", LT_FROM},
|
||||
{ "like", LT_LIKE},
|
||||
{ "=", LT_EQUAL},
|
||||
{ ",", LT_COMMA},
|
||||
{ "*", LT_STAR},
|
||||
{ "flush", LT_FLUSH},
|
||||
{ "set", LT_SET},
|
||||
{ "clear", LT_CLEAR},
|
||||
{ "shutdown", LT_SHUTDOWN},
|
||||
{ "restart", LT_RESTART},
|
||||
{ NULL, 0}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -322,3 +390,36 @@ int i;
|
||||
*token = LT_STRING;
|
||||
return s2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the remaining arguments as literals.
|
||||
* @param tree Previous head of the parse tree
|
||||
* @param min_args Minimum required number of arguments
|
||||
* @param ptr Pointer to client command
|
||||
* @param parse_error Pointer to parsing error to fill
|
||||
* @return Parsed tree or NULL if parsing failed
|
||||
*/
|
||||
MAXINFO_TREE* maxinfo_parse_literals(MAXINFO_TREE *tree, int min_args, char *ptr,
|
||||
PARSE_ERROR *parse_error)
|
||||
{
|
||||
int token;
|
||||
MAXINFO_TREE* node = tree;
|
||||
char *text;
|
||||
for(int i = 0; i < min_args; i++)
|
||||
{
|
||||
if((ptr = fetch_token(ptr, &token, &text)) == NULL ||
|
||||
(node->right = make_tree_node(MAXOP_LITERAL, text, NULL, NULL)) == NULL)
|
||||
{
|
||||
*parse_error = PARSE_SYNTAX_ERROR;
|
||||
free_tree(tree);
|
||||
if(ptr)
|
||||
{
|
||||
free(text);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
node = node->right;
|
||||
}
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
Reference in New Issue
Block a user