eval received i3-msg
This commit is contained in:
parent
3fe8e00356
commit
176a56df0a
|
@ -256,195 +256,30 @@ char *parse_string(const char **walk, bool as_word) {
|
||||||
* Free the returned CommandResult with command_result_free().
|
* Free the returned CommandResult with command_result_free().
|
||||||
*/
|
*/
|
||||||
CommandResult *parse_command(const char *input, yajl_gen gen, ipc_client *client) {
|
CommandResult *parse_command(const char *input, yajl_gen gen, ipc_client *client) {
|
||||||
DLOG("COMMAND: *%.4000s*\n", input);
|
SCM status = scm_c_eval_string(input);
|
||||||
state = INITIAL;
|
DLOG("COMMAND: *%.4000s*\n", input);
|
||||||
CommandResult *result = scalloc(1, sizeof(CommandResult));
|
state = INITIAL;
|
||||||
|
CommandResult *result = scalloc(1, sizeof(CommandResult));
|
||||||
|
|
||||||
command_output.client = client;
|
command_output.client = client;
|
||||||
|
|
||||||
/* A YAJL JSON generator used for formatting replies. */
|
/* A YAJL JSON generator used for formatting replies. */
|
||||||
command_output.json_gen = gen;
|
command_output.json_gen = gen;
|
||||||
|
|
||||||
y(array_open);
|
// FIXME: Add results (as string, remove this json dependency)
|
||||||
command_output.needs_tree_render = false;
|
y(map_open);
|
||||||
|
// BOOL + false -> failed
|
||||||
|
// else success
|
||||||
|
ystr("success");
|
||||||
|
bool success = (scm_is_bool(status) == 0) || scm_is_true(status);
|
||||||
|
y(bool, success);
|
||||||
|
ystr("results");
|
||||||
|
ystr(scm_is_string(status) ? scm_to_locale_string(status) : "#undefined");
|
||||||
|
y(map_close);
|
||||||
|
command_output.needs_tree_render = false;
|
||||||
|
|
||||||
const char *walk = input;
|
result->needs_tree_render = command_output.needs_tree_render;
|
||||||
const size_t len = strlen(input);
|
return result;
|
||||||
int c;
|
|
||||||
const cmdp_token *token;
|
|
||||||
bool token_handled;
|
|
||||||
|
|
||||||
// TODO: make this testable
|
|
||||||
#ifndef TEST_PARSER
|
|
||||||
cmd_criteria_init(¤t_match, &subcommand_output);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* The "<=" operator is intentional: We also handle the terminating 0-byte
|
|
||||||
* explicitly by looking for an 'end' token. */
|
|
||||||
while ((size_t)(walk - input) <= len) {
|
|
||||||
/* skip whitespace and newlines before every token */
|
|
||||||
while ((*walk == ' ' || *walk == '\t' ||
|
|
||||||
*walk == '\r' || *walk == '\n') &&
|
|
||||||
*walk != '\0')
|
|
||||||
walk++;
|
|
||||||
|
|
||||||
cmdp_token_ptr *ptr = &(tokens[state]);
|
|
||||||
token_handled = false;
|
|
||||||
for (c = 0; c < ptr->n; c++) {
|
|
||||||
token = &(ptr->array[c]);
|
|
||||||
|
|
||||||
/* A literal. */
|
|
||||||
if (token->name[0] == '\'') {
|
|
||||||
if (strncasecmp(walk, token->name + 1, strlen(token->name) - 1) == 0) {
|
|
||||||
if (token->identifier != NULL)
|
|
||||||
push_string(token->identifier, sstrdup(token->name + 1));
|
|
||||||
walk += strlen(token->name) - 1;
|
|
||||||
next_state(token);
|
|
||||||
token_handled = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
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'));
|
|
||||||
if (str != NULL) {
|
|
||||||
if (token->identifier)
|
|
||||||
push_string(token->identifier, str);
|
|
||||||
/* If we are at the end of a quoted string, skip the ending
|
|
||||||
* double quote. */
|
|
||||||
if (*walk == '"')
|
|
||||||
walk++;
|
|
||||||
next_state(token);
|
|
||||||
token_handled = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(token->name, "end") == 0) {
|
|
||||||
if (*walk == '\0' || *walk == ',' || *walk == ';') {
|
|
||||||
next_state(token);
|
|
||||||
token_handled = true;
|
|
||||||
/* To make sure we start with an appropriate matching
|
|
||||||
* datastructure for commands which do *not* specify any
|
|
||||||
* criteria, we re-initialize the criteria system after
|
|
||||||
* every command. */
|
|
||||||
// TODO: make this testable
|
|
||||||
#ifndef TEST_PARSER
|
|
||||||
if (*walk == '\0' || *walk == ';')
|
|
||||||
cmd_criteria_init(¤t_match, &subcommand_output);
|
|
||||||
#endif
|
|
||||||
walk++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!token_handled) {
|
|
||||||
/* Figure out how much memory we will need to fill in the names of
|
|
||||||
* all tokens afterwards. */
|
|
||||||
int tokenlen = 0;
|
|
||||||
for (c = 0; c < ptr->n; c++)
|
|
||||||
tokenlen += strlen(ptr->array[c].name) + strlen("'', ");
|
|
||||||
|
|
||||||
/* Build up a decent error message. We include the problem, the
|
|
||||||
* full input, and underline the position where the parser
|
|
||||||
* currently is. */
|
|
||||||
char *errormessage;
|
|
||||||
char *possible_tokens = smalloc(tokenlen + 1);
|
|
||||||
char *tokenwalk = possible_tokens;
|
|
||||||
for (c = 0; c < ptr->n; c++) {
|
|
||||||
token = &(ptr->array[c]);
|
|
||||||
if (token->name[0] == '\'') {
|
|
||||||
/* A literal is copied to the error message enclosed with
|
|
||||||
* single quotes. */
|
|
||||||
*tokenwalk++ = '\'';
|
|
||||||
strcpy(tokenwalk, token->name + 1);
|
|
||||||
tokenwalk += strlen(token->name + 1);
|
|
||||||
*tokenwalk++ = '\'';
|
|
||||||
} else {
|
|
||||||
/* Any other token is copied to the error message enclosed
|
|
||||||
* with angle brackets. */
|
|
||||||
*tokenwalk++ = '<';
|
|
||||||
strcpy(tokenwalk, token->name);
|
|
||||||
tokenwalk += strlen(token->name);
|
|
||||||
*tokenwalk++ = '>';
|
|
||||||
}
|
|
||||||
if (c < (ptr->n - 1)) {
|
|
||||||
*tokenwalk++ = ',';
|
|
||||||
*tokenwalk++ = ' ';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*tokenwalk = '\0';
|
|
||||||
sasprintf(&errormessage, "Expected one of these tokens: %s",
|
|
||||||
possible_tokens);
|
|
||||||
free(possible_tokens);
|
|
||||||
|
|
||||||
/* Contains the same amount of characters as 'input' has, but with
|
|
||||||
* the unparseable part highlighted using ^ characters. */
|
|
||||||
char *position = smalloc(len + 1);
|
|
||||||
for (const char *copywalk = input; *copywalk != '\0'; copywalk++)
|
|
||||||
position[(copywalk - input)] = (copywalk >= walk ? '^' : ' ');
|
|
||||||
position[len] = '\0';
|
|
||||||
|
|
||||||
ELOG("%s\n", errormessage);
|
|
||||||
ELOG("Your command: %s\n", input);
|
|
||||||
ELOG(" %s\n", position);
|
|
||||||
|
|
||||||
result->parse_error = true;
|
|
||||||
result->error_message = errormessage;
|
|
||||||
|
|
||||||
/* Format this error message as a JSON reply. */
|
|
||||||
y(map_open);
|
|
||||||
ystr("success");
|
|
||||||
y(bool, false);
|
|
||||||
/* We set parse_error to true to distinguish this from other
|
|
||||||
* errors. i3-nagbar is spawned upon keypresses only for parser
|
|
||||||
* errors. */
|
|
||||||
ystr("parse_error");
|
|
||||||
y(bool, true);
|
|
||||||
ystr("error");
|
|
||||||
ystr(errormessage);
|
|
||||||
ystr("input");
|
|
||||||
ystr(input);
|
|
||||||
ystr("errorposition");
|
|
||||||
ystr(position);
|
|
||||||
y(map_close);
|
|
||||||
|
|
||||||
free(position);
|
|
||||||
clear_stack();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
y(array_close);
|
|
||||||
|
|
||||||
result->needs_tree_render = command_output.needs_tree_render;
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue