Allow the commands parser to use "number" arguments by making the stack typed.
This commit is contained in:
parent
34b8a02a36
commit
23d5d704ed
@ -73,7 +73,14 @@ typedef struct tokenptr {
|
||||
struct stack_entry {
|
||||
/* Just a pointer, not dynamically allocated. */
|
||||
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. */
|
||||
@ -90,7 +97,30 @@ static void push_string(const char *identifier, char *str) {
|
||||
continue;
|
||||
/* Found a free slot, let’s store it here. */
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
// called functions.
|
||||
// TODO move to a common util
|
||||
static char *get_string(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].str;
|
||||
return stack[c].val.str;
|
||||
}
|
||||
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) {
|
||||
for (int c = 0; c < 10; c++) {
|
||||
if (stack[c].str != NULL)
|
||||
free(stack[c].str);
|
||||
if (stack[c].type == STACK_STR && stack[c].val.str != NULL)
|
||||
free(stack[c].val.str);
|
||||
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.
|
||||
******************************************************************************/
|
||||
@ -316,6 +314,29 @@ CommandResult *parse_command(const char *input, yajl_gen gen) {
|
||||
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 ||
|
||||
strcmp(token->name, "word") == 0) {
|
||||
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
|
||||
* 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 "
|
||||
fprintf(stderr, "BUG: config_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);
|
||||
@ -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
|
||||
* 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 "
|
||||
fprintf(stderr, "BUG: config_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);
|
||||
@ -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.
|
||||
******************************************************************************/
|
||||
|
Loading…
Reference in New Issue
Block a user