diff --git a/src/commands_parser.c b/src/commands_parser.c index 6c791415..05db36ba 100644 --- a/src/commands_parser.c +++ b/src/commands_parser.c @@ -256,195 +256,30 @@ char *parse_string(const char **walk, bool as_word) { * Free the returned CommandResult with command_result_free(). */ CommandResult *parse_command(const char *input, yajl_gen gen, ipc_client *client) { - DLOG("COMMAND: *%.4000s*\n", input); - state = INITIAL; - CommandResult *result = scalloc(1, sizeof(CommandResult)); + SCM status = scm_c_eval_string(input); + DLOG("COMMAND: *%.4000s*\n", input); + state = INITIAL; + CommandResult *result = scalloc(1, sizeof(CommandResult)); - command_output.client = client; + command_output.client = client; - /* A YAJL JSON generator used for formatting replies. */ - command_output.json_gen = gen; + /* A YAJL JSON generator used for formatting replies. */ + command_output.json_gen = gen; - y(array_open); - command_output.needs_tree_render = false; + // FIXME: Add results (as string, remove this json dependency) + 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; - const size_t len = strlen(input); - 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; + result->needs_tree_render = command_output.needs_tree_render; + return result; } /*