* internally use this struct when calling cmd_floating and cmd_border.
*/
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;
/* The next state to transition to. Passed to the function so that we can
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);
DLOG("execute command %s\n", current->dest.command);
char *full_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);
- if (command_output->needs_tree_render)
+ if (result->needs_tree_render)
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 */
#include "shmlog.h"
// Macros to make the YAJL API a bit easier to use.
-#define y(x, ...) yajl_gen_ ## x (cmd_output->json_gen, ##__VA_ARGS__)
-#define ystr(str) yajl_gen_string(cmd_output->json_gen, (unsigned char*)str, strlen(str))
+#define y(x, ...) (cmd_output->json_gen != NULL ? yajl_gen_ ## x (cmd_output->json_gen, ##__VA_ARGS__) : 0)
+#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 { \
- y(map_open); \
- ystr("success"); \
- y(bool, success); \
- y(map_close); \
+ if (cmd_output->json_gen != NULL) { \
+ y(map_open); \
+ ystr("success"); \
+ y(bool, success); \
+ y(map_close); \
+ } \
} while (0)
#define yerror(message) do { \
- y(map_open); \
- ystr("success"); \
- y(bool, false); \
- ystr("error"); \
- ystr(message); \
- y(map_close); \
+ if (cmd_output->json_gen != NULL) { \
+ y(map_open); \
+ ystr("success"); \
+ y(bool, false); \
+ ystr("error"); \
+ ystr(message); \
+ y(map_close); \
+ } \
} while (0)
/** When the command did not include match criteria (!), we use the currently
#include "all.h"
// Macros to make the YAJL API a bit easier to use.
-#define y(x, ...) yajl_gen_ ## x (command_output.json_gen, ##__VA_ARGS__)
-#define ystr(str) yajl_gen_string(command_output.json_gen, (unsigned char*)str, strlen(str))
+#define y(x, ...) (command_output.json_gen != NULL ? yajl_gen_ ## x (command_output.json_gen, ##__VA_ARGS__) : 0)
+#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
}
}
-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);
state = INITIAL;
+ CommandResult *result = scalloc(sizeof(CommandResult));
/* A YAJL JSON generator used for formatting replies. */
- command_output.json_gen = yajl_gen_alloc(NULL);
+ command_output.json_gen = gen;
y(array_open);
command_output.needs_tree_render = false;
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(map_close);
free(position);
- free(errormessage);
clear_stack();
break;
}
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);
}
/*******************************************************************************
fprintf(stderr, "Syntax: %s <command>\n", argv[0]);
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
char *command = scalloc(message_size + 1);
strncpy(command, (const char*)message, message_size);
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);
- if (command_output->needs_tree_render)
+ if (result->needs_tree_render)
tree_render();
+ command_result_free(result);
+
const unsigned char *reply;
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,
(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) {
if (bind == NULL)
return;
+ yajl_gen gen = yajl_gen_alloc(NULL);
+
char *command_copy = sstrdup(bind->command);
- struct CommandResultIR *command_output = parse_command(command_copy);
+ CommandResult *result = parse_command(command_copy, gen);
free(command_copy);
- if (command_output->needs_tree_render)
+ if (result->needs_tree_render)
tree_render();
+ command_result_free(result);
+
/* We parse the JSON reply to figure out whether there was an error
* ("success" being false in on of the returned dictionaries). */
const unsigned char *reply;
size_t length;
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;
parse_error_key = false;
yajl_free(handle);
- yajl_gen_free(command_output->json_gen);
+ yajl_gen_free(gen);
}