From 88d6dc2ef7ebee4b04b079455727034a0f594aae Mon Sep 17 00:00:00 2001 From: Jeinzi Date: Sat, 1 Sep 2018 00:34:50 +0200 Subject: Added support for multiple commands per bind. --- src/binds.c | 34 ++++++++++++++++++---------------- src/binds.h | 2 +- src/commands.c | 36 +++++++++++++++++++++--------------- src/commands.h | 2 +- src/imv.c | 21 ++++++++++++++------- 5 files changed, 55 insertions(+), 40 deletions(-) diff --git a/src/binds.c b/src/binds.c index 1649537..a710278 100644 --- a/src/binds.c +++ b/src/binds.c @@ -5,7 +5,7 @@ struct bind_node { char *key; /* input key to reach this node */ - char *command; /* command to run for this node, or NULL if not leaf node */ + struct list *commands; /* commands to run for this node, or NULL if not leaf node */ struct list *suffixes; /* list of bind_node* suffixes, or NULL if leaf node */ }; @@ -24,7 +24,7 @@ static int compare_node_key(const void* item, const void *key) static void init_bind_node(struct bind_node *bn) { bn->key = NULL; - bn->command = NULL; + bn->commands = NULL; bn->suffixes = list_create(); } @@ -34,7 +34,9 @@ static void destroy_bind_node(struct bind_node *bn) destroy_bind_node(bn->suffixes->items[i]); } free(bn->key); - free(bn->command); + if(bn->commands) { + list_deep_free(bn->commands); + } list_deep_free(bn->suffixes); } @@ -69,7 +71,7 @@ enum bind_result imv_binds_add(struct imv_binds *binds, const struct list *keys, struct bind_node *node = &binds->bind_tree; for(size_t i = 0; i < keys->len; ++i) { /* If we've reached a node that already has a command, there's a conflict */ - if(node->command) { + if(node->commands) { result = BIND_INVALID_COMMAND; break; } @@ -90,15 +92,14 @@ enum bind_result imv_binds_add(struct imv_binds *binds, const struct list *keys, /* We've now found the correct node for this key */ /* Check if the node has a command */ - if(next_node->command) { + if(next_node->commands) { if(i + 1 < keys->len) { /* If we're not at the end, it's a conflict */ result = BIND_CONFLICTS; break; } else { - /* Otherwise we just need to overwrite the existing bind. */ - free(next_node->command); - next_node->command = strdup(command); + /* Otherwise we just need to append a new command to the existing bind. */ + list_append(next_node->commands, strdup(command)); result = BIND_SUCCESS; break; } @@ -110,7 +111,8 @@ enum bind_result imv_binds_add(struct imv_binds *binds, const struct list *keys, if(next_node->suffixes->len > 0) { result = BIND_CONFLICTS; } else { - next_node->command = strdup(command); + next_node->commands = list_create(); + list_append(next_node->commands, strdup(command)); } } else { /* Otherwise, move down the trie */ @@ -133,7 +135,7 @@ enum lookup_result { LOOKUP_MATCH, }; -static enum lookup_result bind_lookup(struct bind_node *node, struct list *keys, const char **out_str) +static enum lookup_result bind_lookup(struct bind_node *node, struct list *keys, struct list **out_list) { for(size_t part = 0; part < keys->len; ++part) { const char* cur_key = keys->items[part]; @@ -151,8 +153,8 @@ static enum lookup_result bind_lookup(struct bind_node *node, struct list *keys, } } - if(node->command) { - *out_str = node->command; + if(node->commands) { + *out_list = node->commands; return LOOKUP_MATCH; } return LOOKUP_PARTIAL; @@ -216,7 +218,7 @@ void imv_bind_clear_input(struct imv_binds *binds) binds->keys = list_create(); } -const char *imv_bind_handle_event(struct imv_binds *binds, const SDL_Event *event) +struct list *imv_bind_handle_event(struct imv_binds *binds, const SDL_Event *event) { if(event->key.keysym.sym == SDLK_ESCAPE) { imv_bind_clear_input(binds); @@ -230,13 +232,13 @@ const char *imv_bind_handle_event(struct imv_binds *binds, const SDL_Event *even } list_append(binds->keys, strdup(buffer)); - const char *command = NULL; - enum lookup_result result = bind_lookup(&binds->bind_tree, binds->keys, &command); + struct list *commands = NULL; + enum lookup_result result = bind_lookup(&binds->bind_tree, binds->keys, &commands); if(result == LOOKUP_PARTIAL) { return NULL; } else if(result == LOOKUP_MATCH) { imv_bind_clear_input(binds); - return command; + return commands; } else if(result == LOOKUP_INVALID) { imv_bind_clear_input(binds); return NULL; diff --git a/src/binds.h b/src/binds.h index 05810d8..a720fe1 100644 --- a/src/binds.h +++ b/src/binds.h @@ -32,7 +32,7 @@ const struct list *imv_bind_input_buffer(struct imv_binds *binds); void imv_bind_clear_input(struct imv_binds *binds); /* Handle an input event, if a bind is triggered, return its command */ -const char *imv_bind_handle_event(struct imv_binds *binds, const SDL_Event *event); +struct list *imv_bind_handle_event(struct imv_binds *binds, const SDL_Event *event); /* Convert a string (such as from a config) to a key list */ struct list *imv_bind_parse_keys(const char *keys); diff --git a/src/commands.c b/src/commands.c index 7dfbc2c..2bc33fe 100644 --- a/src/commands.c +++ b/src/commands.c @@ -46,29 +46,35 @@ void imv_command_alias(struct imv_commands *cmds, const char *command, const cha list_append(cmds->command_list, cmd); } -int imv_command_exec(struct imv_commands *cmds, const char *command, void *data) +int imv_command_exec(struct imv_commands *cmds, struct list *commands, void *data) { - struct list *args = list_from_string(command, ' '); int ret = 1; + for(size_t i = 0; i < commands->len; ++i) { + const char *command = commands->items[i]; + struct list *args = list_from_string(command, ' '); - if(args->len > 0) { - for(size_t i = 0; i < cmds->command_list->len; ++i) { - struct command *cmd = cmds->command_list->items[i]; - if(!strcmp(cmd->command, args->items[0])) { - if(cmd->handler) { - /* argstr = all args as a single string */ - const char *argstr = command + strlen(cmd->command) + 1; - cmd->handler(args, argstr, data); - ret = 0; - } else if(cmd->alias) { - ret = imv_command_exec(cmds, cmd->alias, data); + if(args->len > 0) { + for(size_t i = 0; i < cmds->command_list->len; ++i) { + struct command *cmd = cmds->command_list->items[i]; + if(!strcmp(cmd->command, args->items[0])) { + if(cmd->handler) { + /* argstr = all args as a single string */ + const char *argstr = command + strlen(cmd->command) + 1; + cmd->handler(args, argstr, data); + ret = 0; + } else if(cmd->alias) { + struct list *commands = list_create(); + list_append(commands, cmd->alias); + ret = imv_command_exec(cmds, commands, data); + list_free(commands); + } + break; } - break; } } + list_deep_free(args); } - list_deep_free(args); return ret; } diff --git a/src/commands.h b/src/commands.h index cf3a728..256018e 100644 --- a/src/commands.h +++ b/src/commands.h @@ -11,7 +11,7 @@ struct imv_commands *imv_commands_create(void); void imv_commands_free(struct imv_commands *cmds); void imv_command_register(struct imv_commands *cmds, const char *command, void (*handler)(struct list*, const char*, void*)); void imv_command_alias(struct imv_commands *cmds, const char *command, const char *alias); -int imv_command_exec(struct imv_commands *cmds, const char *command, void *data); +int imv_command_exec(struct imv_commands *cmds, struct list *commands, void *data); #endif diff --git a/src/imv.c b/src/imv.c index dc3dedf..768ae21 100644 --- a/src/imv.c +++ b/src/imv.c @@ -760,10 +760,14 @@ static void handle_event(struct imv *imv, SDL_Event *event) } switch(event->type) { - case SDL_QUIT: - imv_command_exec(imv->commands, "quit", imv); + case SDL_QUIT: { + /* new scope needed in order to declare variables in a switch statement */ + struct list *commands = list_create(); + list_append(commands, "quit"); + imv_command_exec(imv->commands, commands, imv); + list_free(commands); break; - + } case SDL_TEXTINPUT: strncat(imv->input_buffer, event->text.text, command_buffer_len - 1); imv->need_redraw = true; @@ -780,8 +784,11 @@ static void handle_event(struct imv *imv, SDL_Event *event) imv->input_buffer = NULL; imv->need_redraw = true; } else if(event->key.keysym.sym == SDLK_RETURN) { - imv_command_exec(imv->commands, imv->input_buffer, imv); + struct list *commands = list_create(); + list_append(commands, imv->input_buffer); + imv_command_exec(imv->commands, commands, imv); SDL_StopTextInput(); + list_free(commands); free(imv->input_buffer); imv->input_buffer = NULL; imv->need_redraw = true; @@ -806,9 +813,9 @@ static void handle_event(struct imv *imv, SDL_Event *event) } break; default: { /* braces to allow const char *cmd definition */ - const char *cmd = imv_bind_handle_event(imv->binds, event); - if(cmd) { - imv_command_exec(imv->commands, cmd, imv); + struct list *cmds = imv_bind_handle_event(imv->binds, event); + if(cmds) { + imv_command_exec(imv->commands, cmds, imv); } } } -- cgit v1.2.3 From b5e646615e42a1f6991c7424c639faf2c4b49d52 Mon Sep 17 00:00:00 2001 From: Jeinzi Date: Sat, 1 Sep 2018 03:33:22 +0200 Subject: Adapted documentation. --- README.md | 7 ++++--- doc/imv.5.txt | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 12e3a1d..fd139d2 100644 --- a/README.md +++ b/README.md @@ -51,15 +51,16 @@ you like. In your imv config: [binds] - = exec rm $imv_current_file + = exec rm "$imv_current_file" + = close -Then press 'X' within imv to delete the image. +Then press 'X' within imv to delete the image and close it. #### Rotate an image In your imv config: [binds] - = exec mogrify -rotate 90 $imv_current_file + = exec mogrify -rotate 90 "$imv_current_file" Then press 'R' within imv to rotate the image 90 degrees using imagemagick. diff --git a/doc/imv.5.txt b/doc/imv.5.txt index cb12eb3..8c376a6 100644 --- a/doc/imv.5.txt +++ b/doc/imv.5.txt @@ -96,7 +96,8 @@ Binds The *[binds]* section allows custom key bindings to be added to imv. Binds are in the format 'key combination = command'. A key combination can -consist of multiple keys in succession. +consist of multiple keys in succession. If there is more then one command +defined for a given key combination, they are executed one after another. Single keys such as 'q' are just that: 'q = quit' will bind the 'q' key to the 'quit' command. -- cgit v1.2.3 From 3974eaebe657b989ce55a85fc24bc7fd09e67c00 Mon Sep 17 00:00:00 2001 From: Jeinzi Date: Sat, 1 Sep 2018 03:33:33 +0200 Subject: Fixed several memory leaks. --- src/binds.c | 3 ++- src/imv.c | 9 ++++++++- src/list.c | 1 + 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/binds.c b/src/binds.c index a710278..9e268b4 100644 --- a/src/binds.c +++ b/src/binds.c @@ -51,6 +51,7 @@ struct imv_binds *imv_binds_create(void) void imv_binds_free(struct imv_binds *binds) { destroy_bind_node(&binds->bind_tree); + list_deep_free(binds->keys); free(binds); } @@ -83,7 +84,7 @@ enum bind_result imv_binds_add(struct imv_binds *binds, const struct list *keys, /* Create our new node */ next_node = malloc(sizeof(struct bind_node)); init_bind_node(next_node); - next_node->key = strdup(keys->items[i]); + next_node->key = keys->items[i]; list_append(node->suffixes, next_node); } else { next_node = node->suffixes->items[child_index]; diff --git a/src/imv.c b/src/imv.c index 768ae21..674283f 100644 --- a/src/imv.c +++ b/src/imv.c @@ -129,6 +129,7 @@ static const char *add_bind(struct imv *imv, const char *keys, const char *comma } enum bind_result result = imv_binds_add(imv->binds, list, command); + list_free(list); if (result == BIND_SUCCESS) { return NULL; @@ -244,10 +245,14 @@ struct imv *imv_create(void) void imv_free(struct imv *imv) { free(imv->font_name); + free(imv->title_text); + free(imv->overlay_text); imv_binds_free(imv->binds); imv_navigator_free(imv->navigator); imv_loader_free(imv->loader); imv_commands_free(imv->commands); + imv_viewport_free(imv->view); + imv_image_free(imv->image); if(imv->stdin_image_data) { free(imv->stdin_image_data); } @@ -928,6 +933,7 @@ static char *get_config_path(void) wordexp_t word; if(wordexp(config_paths[i], &word, 0) == 0) { if (!word.we_wordv[0]) { + wordfree(&word); continue; } @@ -1073,7 +1079,7 @@ static int handle_ini_value(void *user, const char *section, const char *name, bool imv_load_config(struct imv *imv) { - const char *path = get_config_path(); + char *path = get_config_path(); if(!path) { /* no config, no problem - we have defaults */ return true; @@ -1087,6 +1093,7 @@ bool imv_load_config(struct imv *imv) fprintf(stderr, "Error in config file: %s:%d\n", path, err); return false; } + free(path); return true; } diff --git a/src/list.c b/src/list.c index 0bc3b7e..4cd7f24 100644 --- a/src/list.c +++ b/src/list.c @@ -12,6 +12,7 @@ struct list *list_create(void) void list_free(struct list *list) { free(list->items); + free(list); } void list_deep_free(struct list *list) -- cgit v1.2.3 From a8fc50025e2c3470b0ad9e63d6e9f1bc32ff5e8a Mon Sep 17 00:00:00 2001 From: Jeinzi Date: Sat, 1 Sep 2018 04:14:04 +0200 Subject: Fixed name conflicts. --- src/commands.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/commands.c b/src/commands.c index 2bc33fe..a989a7c 100644 --- a/src/commands.c +++ b/src/commands.c @@ -54,8 +54,8 @@ int imv_command_exec(struct imv_commands *cmds, struct list *commands, void *dat struct list *args = list_from_string(command, ' '); if(args->len > 0) { - for(size_t i = 0; i < cmds->command_list->len; ++i) { - struct command *cmd = cmds->command_list->items[i]; + for(size_t j = 0; j < cmds->command_list->len; ++j) { + struct command *cmd = cmds->command_list->items[j]; if(!strcmp(cmd->command, args->items[0])) { if(cmd->handler) { /* argstr = all args as a single string */ @@ -63,10 +63,10 @@ int imv_command_exec(struct imv_commands *cmds, struct list *commands, void *dat cmd->handler(args, argstr, data); ret = 0; } else if(cmd->alias) { - struct list *commands = list_create(); - list_append(commands, cmd->alias); - ret = imv_command_exec(cmds, commands, data); - list_free(commands); + struct list *command_list = list_create(); + list_append(command_list, cmd->alias); + ret = imv_command_exec(cmds, command_list, data); + list_free(command_list); } break; } -- cgit v1.2.3 From 51837d93572fe229275d239c7a8d4113ef81ea38 Mon Sep 17 00:00:00 2001 From: Jeinzi Date: Thu, 27 Sep 2018 00:53:17 +0200 Subject: Implemented imv_command_exec_list(). --- AUTHORS | 1 + src/commands.c | 46 +++++++++++++++++++++++++--------------------- src/commands.h | 3 ++- src/imv.c | 13 ++++--------- 4 files changed, 32 insertions(+), 31 deletions(-) diff --git a/AUTHORS b/AUTHORS index 99eb671..b88acf6 100644 --- a/AUTHORS +++ b/AUTHORS @@ -6,6 +6,7 @@ People who have contributed to imv: * Dmitrij D. Czarkoff * Jose Diez * Kenneth Hanley + * Julian Heinzel * Hannes Körber * Aleksandra Kosiacka * Michal Koutenský diff --git a/src/commands.c b/src/commands.c index a989a7c..0fb8b46 100644 --- a/src/commands.c +++ b/src/commands.c @@ -46,35 +46,39 @@ void imv_command_alias(struct imv_commands *cmds, const char *command, const cha list_append(cmds->command_list, cmd); } -int imv_command_exec(struct imv_commands *cmds, struct list *commands, void *data) +int imv_command_exec(struct imv_commands *cmds, const char *command, void *data) { + struct list *args = list_from_string(command, ' '); int ret = 1; - for(size_t i = 0; i < commands->len; ++i) { - const char *command = commands->items[i]; - struct list *args = list_from_string(command, ' '); - if(args->len > 0) { - for(size_t j = 0; j < cmds->command_list->len; ++j) { - struct command *cmd = cmds->command_list->items[j]; - if(!strcmp(cmd->command, args->items[0])) { - if(cmd->handler) { - /* argstr = all args as a single string */ - const char *argstr = command + strlen(cmd->command) + 1; - cmd->handler(args, argstr, data); - ret = 0; - } else if(cmd->alias) { - struct list *command_list = list_create(); - list_append(command_list, cmd->alias); - ret = imv_command_exec(cmds, command_list, data); - list_free(command_list); - } - break; + if(args->len > 0) { + for(size_t i = 0; i < cmds->command_list->len; ++i) { + struct command *cmd = cmds->command_list->items[i]; + if(!strcmp(cmd->command, args->items[0])) { + if(cmd->handler) { + /* argstr = all args as a single string */ + const char *argstr = command + strlen(cmd->command) + 1; + cmd->handler(args, argstr, data); + ret = 0; + } else if(cmd->alias) { + ret = imv_command_exec(cmds, cmd->alias, data); } + break; } } - list_deep_free(args); } + list_deep_free(args); + return ret; +} + +int imv_command_exec_list(struct imv_commands *cmds, struct list *commands, void *data) +{ + int ret = 0; + for(size_t i = 0; i < commands->len; ++i) { + const char *command = commands->items[i]; + ret += imv_command_exec(cmds, command, data); + } return ret; } diff --git a/src/commands.h b/src/commands.h index 256018e..cf81f68 100644 --- a/src/commands.h +++ b/src/commands.h @@ -11,7 +11,8 @@ struct imv_commands *imv_commands_create(void); void imv_commands_free(struct imv_commands *cmds); void imv_command_register(struct imv_commands *cmds, const char *command, void (*handler)(struct list*, const char*, void*)); void imv_command_alias(struct imv_commands *cmds, const char *command, const char *alias); -int imv_command_exec(struct imv_commands *cmds, struct list *commands, void *data); +int imv_command_exec(struct imv_commands *cmds, const char *command, void *data); +int imv_command_exec_list(struct imv_commands *cmds, struct list *commands, void *data); #endif diff --git a/src/imv.c b/src/imv.c index 674283f..fd239bb 100644 --- a/src/imv.c +++ b/src/imv.c @@ -765,14 +765,9 @@ static void handle_event(struct imv *imv, SDL_Event *event) } switch(event->type) { - case SDL_QUIT: { - /* new scope needed in order to declare variables in a switch statement */ - struct list *commands = list_create(); - list_append(commands, "quit"); - imv_command_exec(imv->commands, commands, imv); - list_free(commands); + case SDL_QUIT: + imv_command_exec(imv->commands, "quit", imv); break; - } case SDL_TEXTINPUT: strncat(imv->input_buffer, event->text.text, command_buffer_len - 1); imv->need_redraw = true; @@ -791,7 +786,7 @@ static void handle_event(struct imv *imv, SDL_Event *event) } else if(event->key.keysym.sym == SDLK_RETURN) { struct list *commands = list_create(); list_append(commands, imv->input_buffer); - imv_command_exec(imv->commands, commands, imv); + imv_command_exec_list(imv->commands, commands, imv); SDL_StopTextInput(); list_free(commands); free(imv->input_buffer); @@ -820,7 +815,7 @@ static void handle_event(struct imv *imv, SDL_Event *event) default: { /* braces to allow const char *cmd definition */ struct list *cmds = imv_bind_handle_event(imv->binds, event); if(cmds) { - imv_command_exec(imv->commands, cmds, imv); + imv_command_exec_list(imv->commands, cmds, imv); } } } -- cgit v1.2.3