Refactor parse_command
parse_command returns a struct that contains useful information about the result of a command as a whole (instead of the intermediate representation used during parsing). parse_command now requires the caller to allocate the yajl_gen used for generating a json reply. This is passed as the second parameter to parse_command. If NULL is passed, no json reply will be generated.
This commit is contained in:
parent
62ea60ba42
commit
c7aae56030
|
@ -17,7 +17,7 @@
|
||||||
* internally use this struct when calling cmd_floating and cmd_border.
|
* internally use this struct when calling cmd_floating and cmd_border.
|
||||||
*/
|
*/
|
||||||
struct CommandResultIR {
|
struct CommandResultIR {
|
||||||
/* The JSON generator to append a reply to. */
|
/* The JSON generator to append a reply to (may be NULL). */
|
||||||
yajl_gen json_gen;
|
yajl_gen json_gen;
|
||||||
|
|
||||||
/* The next state to transition to. Passed to the function so that we can
|
/* The next state to transition to. Passed to the function so that we can
|
||||||
|
@ -29,4 +29,31 @@ struct CommandResultIR {
|
||||||
bool needs_tree_render;
|
bool needs_tree_render;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CommandResultIR *parse_command(const char *input);
|
typedef struct CommandResult CommandResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A struct that contains useful information about the result of a command as a
|
||||||
|
* whole (e.g. a compound command like "floating enable, border none").
|
||||||
|
* needs_tree_render is true if needs_tree_render of any individual command was
|
||||||
|
* true.
|
||||||
|
*/
|
||||||
|
struct CommandResult {
|
||||||
|
bool parse_error;
|
||||||
|
/* the error_message is currently only set for parse errors */
|
||||||
|
char *error_message;
|
||||||
|
bool needs_tree_render;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses and executes the given command. If a caller-allocated yajl_gen is
|
||||||
|
* passed, a json reply will be generated in the format specified by the ipc
|
||||||
|
* protocol. Pass NULL if no json reply is required.
|
||||||
|
*
|
||||||
|
* Free the returned CommandResult with command_result_free().
|
||||||
|
*/
|
||||||
|
CommandResult *parse_command(const char *input, yajl_gen gen);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frees a CommandResult
|
||||||
|
*/
|
||||||
|
void command_result_free(CommandResult *result);
|
||||||
|
|
|
@ -45,13 +45,13 @@ void run_assignments(i3Window *window) {
|
||||||
DLOG("execute command %s\n", current->dest.command);
|
DLOG("execute command %s\n", current->dest.command);
|
||||||
char *full_command;
|
char *full_command;
|
||||||
sasprintf(&full_command, "[id=\"%d\"] %s", window->id, current->dest.command);
|
sasprintf(&full_command, "[id=\"%d\"] %s", window->id, current->dest.command);
|
||||||
struct CommandResultIR *command_output = parse_command(full_command);
|
CommandResult *result = parse_command(full_command, NULL);
|
||||||
free(full_command);
|
free(full_command);
|
||||||
|
|
||||||
if (command_output->needs_tree_render)
|
if (result->needs_tree_render)
|
||||||
needs_tree_render = true;
|
needs_tree_render = true;
|
||||||
|
|
||||||
yajl_gen_free(command_output->json_gen);
|
command_result_free(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Store that we ran this assignment to not execute it again */
|
/* Store that we ran this assignment to not execute it again */
|
||||||
|
|
|
@ -16,21 +16,25 @@
|
||||||
#include "shmlog.h"
|
#include "shmlog.h"
|
||||||
|
|
||||||
// Macros to make the YAJL API a bit easier to use.
|
// Macros to make the YAJL API a bit easier to use.
|
||||||
#define y(x, ...) yajl_gen_ ## x (cmd_output->json_gen, ##__VA_ARGS__)
|
#define y(x, ...) (cmd_output->json_gen != NULL ? yajl_gen_ ## x (cmd_output->json_gen, ##__VA_ARGS__) : 0)
|
||||||
#define ystr(str) yajl_gen_string(cmd_output->json_gen, (unsigned char*)str, strlen(str))
|
#define ystr(str) (cmd_output->json_gen != NULL ? yajl_gen_string(cmd_output->json_gen, (unsigned char*)str, strlen(str)) : 0)
|
||||||
#define ysuccess(success) do { \
|
#define ysuccess(success) do { \
|
||||||
y(map_open); \
|
if (cmd_output->json_gen != NULL) { \
|
||||||
ystr("success"); \
|
y(map_open); \
|
||||||
y(bool, success); \
|
ystr("success"); \
|
||||||
y(map_close); \
|
y(bool, success); \
|
||||||
|
y(map_close); \
|
||||||
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
#define yerror(message) do { \
|
#define yerror(message) do { \
|
||||||
y(map_open); \
|
if (cmd_output->json_gen != NULL) { \
|
||||||
ystr("success"); \
|
y(map_open); \
|
||||||
y(bool, false); \
|
ystr("success"); \
|
||||||
ystr("error"); \
|
y(bool, false); \
|
||||||
ystr(message); \
|
ystr("error"); \
|
||||||
y(map_close); \
|
ystr(message); \
|
||||||
|
y(map_close); \
|
||||||
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/** When the command did not include match criteria (!), we use the currently
|
/** When the command did not include match criteria (!), we use the currently
|
||||||
|
|
|
@ -35,8 +35,8 @@
|
||||||
#include "all.h"
|
#include "all.h"
|
||||||
|
|
||||||
// Macros to make the YAJL API a bit easier to use.
|
// Macros to make the YAJL API a bit easier to use.
|
||||||
#define y(x, ...) yajl_gen_ ## x (command_output.json_gen, ##__VA_ARGS__)
|
#define y(x, ...) (command_output.json_gen != NULL ? yajl_gen_ ## x (command_output.json_gen, ##__VA_ARGS__) : 0)
|
||||||
#define ystr(str) yajl_gen_string(command_output.json_gen, (unsigned char*)str, strlen(str))
|
#define ystr(str) (command_output.json_gen != NULL ? yajl_gen_string(command_output.json_gen, (unsigned char*)str, strlen(str)) : 0)
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* The data structures used for parsing. Essentially the current state and a
|
* The data structures used for parsing. Essentially the current state and a
|
||||||
|
@ -205,12 +205,20 @@ static void next_state(const cmdp_token *token) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CommandResultIR *parse_command(const char *input) {
|
/*
|
||||||
|
* Parses and executes the given command. If a caller-allocated yajl_gen is
|
||||||
|
* passed, a json reply will be generated in the format specified by the ipc
|
||||||
|
* protocol. Pass NULL if no json reply is required.
|
||||||
|
*
|
||||||
|
* Free the returned CommandResult with command_result_free().
|
||||||
|
*/
|
||||||
|
CommandResult *parse_command(const char *input, yajl_gen gen) {
|
||||||
DLOG("COMMAND: *%s*\n", input);
|
DLOG("COMMAND: *%s*\n", input);
|
||||||
state = INITIAL;
|
state = INITIAL;
|
||||||
|
CommandResult *result = scalloc(sizeof(CommandResult));
|
||||||
|
|
||||||
/* A YAJL JSON generator used for formatting replies. */
|
/* A YAJL JSON generator used for formatting replies. */
|
||||||
command_output.json_gen = yajl_gen_alloc(NULL);
|
command_output.json_gen = gen;
|
||||||
|
|
||||||
y(array_open);
|
y(array_open);
|
||||||
command_output.needs_tree_render = false;
|
command_output.needs_tree_render = false;
|
||||||
|
@ -378,6 +386,9 @@ struct CommandResultIR *parse_command(const char *input) {
|
||||||
ELOG("Your command: %s\n", input);
|
ELOG("Your command: %s\n", input);
|
||||||
ELOG(" %s\n", position);
|
ELOG(" %s\n", position);
|
||||||
|
|
||||||
|
result->parse_error = true;
|
||||||
|
result->error_message = errormessage;
|
||||||
|
|
||||||
/* Format this error message as a JSON reply. */
|
/* Format this error message as a JSON reply. */
|
||||||
y(map_open);
|
y(map_open);
|
||||||
ystr("success");
|
ystr("success");
|
||||||
|
@ -396,7 +407,6 @@ struct CommandResultIR *parse_command(const char *input) {
|
||||||
y(map_close);
|
y(map_close);
|
||||||
|
|
||||||
free(position);
|
free(position);
|
||||||
free(errormessage);
|
|
||||||
clear_stack();
|
clear_stack();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -404,7 +414,19 @@ struct CommandResultIR *parse_command(const char *input) {
|
||||||
|
|
||||||
y(array_close);
|
y(array_close);
|
||||||
|
|
||||||
return &command_output;
|
result->needs_tree_render = command_output.needs_tree_render;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Frees a CommandResult
|
||||||
|
*/
|
||||||
|
void command_result_free(CommandResult *result) {
|
||||||
|
if (result == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
FREE(result->error_message);
|
||||||
|
FREE(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
@ -442,6 +464,12 @@ int main(int argc, char *argv[]) {
|
||||||
fprintf(stderr, "Syntax: %s <command>\n", argv[0]);
|
fprintf(stderr, "Syntax: %s <command>\n", argv[0]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
parse_command(argv[1]);
|
yajl_gen gen = yajl_gen_alloc(NULL);
|
||||||
|
|
||||||
|
CommandResult *result = parse_command(argv[1], gen);
|
||||||
|
|
||||||
|
command_result_free(result);
|
||||||
|
|
||||||
|
yajl_gen_free(gen);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
12
src/ipc.c
12
src/ipc.c
|
@ -117,20 +117,24 @@ IPC_HANDLER(command) {
|
||||||
char *command = scalloc(message_size + 1);
|
char *command = scalloc(message_size + 1);
|
||||||
strncpy(command, (const char*)message, message_size);
|
strncpy(command, (const char*)message, message_size);
|
||||||
LOG("IPC: received: *%s*\n", command);
|
LOG("IPC: received: *%s*\n", command);
|
||||||
struct CommandResultIR *command_output = parse_command((const char*)command);
|
yajl_gen gen = yajl_gen_alloc(NULL);
|
||||||
|
|
||||||
|
CommandResult *result = parse_command((const char*)command, gen);
|
||||||
free(command);
|
free(command);
|
||||||
|
|
||||||
if (command_output->needs_tree_render)
|
if (result->needs_tree_render)
|
||||||
tree_render();
|
tree_render();
|
||||||
|
|
||||||
|
command_result_free(result);
|
||||||
|
|
||||||
const unsigned char *reply;
|
const unsigned char *reply;
|
||||||
ylength length;
|
ylength length;
|
||||||
yajl_gen_get_buf(command_output->json_gen, &reply, &length);
|
yajl_gen_get_buf(gen, &reply, &length);
|
||||||
|
|
||||||
ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_COMMAND,
|
ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_COMMAND,
|
||||||
(const uint8_t*)reply);
|
(const uint8_t*)reply);
|
||||||
|
|
||||||
yajl_gen_free(command_output->json_gen);
|
yajl_gen_free(gen);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dump_rect(yajl_gen gen, const char *name, Rect r) {
|
static void dump_rect(yajl_gen gen, const char *name, Rect r) {
|
||||||
|
|
|
@ -72,19 +72,23 @@ void handle_key_press(xcb_key_press_event_t *event) {
|
||||||
if (bind == NULL)
|
if (bind == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
yajl_gen gen = yajl_gen_alloc(NULL);
|
||||||
|
|
||||||
char *command_copy = sstrdup(bind->command);
|
char *command_copy = sstrdup(bind->command);
|
||||||
struct CommandResultIR *command_output = parse_command(command_copy);
|
CommandResult *result = parse_command(command_copy, gen);
|
||||||
free(command_copy);
|
free(command_copy);
|
||||||
|
|
||||||
if (command_output->needs_tree_render)
|
if (result->needs_tree_render)
|
||||||
tree_render();
|
tree_render();
|
||||||
|
|
||||||
|
command_result_free(result);
|
||||||
|
|
||||||
/* We parse the JSON reply to figure out whether there was an error
|
/* We parse the JSON reply to figure out whether there was an error
|
||||||
* ("success" being false in on of the returned dictionaries). */
|
* ("success" being false in on of the returned dictionaries). */
|
||||||
const unsigned char *reply;
|
const unsigned char *reply;
|
||||||
size_t length;
|
size_t length;
|
||||||
yajl_handle handle = yajl_alloc(&command_error_callbacks, NULL, NULL);
|
yajl_handle handle = yajl_alloc(&command_error_callbacks, NULL, NULL);
|
||||||
yajl_gen_get_buf(command_output->json_gen, &reply, &length);
|
yajl_gen_get_buf(gen, &reply, &length);
|
||||||
|
|
||||||
current_nesting_level = 0;
|
current_nesting_level = 0;
|
||||||
parse_error_key = false;
|
parse_error_key = false;
|
||||||
|
@ -116,5 +120,5 @@ void handle_key_press(xcb_key_press_event_t *event) {
|
||||||
|
|
||||||
yajl_free(handle);
|
yajl_free(handle);
|
||||||
|
|
||||||
yajl_gen_free(command_output->json_gen);
|
yajl_gen_free(gen);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue