diff --git a/config.c b/config.c index a367ed88..c99dd21f 100644 --- a/config.c +++ b/config.c @@ -501,29 +501,59 @@ str_to_pt_or_px(const char *s, struct pt_or_px *res, struct config *conf, return true; } + +static void NOINLINE +free_spawn_template(struct config_spawn_template *template) +{ + if (template->argv == NULL) + return; + + for (char **argv = template->argv; *argv != NULL; argv++) + free(*argv); + free(template->argv); + template->argv = NULL; +} + +static void NOINLINE +clone_spawn_template(struct config_spawn_template *dst, + const struct config_spawn_template *src) +{ + if (src->argv == NULL) { + dst->argv = NULL; + return; + } + + size_t count = 0; + for (char **argv = src->argv; *argv != NULL; argv++) + count++; + + dst->argv = xmalloc((count + 1) * sizeof(dst->argv[0])); + for (char **argv_src = src->argv, **argv_dst = dst->argv; + *argv_src != NULL; argv_src++, + argv_dst++) + { + *argv_dst = xstrdup(*argv_src); + } + dst->argv[count] = NULL; +} + static bool NOINLINE str_to_spawn_template(struct config *conf, const char *s, struct config_spawn_template *template, const char *path, int lineno, const char *section, const char *key) { - free(template->raw_cmd); - free(template->argv); + free_spawn_template(template); - template->raw_cmd = NULL; - template->argv = NULL; - - char *raw_cmd = xstrdup(s); char **argv = NULL; - if (!tokenize_cmdline(raw_cmd, &argv)) { + if (!tokenize_cmdline(s, &argv)) { LOG_AND_NOTIFY_ERR( "%s:%d: [%s]: %s: syntax error in command line", path, lineno, section, key); return false; } - template->raw_cmd = raw_cmd; template->argv = argv; return true; } @@ -2594,7 +2624,6 @@ config_load(struct config *conf, const char *conf_path, .urgent = false, .notify = false, .command = { - .raw_cmd = NULL, .argv = NULL, }, .command_focused = false, @@ -2671,7 +2700,6 @@ config_load(struct config *conf, const char *conf_path, .selection_target = SELECTION_TARGET_PRIMARY, .hold_at_exit = false, .notify = { - .raw_cmd = NULL, .argv = NULL, }, @@ -2717,12 +2745,9 @@ config_load(struct config *conf, const char *conf_path, } } - conf->notify.raw_cmd = xstrdup( - "notify-send -a ${app-id} -i ${app-id} ${title} ${body}"); - tokenize_cmdline(conf->notify.raw_cmd, &conf->notify.argv); - - conf->url.launch.raw_cmd = xstrdup("xdg-open ${url}"); - tokenize_cmdline(conf->url.launch.raw_cmd, &conf->url.launch.argv); + tokenize_cmdline("notify-send -a ${app-id} -i ${app-id} ${title} ${body}", + &conf->notify.argv); + tokenize_cmdline("xdg-open ${url}", &conf->url.launch.argv); static const wchar_t *url_protocols[] = { L"http://", @@ -2847,13 +2872,6 @@ config_override_apply(struct config *conf, config_override_t *overrides, bool er return true; } -static void NOINLINE -free_spawn_template(struct config_spawn_template *template) -{ - free(template->raw_cmd); - free(template->argv); -} - static void NOINLINE binding_pipe_free(struct config_binding_pipe *pipe) { diff --git a/config.h b/config.h index bdb1a109..a82a0cd1 100644 --- a/config.h +++ b/config.h @@ -63,7 +63,6 @@ DEFINE_LIST(struct config_mouse_binding); typedef tll(char *) config_override_t; struct config_spawn_template { - char *raw_cmd; char **argv; }; diff --git a/slave.c b/slave.c index 8e800214..ba2d0867 100644 --- a/slave.c +++ b/slave.c @@ -293,9 +293,7 @@ slave_spawn(int ptmx, int argc, const char *cwd, char *const *argv, char **shell_argv = NULL; if (argc == 0) { - char *shell_copy = xstrdup(conf_shell); - if (!tokenize_cmdline(shell_copy, &_shell_argv)) { - free(shell_copy); + if (!tokenize_cmdline(conf_shell, &_shell_argv)) { (void)!write(fork_pipe[1], &errno, sizeof(errno)); _exit(0); } diff --git a/tokenize.c b/tokenize.c index 35d52345..e29fed58 100644 --- a/tokenize.c +++ b/tokenize.c @@ -6,9 +6,10 @@ #define LOG_MODULE "tokenize" #define LOG_ENABLE_DBG 0 #include "log.h" +#include "xmalloc.h" static bool -push_argv(char ***argv, size_t *size, char *arg, size_t *argc) +push_argv(char ***argv, size_t *size, const char *arg, size_t len, size_t *argc) { if (arg != NULL && arg[0] == '%') return true; @@ -24,21 +25,23 @@ push_argv(char ***argv, size_t *size, char *arg, size_t *argc) *size = new_size; } - (*argv)[(*argc)++] = arg; + (*argv)[(*argc)++] = arg != NULL ? xstrndup(arg, len) : NULL; return true; } bool -tokenize_cmdline(char *cmdline, char ***argv) +tokenize_cmdline(const char *cmdline, char ***argv) { *argv = NULL; size_t argv_size = 0; + const char *final_end = cmdline + strlen(cmdline) + 1; + bool first_token_is_quoted = cmdline[0] == '"' || cmdline[0] == '\''; char delim = first_token_is_quoted ? cmdline[0] : ' '; - char *p = first_token_is_quoted ? &cmdline[1] : &cmdline[0]; - char *search_start = p; + const char *p = first_token_is_quoted ? &cmdline[1] : &cmdline[0]; + const char *search_start = p; size_t idx = 0; while (*p != '\0') { @@ -51,8 +54,8 @@ tokenize_cmdline(char *cmdline, char ***argv) return false; } - if (!push_argv(argv, &argv_size, p, &idx) || - !push_argv(argv, &argv_size, NULL, &idx)) + if (!push_argv(argv, &argv_size, p, final_end - p, &idx) || + !push_argv(argv, &argv_size, NULL, 0, &idx)) { goto err; } else @@ -68,9 +71,9 @@ tokenize_cmdline(char *cmdline, char ***argv) continue; } - *end = '\0'; + //*end = '\0'; - if (!push_argv(argv, &argv_size, p, &idx)) + if (!push_argv(argv, &argv_size, p, end - p, &idx)) goto err; p = end + 1; @@ -88,7 +91,7 @@ tokenize_cmdline(char *cmdline, char ***argv) search_start = p; } - if (!push_argv(argv, &argv_size, NULL, &idx)) + if (!push_argv(argv, &argv_size, NULL, 0, &idx)) goto err; return true; diff --git a/tokenize.h b/tokenize.h index f9579255..9e5de6c9 100644 --- a/tokenize.h +++ b/tokenize.h @@ -2,4 +2,4 @@ #include -bool tokenize_cmdline(char *cmdline, char ***argv); +bool tokenize_cmdline(const char *cmdline, char ***argv);