Allow the commands parser to use "number" arguments by making the stack typed.
This commit is contained in:
parent
5049990284
commit
f5f5683fa7
@ -73,7 +73,14 @@ typedef struct tokenptr {
|
|||||||
struct stack_entry {
|
struct stack_entry {
|
||||||
/* Just a pointer, not dynamically allocated. */
|
/* Just a pointer, not dynamically allocated. */
|
||||||
const char *identifier;
|
const char *identifier;
|
||||||
char *str;
|
enum {
|
||||||
|
STACK_STR = 0,
|
||||||
|
STACK_LONG = 1,
|
||||||
|
} type;
|
||||||
|
union {
|
||||||
|
char *str;
|
||||||
|
long num;
|
||||||
|
} val;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* 10 entries should be enough for everybody. */
|
/* 10 entries should be enough for everybody. */
|
||||||
@ -90,7 +97,30 @@ static void push_string(const char *identifier, char *str) {
|
|||||||
continue;
|
continue;
|
||||||
/* Found a free slot, let’s store it here. */
|
/* Found a free slot, let’s store it here. */
|
||||||
stack[c].identifier = identifier;
|
stack[c].identifier = identifier;
|
||||||
stack[c].str = str;
|
stack[c].val.str = str;
|
||||||
|
stack[c].type = STACK_STR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* When we arrive here, the stack is full. This should not happen and
|
||||||
|
* means there’s either a bug in this parser or the specification
|
||||||
|
* contains a command with more than 10 identified tokens. */
|
||||||
|
fprintf(stderr, "BUG: commands_parser stack full. This means either a bug "
|
||||||
|
"in the code, or a new command which contains more than "
|
||||||
|
"10 identified tokens.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO move to a common util
|
||||||
|
static void push_long(const char *identifier, long num) {
|
||||||
|
for (int c = 0; c < 10; c++) {
|
||||||
|
if (stack[c].identifier != NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
stack[c].identifier = identifier;
|
||||||
|
stack[c].val.num = num;
|
||||||
|
stack[c].type = STACK_LONG;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,72 +135,40 @@ static void push_string(const char *identifier, char *str) {
|
|||||||
|
|
||||||
// XXX: ideally, this would be const char. need to check if that works with all
|
// XXX: ideally, this would be const char. need to check if that works with all
|
||||||
// called functions.
|
// called functions.
|
||||||
|
// TODO move to a common util
|
||||||
static char *get_string(const char *identifier) {
|
static char *get_string(const char *identifier) {
|
||||||
for (int c = 0; c < 10; c++) {
|
for (int c = 0; c < 10; c++) {
|
||||||
if (stack[c].identifier == NULL)
|
if (stack[c].identifier == NULL)
|
||||||
break;
|
break;
|
||||||
if (strcmp(identifier, stack[c].identifier) == 0)
|
if (strcmp(identifier, stack[c].identifier) == 0)
|
||||||
return stack[c].str;
|
return stack[c].val.str;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO move to a common util
|
||||||
|
static long get_long(const char *identifier) {
|
||||||
|
for (int c = 0; c < 10; c++) {
|
||||||
|
if (stack[c].identifier == NULL)
|
||||||
|
break;
|
||||||
|
if (strcmp(identifier, stack[c].identifier) == 0)
|
||||||
|
return stack[c].val.num;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO move to a common util
|
||||||
static void clear_stack(void) {
|
static void clear_stack(void) {
|
||||||
for (int c = 0; c < 10; c++) {
|
for (int c = 0; c < 10; c++) {
|
||||||
if (stack[c].str != NULL)
|
if (stack[c].type == STACK_STR && stack[c].val.str != NULL)
|
||||||
free(stack[c].str);
|
free(stack[c].val.str);
|
||||||
stack[c].identifier = NULL;
|
stack[c].identifier = NULL;
|
||||||
stack[c].str = NULL;
|
stack[c].val.str = NULL;
|
||||||
|
stack[c].val.num = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove this if it turns out we don’t need it for testing.
|
|
||||||
#if 0
|
|
||||||
/*******************************************************************************
|
|
||||||
* A dynamically growing linked list which holds the criteria for the current
|
|
||||||
* command.
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
typedef struct criterion {
|
|
||||||
char *type;
|
|
||||||
char *value;
|
|
||||||
|
|
||||||
TAILQ_ENTRY(criterion) criteria;
|
|
||||||
} criterion;
|
|
||||||
|
|
||||||
static TAILQ_HEAD(criteria_head, criterion) criteria =
|
|
||||||
TAILQ_HEAD_INITIALIZER(criteria);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Stores the given type/value in the list of criteria.
|
|
||||||
* Accepts a pointer as first argument, since it is 'call'ed by the parser.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static void push_criterion(void *unused_criteria, const char *type,
|
|
||||||
const char *value) {
|
|
||||||
struct criterion *criterion = smalloc(sizeof(struct criterion));
|
|
||||||
criterion->type = sstrdup(type);
|
|
||||||
criterion->value = sstrdup(value);
|
|
||||||
TAILQ_INSERT_TAIL(&criteria, criterion, criteria);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Clears the criteria linked list.
|
|
||||||
* Accepts a pointer as first argument, since it is 'call'ed by the parser.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static void clear_criteria(void *unused_criteria) {
|
|
||||||
struct criterion *criterion;
|
|
||||||
while (!TAILQ_EMPTY(&criteria)) {
|
|
||||||
criterion = TAILQ_FIRST(&criteria);
|
|
||||||
free(criterion->type);
|
|
||||||
free(criterion->value);
|
|
||||||
TAILQ_REMOVE(&criteria, criterion, criteria);
|
|
||||||
free(criterion);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* The parser itself.
|
* The parser itself.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
@ -316,6 +314,29 @@ CommandResult *parse_command(const char *input, yajl_gen gen) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (strcmp(token->name, "number") == 0) {
|
||||||
|
/* Handle numbers. We only accept decimal numbers for now. */
|
||||||
|
char *end = NULL;
|
||||||
|
errno = 0;
|
||||||
|
long int num = strtol(walk, &end, 10);
|
||||||
|
if ((errno == ERANGE && (num == LONG_MIN || num == LONG_MAX)) ||
|
||||||
|
(errno != 0 && num == 0))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* No valid numbers found */
|
||||||
|
if (end == walk)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (token->identifier != NULL)
|
||||||
|
push_long(token->identifier, num);
|
||||||
|
|
||||||
|
/* Set walk to the first non-number character */
|
||||||
|
walk = end;
|
||||||
|
next_state(token);
|
||||||
|
token_handled = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (strcmp(token->name, "string") == 0 ||
|
if (strcmp(token->name, "string") == 0 ||
|
||||||
strcmp(token->name, "word") == 0) {
|
strcmp(token->name, "word") == 0) {
|
||||||
char *str = parse_string(&walk, (token->name[0] != 's'));
|
char *str = parse_string(&walk, (token->name[0] != 's'));
|
||||||
|
@ -122,7 +122,7 @@ static void push_string(const char *identifier, const char *str) {
|
|||||||
/* When we arrive here, the stack is full. This should not happen and
|
/* When we arrive here, the stack is full. This should not happen and
|
||||||
* means there’s either a bug in this parser or the specification
|
* means there’s either a bug in this parser or the specification
|
||||||
* contains a command with more than 10 identified tokens. */
|
* contains a command with more than 10 identified tokens. */
|
||||||
fprintf(stderr, "BUG: commands_parser stack full. This means either a bug "
|
fprintf(stderr, "BUG: config_parser stack full. This means either a bug "
|
||||||
"in the code, or a new command which contains more than "
|
"in the code, or a new command which contains more than "
|
||||||
"10 identified tokens.\n");
|
"10 identified tokens.\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
@ -142,7 +142,7 @@ static void push_long(const char *identifier, long num) {
|
|||||||
/* When we arrive here, the stack is full. This should not happen and
|
/* When we arrive here, the stack is full. This should not happen and
|
||||||
* means there’s either a bug in this parser or the specification
|
* means there’s either a bug in this parser or the specification
|
||||||
* contains a command with more than 10 identified tokens. */
|
* contains a command with more than 10 identified tokens. */
|
||||||
fprintf(stderr, "BUG: commands_parser stack full. This means either a bug "
|
fprintf(stderr, "BUG: config_parser stack full. This means either a bug "
|
||||||
"in the code, or a new command which contains more than "
|
"in the code, or a new command which contains more than "
|
||||||
"10 identified tokens.\n");
|
"10 identified tokens.\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
@ -178,53 +178,6 @@ static void clear_stack(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove this if it turns out we don’t need it for testing.
|
|
||||||
#if 0
|
|
||||||
/*******************************************************************************
|
|
||||||
* A dynamically growing linked list which holds the criteria for the current
|
|
||||||
* command.
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
typedef struct criterion {
|
|
||||||
char *type;
|
|
||||||
char *value;
|
|
||||||
|
|
||||||
TAILQ_ENTRY(criterion) criteria;
|
|
||||||
} criterion;
|
|
||||||
|
|
||||||
static TAILQ_HEAD(criteria_head, criterion) criteria =
|
|
||||||
TAILQ_HEAD_INITIALIZER(criteria);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Stores the given type/value in the list of criteria.
|
|
||||||
* Accepts a pointer as first argument, since it is 'call'ed by the parser.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static void push_criterion(void *unused_criteria, const char *type,
|
|
||||||
const char *value) {
|
|
||||||
struct criterion *criterion = smalloc(sizeof(struct criterion));
|
|
||||||
criterion->type = sstrdup(type);
|
|
||||||
criterion->value = sstrdup(value);
|
|
||||||
TAILQ_INSERT_TAIL(&criteria, criterion, criteria);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Clears the criteria linked list.
|
|
||||||
* Accepts a pointer as first argument, since it is 'call'ed by the parser.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static void clear_criteria(void *unused_criteria) {
|
|
||||||
struct criterion *criterion;
|
|
||||||
while (!TAILQ_EMPTY(&criteria)) {
|
|
||||||
criterion = TAILQ_FIRST(&criteria);
|
|
||||||
free(criterion->type);
|
|
||||||
free(criterion->value);
|
|
||||||
TAILQ_REMOVE(&criteria, criterion, criteria);
|
|
||||||
free(criterion);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* The parser itself.
|
* The parser itself.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
Loading…
Reference in New Issue
Block a user