From 7502cb3adbb26a2f94445a35626e64041d6769f9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 4 Jan 2011 00:42:46 +0000 Subject: Clean up and simplify tmux command argument parsing. Originally, tmux commands were parsed in the client process into a struct with the command data which was then serialised and sent to the server to be executed. The parsing was later moved into the server (an argv was sent from the client), but the parse step and intermediate struct was kept. This change removes that struct and the separate parse step. Argument parsing and printing is now common to all commands (in arguments.c) with each command left with just an optional check function (to validate the arguments at parse time), the exec function and a function to set up any key bindings (renamed from the old init function). This is overall more simple and consistent. There should be no changes to any commands behaviour or syntax although as this touches every command please watch for any unexpected changes. --- Makefile | 4 +- arguments.c | 222 +++++++++++++++++++++++++ cmd-attach-session.c | 32 ++-- cmd-bind-key.c | 179 +++++--------------- cmd-break-pane.c | 19 +-- cmd-capture-pane.c | 133 +++------------ cmd-choose-buffer.c | 23 ++- cmd-choose-client.c | 19 +-- cmd-choose-session.c | 19 +-- cmd-choose-window.c | 19 +-- cmd-clear-history.c | 15 +- cmd-clock-mode.c | 15 +- cmd-command-prompt.c | 150 ++++------------- cmd-confirm-before.c | 35 ++-- cmd-copy-mode.c | 34 ++-- cmd-delete-buffer.c | 31 ++-- cmd-detach-client.c | 17 +- cmd-display-message.c | 21 ++- cmd-display-panes.c | 17 +- cmd-find-window.c | 25 +-- cmd-generic.c | 414 ---------------------------------------------- cmd-has-session.c | 15 +- cmd-if-shell.c | 17 +- cmd-join-pane.c | 198 +++++----------------- cmd-kill-pane.c | 17 +- cmd-kill-server.c | 7 +- cmd-kill-session.c | 17 +- cmd-kill-window.c | 17 +- cmd-last-pane.c | 19 +-- cmd-last-window.c | 17 +- cmd-link-window.c | 29 ++-- cmd-list-buffers.c | 7 +- cmd-list-clients.c | 7 +- cmd-list-commands.c | 7 +- cmd-list-keys.c | 23 +-- cmd-list-panes.c | 15 +- cmd-list-sessions.c | 10 +- cmd-list-windows.c | 21 ++- cmd-load-buffer.c | 78 +++++---- cmd-lock-client.c | 17 +- cmd-lock-server.c | 7 +- cmd-lock-session.c | 17 +- cmd-move-window.c | 29 ++-- cmd-new-session.c | 177 +++++--------------- cmd-new-window.c | 169 +++---------------- cmd-next-layout.c | 19 +-- cmd-next-window.c | 33 ++-- cmd-paste-buffer.c | 190 +++++---------------- cmd-pipe-pane.c | 21 ++- cmd-previous-layout.c | 19 +-- cmd-previous-window.c | 33 ++-- cmd-refresh-client.c | 17 +- cmd-rename-session.c | 25 +-- cmd-rename-window.c | 21 ++- cmd-resize-pane.c | 98 +++++------ cmd-respawn-window.c | 25 +-- cmd-rotate-window.c | 29 ++-- cmd-run-shell.c | 17 +- cmd-save-buffer.c | 52 +++--- cmd-select-layout.c | 73 ++++---- cmd-select-pane.c | 45 +++-- cmd-select-window.c | 31 ++-- cmd-send-keys.c | 124 ++------------ cmd-send-prefix.c | 15 +- cmd-server-info.c | 7 +- cmd-set-buffer.c | 37 +++-- cmd-set-environment.c | 46 +++--- cmd-set-option.c | 205 ++++++++++++----------- cmd-set-window-option.c | 13 +- cmd-show-buffer.c | 29 ++-- cmd-show-environment.c | 23 ++- cmd-show-messages.c | 23 ++- cmd-show-options.c | 25 ++- cmd-show-window-options.c | 15 +- cmd-source-file.c | 97 ++--------- cmd-split-window.c | 218 ++++++------------------ cmd-start-server.c | 7 +- cmd-suspend-client.c | 17 +- cmd-swap-pane.c | 44 ++--- cmd-swap-window.c | 22 +-- cmd-switch-client.c | 152 +++-------------- cmd-unbind-key.c | 126 ++++---------- cmd-unlink-window.c | 17 +- cmd.c | 58 +++---- key-bindings.c | 7 +- tmux.h | 117 +++++-------- 86 files changed, 1607 insertions(+), 2965 deletions(-) create mode 100644 arguments.c delete mode 100644 cmd-generic.c diff --git a/Makefile b/Makefile index 86b28b60..0f7f403e 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,13 @@ # $OpenBSD$ PROG= tmux -SRCS= attributes.c cfg.c client.c clock.c \ +SRCS= arguments.c attributes.c cfg.c client.c clock.c \ cmd-attach-session.c cmd-bind-key.c \ cmd-break-pane.c cmd-choose-session.c cmd-choose-window.c \ cmd-clear-history.c cmd-clock-mode.c cmd-command-prompt.c \ cmd-confirm-before.c cmd-copy-mode.c \ cmd-choose-buffer.c cmd-delete-buffer.c cmd-detach-client.c \ - cmd-find-window.c cmd-generic.c cmd-has-session.c cmd-kill-pane.c \ + cmd-find-window.c cmd-has-session.c cmd-kill-pane.c \ cmd-kill-server.c cmd-kill-session.c cmd-kill-window.c \ cmd-last-pane.c cmd-last-window.c cmd-link-window.c cmd-list-buffers.c \ cmd-list-clients.c cmd-list-commands.c cmd-list-keys.c \ diff --git a/arguments.c b/arguments.c new file mode 100644 index 00000000..ebd09580 --- /dev/null +++ b/arguments.c @@ -0,0 +1,222 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2010 Nicholas Marriott + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include +#include + +#include "tmux.h" + +/* Create an arguments set with no flags. */ +struct args * +args_create(int argc, ...) +{ + struct args *args; + va_list ap; + int i; + + args = xcalloc(1, sizeof *args); + if ((args->flags = bit_alloc(SCHAR_MAX)) == NULL) + fatal("bit_alloc failed"); + + args->argc = argc; + if (argc == 0) + args->argv = NULL; + else + args->argv = xcalloc(argc, sizeof **args->argv); + + va_start(ap, argc); + for (i = 0; i < argc; i++) + args->argv[i] = xstrdup(va_arg(ap, char *)); + va_end(ap); + + return (args); +} + +/* Parse an argv and argc into a new argument set. */ +struct args * +args_parse(const char *template, int argc, char **argv) +{ + struct args *args; + char *ptr; + int opt; + + args = xcalloc(1, sizeof *args); + if ((args->flags = bit_alloc(SCHAR_MAX)) == NULL) + fatal("bit_alloc failed"); + + optreset = 1; + optind = 1; + + while ((opt = getopt(argc, argv, template)) != -1) { + if (opt < 0 || opt >= SCHAR_MAX) + continue; + if (opt == '?' || (ptr = strchr(template, opt)) == NULL) { + xfree(args->flags); + xfree(args); + return (NULL); + } + + bit_set(args->flags, opt); + if (ptr[1] == ':') { + if (args->values[opt] != NULL) + xfree(args->values[opt]); + args->values[opt] = xstrdup(optarg); + } + } + argc -= optind; + argv += optind; + + args->argc = argc; + args->argv = cmd_copy_argv(argc, argv); + + return (args); +} + +/* Free an arguments set. */ +void +args_free(struct args *args) +{ + u_int i; + + cmd_free_argv(args->argc, args->argv); + + for (i = 0; i < SCHAR_MAX; i++) { + if (args->values[i] != NULL) + xfree(args->values[i]); + } + + xfree(args->flags); + xfree(args); +} + +/* Print a set of arguments. */ +size_t +args_print(struct args *args, char *buf, size_t len) +{ + size_t off; + int i; + const char *quotes; + + /* There must be at least one byte at the start. */ + if (len == 0) + return (0); + off = 0; + + /* Process the flags first. */ + buf[off++] = '-'; + for (i = 0; i < SCHAR_MAX; i++) { + if (!bit_test(args->flags, i) || args->values[i] != NULL) + continue; + + if (off == len - 1) { + buf[off] = '\0'; + return (len); + } + buf[off++] = i; + buf[off] = '\0'; + } + if (off == 1) + buf[--off] = '\0'; + + /* Then the flags with arguments. */ + for (i = 0; i < SCHAR_MAX; i++) { + if (!bit_test(args->flags, i) || args->values[i] == NULL) + continue; + + if (off >= len) { + /* snprintf will have zero terminated. */ + return (len); + } + + if (strchr(args->values[i], ' ') != NULL) + quotes = "\""; + else + quotes = ""; + off += xsnprintf(buf + off, len - off, "%s-%c %s%s%s", + off != 0 ? " " : "", i, quotes, args->values[i], quotes); + } + + /* And finally the argument vector. */ + for (i = 0; i < args->argc; i++) { + if (off >= len) { + /* snprintf will have zero terminated. */ + return (len); + } + + if (strchr(args->argv[i], ' ') != NULL) + quotes = "\""; + else + quotes = ""; + off += xsnprintf(buf + off, len - off, "%s%s%s%s", + off != 0 ? " " : "", quotes, args->argv[i], quotes); + } + + return (off); +} + +/* Return if an argument is present. */ +int +args_has(struct args *args, u_char ch) +{ + return (bit_test(args->flags, ch)); +} + +/* Set argument value. */ +void +args_set(struct args *args, u_char ch, const char *value) +{ + if (value != NULL) { + if (args->values[ch] != NULL) + xfree(args->values[ch]); + args->values[ch] = xstrdup(value); + } + bit_set(args->flags, ch); +} + +/* Get argument value. Will be NULL if it isn't present. */ +const char * +args_get(struct args *args, u_char ch) +{ + return (args->values[ch]); +} + +/* Convert an argument value to a number. */ +long long +args_strtonum(struct args *args, + u_char ch, long long minval, long long maxval, char **cause) +{ + const char *errstr; + long long ll; + + if (!args_has(args, ch)) { + *cause = xstrdup("missing"); + return (0); + } + + ll = strtonum(args->values[ch], minval, maxval, &errstr); + if (errstr != NULL) { + *cause = xstrdup(errstr); + return (0); + } + + *cause = NULL; + return (ll); +} diff --git a/cmd-attach-session.c b/cmd-attach-session.c index 45a49f2b..f320056d 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -28,37 +28,37 @@ int cmd_attach_session_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_attach_session_entry = { "attach-session", "attach", + "drt:", 0, 0, "[-dr] " CMD_TARGET_SESSION_USAGE, - CMD_CANTNEST|CMD_STARTSERVER|CMD_SENDENVIRON, "dr", - cmd_target_init, - cmd_target_parse, - cmd_attach_session_exec, - cmd_target_free, - cmd_target_print + CMD_CANTNEST|CMD_STARTSERVER|CMD_SENDENVIRON, + NULL, + NULL, + cmd_attach_session_exec }; int cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; - struct session *s; - struct client *c; - const char *update; - char *overrides, *cause; - u_int i; + struct args *args = self->args; + struct session *s; + struct client *c; + const char *update; + char *overrides, *cause; + u_int i; if (RB_EMPTY(&sessions)) { ctx->error(ctx, "no sessions"); return (-1); } - if ((s = cmd_find_session(ctx, data->target)) == NULL) + + if ((s = cmd_find_session(ctx, args_get(args, 't'))) == NULL) return (-1); if (ctx->cmdclient == NULL && ctx->curclient == NULL) return (0); if (ctx->cmdclient == NULL) { - if (cmd_check_flag(data->chflags, 'd')) { + if (args_has(self->args, 'd')) { /* * Can't use server_write_session in case attaching to * the same session as currently attached to. @@ -90,10 +90,10 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } - if (cmd_check_flag(data->chflags, 'r')) + if (args_has(self->args, 'r')) ctx->cmdclient->flags |= CLIENT_READONLY; - if (cmd_check_flag(data->chflags, 'd')) + if (args_has(self->args, 'd')) server_write_session(s, MSG_DETACH, NULL, 0); ctx->cmdclient->session = s; diff --git a/cmd-bind-key.c b/cmd-bind-key.c index 60887904..025f6c79 100644 --- a/cmd-bind-key.c +++ b/cmd-bind-key.c @@ -26,136 +26,87 @@ * Bind a key to a command, this recurses through cmd_*. */ -int cmd_bind_key_parse(struct cmd *, int, char **, char **); +int cmd_bind_key_check(struct args *); int cmd_bind_key_exec(struct cmd *, struct cmd_ctx *); -void cmd_bind_key_free(struct cmd *); -size_t cmd_bind_key_print(struct cmd *, char *, size_t); -int cmd_bind_key_table(struct cmd *, struct cmd_ctx *); - -struct cmd_bind_key_data { - int key; - int can_repeat; - struct cmd_list *cmdlist; - - int command_key; - char *tablename; - char *modecmd; -}; +int cmd_bind_key_table(struct cmd *, struct cmd_ctx *, int); const struct cmd_entry cmd_bind_key_entry = { "bind-key", "bind", + "cnrt:", 1, -1, "[-cnr] [-t key-table] key command [arguments]", - 0, "", + 0, NULL, - cmd_bind_key_parse, - cmd_bind_key_exec, - cmd_bind_key_free, - cmd_bind_key_print + cmd_bind_key_check, + cmd_bind_key_exec }; int -cmd_bind_key_parse(struct cmd *self, int argc, char **argv, char **cause) +cmd_bind_key_check(struct args *args) { - struct cmd_bind_key_data *data; - int opt, no_prefix = 0; - - self->data = data = xmalloc(sizeof *data); - data->can_repeat = 0; - data->cmdlist = NULL; - data->command_key = 0; - data->tablename = NULL; - data->modecmd = NULL; - - while ((opt = getopt(argc, argv, "cnrt:")) != -1) { - switch (opt) { - case 'c': - data->command_key = 1; - break; - case 'n': - no_prefix = 1; - break; - case 'r': - data->can_repeat = 1; - break; - case 't': - if (data->tablename == NULL) - data->tablename = xstrdup(optarg); - break; - default: - goto usage; - } - } - argc -= optind; - argv += optind; - if (argc < 1) - goto usage; - - if ((data->key = key_string_lookup_string(argv[0])) == KEYC_NONE) { - xasprintf(cause, "unknown key: %s", argv[0]); - goto error; - } - if (!no_prefix) - data->key |= KEYC_PREFIX; - - argc--; - argv++; - if (data->tablename != NULL) { - if (argc != 1) - goto usage; - data->modecmd = xstrdup(argv[0]); + if (args_has(args, 't')) { + if (args->argc != 1) + return (-1); } else { - if ((data->cmdlist = cmd_list_parse(argc, argv, cause)) == NULL) - goto error; + if (args->argc < 2) + return (-1); } - return (0); - -usage: - xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); - -error: - self->entry->free(self); - return (-1); } int -cmd_bind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx) +cmd_bind_key_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_bind_key_data *data = self->data; + struct args *args = self->args; + char *cause; + struct cmd_list *cmdlist; + int key; - if (data == NULL) - return (0); - if (data->tablename != NULL) - return (cmd_bind_key_table(self, ctx)); + key = key_string_lookup_string(args->argv[0]); + if (key == KEYC_NONE) { + ctx->error(ctx, "unknown key: %s", args->argv[0]); + return (-1); + } + + if (args_has(args, 't')) + return (cmd_bind_key_table(self, ctx, key)); - key_bindings_add(data->key, data->can_repeat, data->cmdlist); - data->cmdlist->references++; + cmdlist = cmd_list_parse(args->argc - 1, args->argv + 1, &cause); + if (cmdlist == NULL) { + ctx->error(ctx, "%s", cause); + xfree(cause); + return (-1); + } + if (!args_has(args, 'n')) + key |= KEYC_PREFIX; + key_bindings_add(key, args_has(args, 'r'), cmdlist); return (0); } int -cmd_bind_key_table(struct cmd *self, struct cmd_ctx *ctx) +cmd_bind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key) { - struct cmd_bind_key_data *data = self->data; + struct args *args = self->args; + const char *tablename; const struct mode_key_table *mtab; struct mode_key_binding *mbind, mtmp; enum mode_key_cmd cmd; - if ((mtab = mode_key_findtable(data->tablename)) == NULL) { - ctx->error(ctx, "unknown key table: %s", data->tablename); + tablename = args_get(args, 't'); + if ((mtab = mode_key_findtable(tablename)) == NULL) { + ctx->error(ctx, "unknown key table: %s", tablename); return (-1); } - cmd = mode_key_fromstring(mtab->cmdstr, data->modecmd); + cmd = mode_key_fromstring(mtab->cmdstr, args->argv[0]); if (cmd == MODEKEY_NONE) { - ctx->error(ctx, "unknown command: %s", data->modecmd); + ctx->error(ctx, "unknown command: %s", args->argv[0]); return (-1); } - mtmp.key = data->key & ~KEYC_PREFIX; - mtmp.mode = data->command_key ? 1 : 0; + mtmp.key = key; + mtmp.mode = !!args_has(args, 'c'); if ((mbind = SPLAY_FIND(mode_key_tree, mtab->tree, &mtmp)) != NULL) { mbind->cmd = cmd; return (0); @@ -167,45 +118,3 @@ cmd_bind_key_table(struct cmd *self, struct cmd_ctx *ctx) SPLAY_INSERT(mode_key_tree, mtab->tree, mbind); return (0); } - -void -cmd_bind_key_free(struct cmd *self) -{ - struct cmd_bind_key_data *data = self->data; - - if (data->cmdlist != NULL) - cmd_list_free(data->cmdlist); - if (data->tablename != NULL) - xfree(data->tablename); - if (data->modecmd != NULL) - xfree(data->modecmd); - xfree(data); -} - -size_t -cmd_bind_key_print(struct cmd *self, char *buf, size_t len) -{ - struct cmd_bind_key_data *data = self->data; - size_t off = 0; - const char *skey; - - off += xsnprintf(buf, len, "%s", self->entry->name); - if (data == NULL) - return (off); - - if (off < len && data->command_key) - off += xsnprintf(buf + off, len - off, " -c"); - if (off < len && !(data->key & KEYC_PREFIX)) - off += xsnprintf(buf + off, len - off, " -n"); - if (off < len && data->can_repeat) - off += xsnprintf(buf + off, len - off, " -r"); - if (off < len && data->tablename != NULL) - off += cmd_prarg(buf + off, len - off, " -t ", data->tablename); - if (off < len) { - skey = key_string_lookup_key(data->key & ~KEYC_PREFIX); - off += xsnprintf(buf + off, len - off, " %s ", skey); - } - if (off < len) - off += cmd_list_print(data->cmdlist, buf + off, len - off); - return (off); -} diff --git a/cmd-break-pane.c b/cmd-break-pane.c index d5f847fb..4c57a116 100644 --- a/cmd-break-pane.c +++ b/cmd-break-pane.c @@ -30,19 +30,18 @@ int cmd_break_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_break_pane_entry = { "break-pane", "breakp", - CMD_TARGET_PANE_USAGE " [-d]", - 0, "d", - cmd_target_init, - cmd_target_parse, - cmd_break_pane_exec, - cmd_target_free, - cmd_target_print + "dt:", 0, 0, + "[-d] " CMD_TARGET_PANE_USAGE, + 0, + NULL, + NULL, + cmd_break_pane_exec }; int cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; struct winlink *wl; struct session *s; struct window_pane *wp; @@ -50,7 +49,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx) char *cause; int base_idx; - if ((wl = cmd_find_pane(ctx, data->target, &s, &wp)) == NULL) + if ((wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp)) == NULL) return (-1); if (window_count_panes(wl->window) == 1) { @@ -74,7 +73,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx) base_idx = options_get_number(&s->options, "base-index"); wl = session_attach(s, w, -1 - base_idx, &cause); /* can't fail */ - if (!cmd_check_flag(data->chflags, 'd')) + if (!args_has(self->args, 'd')) session_select(s, wl->idx); server_redraw_session(s); diff --git a/cmd-capture-pane.c b/cmd-capture-pane.c index c711db42..6efbfe97 100644 --- a/cmd-capture-pane.c +++ b/cmd-capture-pane.c @@ -27,93 +27,30 @@ * Write the entire contents of a pane to a buffer. */ -int cmd_capture_pane_parse(struct cmd *, int, char **, char **); int cmd_capture_pane_exec(struct cmd *, struct cmd_ctx *); -void cmd_capture_pane_free(struct cmd *); -void cmd_capture_pane_init(struct cmd *, int); -size_t cmd_capture_pane_print(struct cmd *, char *, size_t); - -struct cmd_capture_pane_data { - char *target; - int buffer; -}; const struct cmd_entry cmd_capture_pane_entry = { "capture-pane", "capturep", + "b:t:", 0, 0, "[-b buffer-index] [-t target-pane]", - 0, "", - cmd_capture_pane_init, - cmd_capture_pane_parse, - cmd_capture_pane_exec, - cmd_capture_pane_free, - cmd_capture_pane_print + 0, + NULL, + NULL, + cmd_capture_pane_exec }; -/* ARGSUSED */ -void -cmd_capture_pane_init(struct cmd *self, unused int arg) -{ - struct cmd_capture_pane_data *data; - - self->data = data = xmalloc(sizeof *data); - data->buffer = -1; - data->target = NULL; -} - -int -cmd_capture_pane_parse(struct cmd *self, int argc, char **argv, char **cause) -{ - struct cmd_capture_pane_data *data; - const char *errstr; - int n, opt; - - self->entry->init(self, KEYC_NONE); - data = self->data; - - while ((opt = getopt(argc, argv, "b:t:")) != -1) { - switch (opt) { - case 'b': - if (data->buffer == -1) { - n = strtonum(optarg, 0, INT_MAX, &errstr); - if (errstr != NULL) { - xasprintf(cause, "buffer %s", errstr); - goto error; - } - data->buffer = n; - } - break; - case 't': - if (data->target == NULL) - data->target = xstrdup(optarg); - break; - default: - goto usage; - } - } - argc -= optind; - argv += optind; - - return (0); - -usage: - xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); - -error: - self->entry->free(self); - return (-1); -} - int cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_capture_pane_data *data = self->data; - struct window_pane *wp; - char *buf, *line; - struct screen *s; - u_int i, limit; - size_t len, linelen; - - if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL) + struct args *args = self->args; + struct window_pane *wp; + char *buf, *line, *cause; + struct screen *s; + int buffer; + u_int i, limit; + size_t len, linelen; + + if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL) return (-1); s = &wp->base; @@ -133,40 +70,24 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx) } limit = options_get_number(&global_options, "buffer-limit"); - if (data->buffer == -1) { + + if (!args_has(args, 'b')) { paste_add(&global_buffers, buf, len, limit); return (0); } - if (paste_replace(&global_buffers, data->buffer, buf, len) != 0) { - ctx->error(ctx, "no buffer %d", data->buffer); - xfree(buf); + + buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); + if (cause != NULL) { + ctx->error(ctx, "buffer %s", cause); + xfree(cause); return (-1); } - return (0); -} - -void -cmd_capture_pane_free(struct cmd *self) -{ - struct cmd_capture_pane_data *data = self->data; - if (data->target != NULL) - xfree(data->target); - xfree(data); -} + if (paste_replace(&global_buffers, buffer, buf, len) != 0) { + ctx->error(ctx, "no buffer %d", buffer); + xfree(buf); + return (-1); + } -size_t -cmd_capture_pane_print(struct cmd *self, char *buf, size_t len) -{ - struct cmd_capture_pane_data *data = self->data; - size_t off = 0; - - off += xsnprintf(buf, len, "%s", self->entry->name); - if (data == NULL) - return (off); - if (off < len && data->buffer != -1) - off += xsnprintf(buf + off, len - off, " -b %d", data->buffer); - if (off < len && data->target != NULL) - off += xsnprintf(buf + off, len - off, " -t %s", data->target); - return (off); + return (0); } diff --git a/cmd-choose-buffer.c b/cmd-choose-buffer.c index 32bf2f2d..c1093f92 100644 --- a/cmd-choose-buffer.c +++ b/cmd-choose-buffer.c @@ -33,24 +33,23 @@ void cmd_choose_buffer_free(void *); const struct cmd_entry cmd_choose_buffer_entry = { "choose-buffer", NULL, + "t:", 0, 1, CMD_TARGET_WINDOW_USAGE " [template]", - CMD_ARG01, "", - cmd_target_init, - cmd_target_parse, - cmd_choose_buffer_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_choose_buffer_exec }; struct cmd_choose_buffer_data { - struct client *client; - char *template; + struct client *client; + char *template; }; int cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; struct cmd_choose_buffer_data *cdata; struct winlink *wl; struct paste_buffer *pb; @@ -62,7 +61,7 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } - if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) return (-1); if (paste_get_top(&global_buffers) == NULL) @@ -80,8 +79,8 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) } cdata = xmalloc(sizeof *cdata); - if (data->arg != NULL) - cdata->template = xstrdup(data->arg); + if (args->argc != 0) + cdata->template = xstrdup(args->argv[0]); else cdata->template = xstrdup("paste-buffer -b '%%'"); cdata->client = ctx->curclient; diff --git a/cmd-choose-client.c b/cmd-choose-client.c index cd5ab9ea..ac766ab5 100644 --- a/cmd-choose-client.c +++ b/cmd-choose-client.c @@ -33,13 +33,12 @@ void cmd_choose_client_free(void *); const struct cmd_entry cmd_choose_client_entry = { "choose-client", NULL, + "t:", 0, 1, CMD_TARGET_WINDOW_USAGE " [template]", - CMD_ARG01, "", - cmd_target_init, - cmd_target_parse, - cmd_choose_client_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_choose_client_exec }; struct cmd_choose_client_data { @@ -50,7 +49,7 @@ struct cmd_choose_client_data { int cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; struct cmd_choose_client_data *cdata; struct winlink *wl; struct client *c; @@ -61,7 +60,7 @@ cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } - if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) return (-1); if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) @@ -83,8 +82,8 @@ cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx) } cdata = xmalloc(sizeof *cdata); - if (data->arg != NULL) - cdata->template = xstrdup(data->arg); + if (args->argc != 0) + cdata->template = xstrdup(args->argv[0]); else cdata->template = xstrdup("detach-client -t '%%'"); cdata->client = ctx->curclient; diff --git a/cmd-choose-session.c b/cmd-choose-session.c index cf36fe98..5aa0877b 100644 --- a/cmd-choose-session.c +++ b/cmd-choose-session.c @@ -33,13 +33,12 @@ void cmd_choose_session_free(void *); const struct cmd_entry cmd_choose_session_entry = { "choose-session", NULL, + "t:", 0, 1, CMD_TARGET_WINDOW_USAGE " [template]", - CMD_ARG01, "", - cmd_target_init, - cmd_target_parse, - cmd_choose_session_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_choose_session_exec }; struct cmd_choose_session_data { @@ -50,7 +49,7 @@ struct cmd_choose_session_data { int cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; struct cmd_choose_session_data *cdata; struct winlink *wl; struct session *s; @@ -63,7 +62,7 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } - if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) return (-1); if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) @@ -90,8 +89,8 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx) } cdata = xmalloc(sizeof *cdata); - if (data->arg != NULL) - cdata->template = xstrdup(data->arg); + if (args->argc != 0) + cdata->template = xstrdup(args->argv[0]); else cdata->template = xstrdup("switch-client -t '%%'"); cdata->client = ctx->curclient; diff --git a/cmd-choose-window.c b/cmd-choose-window.c index 1bbe0dfe..a1280927 100644 --- a/cmd-choose-window.c +++ b/cmd-choose-window.c @@ -33,13 +33,12 @@ void cmd_choose_window_free(void *); const struct cmd_entry cmd_choose_window_entry = { "choose-window", NULL, + "t:", 0, 1, CMD_TARGET_WINDOW_USAGE " [template]", - CMD_ARG01, "", - cmd_target_init, - cmd_target_parse, - cmd_choose_window_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_choose_window_exec }; struct cmd_choose_window_data { @@ -51,7 +50,7 @@ struct cmd_choose_window_data { int cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; struct cmd_choose_window_data *cdata; struct session *s; struct winlink *wl, *wm; @@ -66,7 +65,7 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx) } s = ctx->curclient->session; - if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) return (-1); if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) @@ -99,8 +98,8 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx) } cdata = xmalloc(sizeof *cdata); - if (data->arg != NULL) - cdata->template = xstrdup(data->arg); + if (args->argc != 0) + cdata->template = xstrdup(args->argv[0]); else cdata->template = xstrdup("select-window -t '%%'"); cdata->session = s; diff --git a/cmd-clear-history.c b/cmd-clear-history.c index 9241485a..cf3da229 100644 --- a/cmd-clear-history.c +++ b/cmd-clear-history.c @@ -28,23 +28,22 @@ int cmd_clear_history_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_clear_history_entry = { "clear-history", "clearhist", + "t:", 0, 0, CMD_TARGET_PANE_USAGE, - 0, "", - cmd_target_init, - cmd_target_parse, - cmd_clear_history_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_clear_history_exec }; int cmd_clear_history_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; struct window_pane *wp; struct grid *gd; - if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL) + if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL) return (-1); gd = wp->base.grid; diff --git a/cmd-clock-mode.c b/cmd-clock-mode.c index 4df934f7..0dc151d1 100644 --- a/cmd-clock-mode.c +++ b/cmd-clock-mode.c @@ -28,22 +28,21 @@ int cmd_clock_mode_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_clock_mode_entry = { "clock-mode", NULL, + "t:", 0, 0, CMD_TARGET_PANE_USAGE, - 0, "", - cmd_target_init, - cmd_target_parse, - cmd_clock_mode_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_clock_mode_exec }; int cmd_clock_mode_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; struct window_pane *wp; - if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL) + if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL) return (-1); window_pane_set_mode(wp, &window_clock_mode); diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index b76ea8d1..db50adc7 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -27,30 +27,21 @@ * Prompt for command in client. */ -void cmd_command_prompt_init(struct cmd *, int); -int cmd_command_prompt_parse(struct cmd *, int, char **, char **); -int cmd_command_prompt_exec(struct cmd *, struct cmd_ctx *); -void cmd_command_prompt_free(struct cmd *); -size_t cmd_command_prompt_print(struct cmd *, char *, size_t); +void cmd_command_prompt_key_binding(struct cmd *, int); +int cmd_command_prompt_check(struct args *); +int cmd_command_prompt_exec(struct cmd *, struct cmd_ctx *); -int cmd_command_prompt_callback(void *, const char *); -void cmd_command_prompt_cfree(void *); +int cmd_command_prompt_callback(void *, const char *); +void cmd_command_prompt_free(void *); const struct cmd_entry cmd_command_prompt_entry = { "command-prompt", NULL, + "p:t:", 0, 0, CMD_TARGET_CLIENT_USAGE " [-p prompts] [template]", - 0, "", - cmd_command_prompt_init, - cmd_command_prompt_parse, - cmd_command_prompt_exec, - cmd_command_prompt_free, - cmd_command_prompt_print -}; - -struct cmd_command_prompt_data { - char *prompts; - char *target; - char *template; + 0, + cmd_command_prompt_key_binding, + NULL, + cmd_command_prompt_exec }; struct cmd_command_prompt_cdata { @@ -62,82 +53,39 @@ struct cmd_command_prompt_cdata { }; void -cmd_command_prompt_init(struct cmd *self, int key) +cmd_command_prompt_key_binding(struct cmd *self, int key) { - struct cmd_command_prompt_data *data; - - self->data = data = xmalloc(sizeof *data); - data->prompts = NULL; - data->target = NULL; - data->template = NULL; - switch (key) { case ',': - data->template = xstrdup("rename-window '%%'"); + self->args = args_create(1, "rename-window '%%'"); break; case '.': - data->template = xstrdup("move-window -t '%%'"); + self->args = args_create(1, "move-window -t '%%'"); break; case 'f': - data->template = xstrdup("find-window '%%'"); + self->args = args_create(1, "find-window '%%'"); break; case '\'': - data->template = xstrdup("select-window -t ':%%'"); - data->prompts = xstrdup("index"); + self->args = args_create(1, "select-window -t ':%%'"); + args_set(self->args, 'p', "index"); + break; + default: + self->args = args_create(0); break; } } -int -cmd_command_prompt_parse(struct cmd *self, int argc, char **argv, char **cause) -{ - struct cmd_command_prompt_data *data; - int opt; - - self->entry->init(self, KEYC_NONE); - data = self->data; - - while ((opt = getopt(argc, argv, "p:t:")) != -1) { - switch (opt) { - case 'p': - if (data->prompts == NULL) - data->prompts = xstrdup(optarg); - break; - case 't': - if (data->target == NULL) - data->target = xstrdup(optarg); - break; - default: - goto usage; - } - } - argc -= optind; - argv += optind; - if (argc != 0 && argc != 1) - goto usage; - - if (argc == 1) - data->template = xstrdup(argv[0]); - - return (0); - -usage: - xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); - - self->entry->free(self); - return (-1); -} - int cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_command_prompt_data *data = self->data; + struct args *args = self->args; + const char *prompts; struct cmd_command_prompt_cdata *cdata; struct client *c; char *prompt, *ptr; size_t n; - if ((c = cmd_find_client(ctx, data->target)) == NULL) + if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) return (-1); if (c->prompt_string != NULL) @@ -150,63 +98,33 @@ cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx) cdata->prompts = NULL; cdata->template = NULL; - if (data->template != NULL) - cdata->template = xstrdup(data->template); + if (args->argc != 0) + cdata->template = xstrdup(args->argv[0]); else cdata->template = xstrdup("%1"); - if (data->prompts != NULL) - cdata->prompts = xstrdup(data->prompts); - else if (data->template != NULL) { - n = strcspn(data->template, " ,"); - xasprintf(&cdata->prompts, "(%.*s) ", (int) n, data->template); + + prompts = args_get(args, 'p'); + if (prompts != NULL) + cdata->prompts = xstrdup(prompts); + else if (args->argc != 0) { + n = strcspn(cdata->template, " ,"); + xasprintf(&cdata->prompts, "(%.*s) ", (int) n, cdata->template); } else cdata->prompts = xstrdup(":"); cdata->next_prompt = cdata->prompts; ptr = strsep(&cdata->next_prompt, ","); - if (data->prompts == NULL) + if (prompts == NULL) prompt = xstrdup(ptr); else xasprintf(&prompt, "%s ", ptr); status_prompt_set(c, prompt, cmd_command_prompt_callback, - cmd_command_prompt_cfree, cdata, 0); + cmd_command_prompt_free, cdata, 0); xfree(prompt); return (0); } -void -cmd_command_prompt_free(struct cmd *self) -{ - struct cmd_command_prompt_data *data = self->data; - - if (data->prompts != NULL) - xfree(data->prompts); - if (data->target != NULL) - xfree(data->target); - if (data->template != NULL) - xfree(data->template); - xfree(data); -} - -size_t -cmd_command_prompt_print(struct cmd *self, char *buf, size_t len) -{ - struct cmd_command_prompt_data *data = self->data; - size_t off = 0; - - off += xsnprintf(buf, len, "%s", self->entry->name); - if (data == NULL) - return (off); - if (off < len && data->prompts != NULL) - off += cmd_prarg(buf + off, len - off, " -p ", data->prompts); - if (off < len && data->target != NULL) - off += cmd_prarg(buf + off, len - off, " -t ", data->target); - if (off < len && data->template != NULL) - off += cmd_prarg(buf + off, len - off, " ", data->template); - return (off); -} - int cmd_command_prompt_callback(void *data, const char *s) { @@ -258,7 +176,7 @@ cmd_command_prompt_callback(void *data, const char *s) } void -cmd_command_prompt_cfree(void *data) +cmd_command_prompt_free(void *data) { struct cmd_command_prompt_cdata *cdata = data; diff --git a/cmd-confirm-before.c b/cmd-confirm-before.c index cdde81ac..b19d69d7 100644 --- a/cmd-confirm-before.c +++ b/cmd-confirm-before.c @@ -25,21 +25,20 @@ * Asks for confirmation before executing a command. */ +void cmd_confirm_before_key_binding(struct cmd *, int); int cmd_confirm_before_exec(struct cmd *, struct cmd_ctx *); -void cmd_confirm_before_init(struct cmd *, int); int cmd_confirm_before_callback(void *, const char *); void cmd_confirm_before_free(void *); const struct cmd_entry cmd_confirm_before_entry = { "confirm-before", "confirm", + "t:", 1, 1, CMD_TARGET_CLIENT_USAGE " command", - CMD_ARG1, "", - cmd_confirm_before_init, - cmd_target_parse, - cmd_confirm_before_exec, - cmd_target_free, - cmd_target_print + 0, + cmd_confirm_before_key_binding, + NULL, + cmd_confirm_before_exec }; struct cmd_confirm_before_data { @@ -48,19 +47,17 @@ struct cmd_confirm_before_data { }; void -cmd_confirm_before_init(struct cmd *self, int key) +cmd_confirm_before_key_binding(struct cmd *self, int key) { - struct cmd_target_data *data; - - cmd_target_init(self, key); - data = self->data; - switch (key) { case '&': - data->arg = xstrdup("kill-window"); + self->args = args_create(1, "kill-window"); break; case 'x': - data->arg = xstrdup("kill-pane"); + self->args = args_create(1, "kill-pane"); + break; + default: + self->args = args_create(0); break; } } @@ -68,7 +65,7 @@ cmd_confirm_before_init(struct cmd *self, int key) int cmd_confirm_before_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; struct cmd_confirm_before_data *cdata; struct client *c; char *buf, *cmd, *ptr; @@ -78,17 +75,17 @@ cmd_confirm_before_exec(struct cmd *self, struct cmd_ctx *ctx) return (-1); } - if ((c = cmd_find_client(ctx, data->target)) == NULL) + if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) return (-1); - ptr = xstrdup(data->arg); + ptr = xstrdup(args->argv[0]); if ((cmd = strtok(ptr, " \t")) == NULL) cmd = ptr; xasprintf(&buf, "Confirm '%s'? (y/n) ", cmd); xfree(ptr); cdata = xmalloc(sizeof *cdata); - cdata->cmd = xstrdup(data->arg); + cdata->cmd = xstrdup(args->argv[0]); cdata->c = c; status_prompt_set(cdata->c, buf, cmd_confirm_before_callback, cmd_confirm_before_free, cdata, diff --git a/cmd-copy-mode.c b/cmd-copy-mode.c index 3e858a33..b9290593 100644 --- a/cmd-copy-mode.c +++ b/cmd-copy-mode.c @@ -24,48 +24,40 @@ * Enter copy mode. */ -void cmd_copy_mode_init(struct cmd *, int); +void cmd_copy_mode_key_binding(struct cmd *, int); int cmd_copy_mode_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_copy_mode_entry = { "copy-mode", NULL, + "t:u", 0, 0, "[-u] " CMD_TARGET_PANE_USAGE, - 0, "u", - cmd_copy_mode_init, - cmd_target_parse, - cmd_copy_mode_exec, - cmd_target_free, - cmd_target_print + 0, + cmd_copy_mode_key_binding, + NULL, + cmd_copy_mode_exec }; void -cmd_copy_mode_init(struct cmd *self, int key) +cmd_copy_mode_key_binding(struct cmd *self, int key) { - struct cmd_target_data *data; - - cmd_target_init(self, key); - data = self->data; - - switch (key) { - case KEYC_PPAGE: - cmd_set_flag(&data->chflags, 'u'); - break; - } + self->args = args_create(0); + if (key == KEYC_PPAGE) + args_set(self->args, 'u', NULL); } int cmd_copy_mode_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; struct window_pane *wp; - if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL) + if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL) return (-1); if (window_pane_set_mode(wp, &window_copy_mode) != 0) return (0); window_copy_init_from_pane(wp); - if (wp->mode == &window_copy_mode && cmd_check_flag(data->chflags, 'u')) + if (wp->mode == &window_copy_mode && args_has(self->args, 'u')) window_copy_pageup(wp); return (0); diff --git a/cmd-delete-buffer.c b/cmd-delete-buffer.c index 0bfd77ae..3f0578ed 100644 --- a/cmd-delete-buffer.c +++ b/cmd-delete-buffer.c @@ -30,24 +30,35 @@ int cmd_delete_buffer_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_delete_buffer_entry = { "delete-buffer", "deleteb", + "b:", 0, 0, CMD_BUFFER_USAGE, - 0, "", - cmd_buffer_init, - cmd_buffer_parse, - cmd_delete_buffer_exec, - cmd_buffer_free, - cmd_buffer_print + 0, + NULL, + NULL, + cmd_delete_buffer_exec }; int cmd_delete_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_buffer_data *data = self->data; + struct args *args = self->args; + char *cause; + int buffer; - if (data->buffer == -1) + if (!args_has(args, 'b')) { paste_free_top(&global_buffers); - else if (paste_free_index(&global_buffers, data->buffer) != 0) { - ctx->error(ctx, "no buffer %d", data->buffer); + return (0); + } + + buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); + if (cause != NULL) { + ctx->error(ctx, "buffer %s", cause); + xfree(cause); + return (-1); + } + + if (paste_free_index(&global_buffers, buffer) != 0) { + ctx->error(ctx, "no buffer %d", buffer); return (-1); } diff --git a/cmd-detach-client.c b/cmd-detach-client.c index a2288036..03789bd8 100644 --- a/cmd-detach-client.c +++ b/cmd-detach-client.c @@ -28,22 +28,21 @@ int cmd_detach_client_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_detach_client_entry = { "detach-client", "detach", + "t:", 0, 0, CMD_TARGET_CLIENT_USAGE, - CMD_READONLY, "", - cmd_target_init, - cmd_target_parse, - cmd_detach_client_exec, - cmd_target_free, - cmd_target_print + CMD_READONLY, + NULL, + NULL, + cmd_detach_client_exec }; int cmd_detach_client_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; - struct client *c; + struct args *args = self->args; + struct client *c; - if ((c = cmd_find_client(ctx, data->target)) == NULL) + if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) return (-1); server_write_client(c, MSG_DETACH, NULL, 0); diff --git a/cmd-display-message.c b/cmd-display-message.c index 8c42ee6d..baf6fb9d 100644 --- a/cmd-display-message.c +++ b/cmd-display-message.c @@ -30,33 +30,32 @@ int cmd_display_message_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_display_message_entry = { "display-message", "display", + "pt:", 0, 1, "[-p] " CMD_TARGET_CLIENT_USAGE " [message]", - CMD_ARG01, "p", - cmd_target_init, - cmd_target_parse, - cmd_display_message_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_display_message_exec }; int cmd_display_message_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; struct client *c; const char *template; char *msg; - if ((c = cmd_find_client(ctx, data->target)) == NULL) + if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) return (-1); - if (data->arg == NULL) + if (args->argc == 0) template = "[#S] #I:#W, current pane #P - (%H:%M %d-%b-%y)"; else - template = data->arg; + template = args->argv[0]; msg = status_replace(c, NULL, template, time(NULL), 0); - if (cmd_check_flag(data->chflags, 'p')) + if (args_has(self->args, 'p')) ctx->print(ctx, "%s", msg); else status_message_set(c, "%s", msg); diff --git a/cmd-display-panes.c b/cmd-display-panes.c index 42ecbb9b..bc64b4b5 100644 --- a/cmd-display-panes.c +++ b/cmd-display-panes.c @@ -28,22 +28,21 @@ int cmd_display_panes_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_display_panes_entry = { "display-panes", "displayp", + "t:", 0, 0, CMD_TARGET_CLIENT_USAGE, - 0, "", - cmd_target_init, - cmd_target_parse, - cmd_display_panes_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_display_panes_exec }; int cmd_display_panes_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; - struct client *c; + struct args *args = self->args; + struct client *c; - if ((c = cmd_find_client(ctx, data->target)) == NULL) + if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) return (-1); server_set_identify(c); diff --git a/cmd-find-window.c b/cmd-find-window.c index 482d9243..6c3c48ce 100644 --- a/cmd-find-window.c +++ b/cmd-find-window.c @@ -34,13 +34,12 @@ void cmd_find_window_free(void *); const struct cmd_entry cmd_find_window_entry = { "find-window", "findw", + "t:", 1, 1, CMD_TARGET_WINDOW_USAGE " match-string", - CMD_ARG1, "", - cmd_target_init, - cmd_target_parse, - cmd_find_window_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_find_window_exec }; struct cmd_find_window_data { @@ -50,7 +49,7 @@ struct cmd_find_window_data { int cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; struct cmd_find_window_data *cdata; struct session *s; struct winlink *wl, *wm; @@ -58,7 +57,7 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) struct window_pane *wp; ARRAY_DECL(, u_int) list_idx; ARRAY_DECL(, char *) list_ctx; - char *sres, *sctx, *searchstr; + char *str, *sres, *sctx, *searchstr; u_int i, line; if (ctx->curclient == NULL) { @@ -67,13 +66,15 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) } s = ctx->curclient->session; - if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) return (-1); + str = args->argv[0]; + ARRAY_INIT(&list_idx); ARRAY_INIT(&list_ctx); - xasprintf(&searchstr, "*%s*", data->arg); + xasprintf(&searchstr, "*%s*", str); RB_FOREACH(wm, winlinks, &s->windows) { i = 0; TAILQ_FOREACH(wp, &wm->window->panes, entry) { @@ -82,7 +83,7 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) if (fnmatch(searchstr, wm->window->name, 0) == 0) sctx = xstrdup(""); else { - sres = window_pane_search(wp, data->arg, &line); + sres = window_pane_search(wp, str, &line); if (sres == NULL && fnmatch(searchstr, wp->base.title, 0) != 0) continue; @@ -106,7 +107,7 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) xfree(searchstr); if (ARRAY_LENGTH(&list_idx) == 0) { - ctx->error(ctx, "no windows matching: %s", data->arg); + ctx->error(ctx, "no windows matching: %s", str); ARRAY_FREE(&list_idx); ARRAY_FREE(&list_ctx); return (-1); diff --git a/cmd-generic.c b/cmd-generic.c deleted file mode 100644 index 97e731c9..00000000 --- a/cmd-generic.c +++ /dev/null @@ -1,414 +0,0 @@ -/* $OpenBSD$ */ - -/* - * Copyright (c) 2008 Nicholas Marriott - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include - -#include -#include - -#include "tmux.h" - -int cmd_getopt(int, char **, const char *, const char *); -int cmd_parse_flags(int, const char *, uint64_t *); -size_t cmd_print_flags(char *, size_t, size_t, uint64_t); -int cmd_fill_argument(int, char **, char **, int, char **); - -size_t -cmd_prarg(char *buf, size_t len, const char *prefix, char *arg) -{ - if (strchr(arg, ' ') != NULL) - return (xsnprintf(buf, len, "%s\"%s\"", prefix, arg)); - return (xsnprintf(buf, len, "%s%s", prefix, arg)); -} - -/* Append two flag strings together and call getopt. */ -int -cmd_getopt(int argc, char **argv, const char *flagstr, const char *chflagstr) -{ - char tmp[BUFSIZ]; - - if (strlcpy(tmp, flagstr, sizeof tmp) >= sizeof tmp) - fatalx("strlcpy overflow"); - if (strlcat(tmp, chflagstr, sizeof tmp) >= sizeof tmp) - fatalx("strlcat overflow"); - return (getopt(argc, argv, tmp)); -} - -/* Return if flag character is set. */ -int -cmd_check_flag(uint64_t chflags, int flag) -{ - if (flag >= 'A' && flag <= 'Z') - flag = 26 + flag - 'A'; - else if (flag >= 'a' && flag <= 'z') - flag = flag - 'a'; - else - return (0); - return ((chflags & (1ULL << flag)) != 0); -} - -/* Set flag character. */ -void -cmd_set_flag(uint64_t *chflags, int flag) -{ - if (flag >= 'A' && flag <= 'Z') - flag = 26 + flag - 'A'; - else if (flag >= 'a' && flag <= 'z') - flag = flag - 'a'; - else - return; - (*chflags) |= (1ULL << flag); -} - -/* If this option is expected, set it in chflags, otherwise return -1. */ -int -cmd_parse_flags(int opt, const char *chflagstr, uint64_t *chflags) -{ - if (strchr(chflagstr, opt) == NULL) - return (-1); - cmd_set_flag(chflags, opt); - return (0); -} - -/* Print the flags present in chflags. */ -size_t -cmd_print_flags(char *buf, size_t len, size_t off, uint64_t chflags) -{ - u_char ch; - size_t boff = off; - - if (chflags == 0) - return (0); - off += xsnprintf(buf + off, len - off, " -"); - - for (ch = 0; ch < 26; ch++) { - if (cmd_check_flag(chflags, 'a' + ch)) - off += xsnprintf(buf + off, len - off, "%c", 'a' + ch); - if (cmd_check_flag(chflags, 'A' + ch)) - off += xsnprintf(buf + off, len - off, "%c", 'A' + ch); - } - return (off - boff); -} - -int -cmd_fill_argument(int flags, char **arg, char **arg2, int argc, char **argv) -{ - *arg = NULL; - *arg2 = NULL; - - if (flags & CMD_ARG1) { - if (argc != 1) - return (-1); - *arg = xstrdup(argv[0]); - return (0); - } - - if (flags & CMD_ARG01) { - if (argc != 0 && argc != 1) - return (-1); - if (argc == 1) - *arg = xstrdup(argv[0]); - return (0); - } - - if (flags & CMD_ARG2) { - if (argc != 2) - return (-1); - *arg = xstrdup(argv[0]); - *arg2 = xstrdup(argv[1]); - return (0); - } - - if (flags & CMD_ARG12) { - if (argc != 1 && argc != 2) - return (-1); - *arg = xstrdup(argv[0]); - if (argc == 2) - *arg2 = xstrdup(argv[1]); - return (0); - } - - if (argc != 0) - return (-1); - return (0); -} - -/* ARGSUSED */ -void -cmd_target_init(struct cmd *self, unused int key) -{ - struct cmd_target_data *data; - - self->data = data = xmalloc(sizeof *data); - data->chflags = 0; - data->target = NULL; - data->arg = NULL; - data->arg2 = NULL; -} - -int -cmd_target_parse(struct cmd *self, int argc, char **argv, char **cause) -{ - struct cmd_target_data *data; - const struct cmd_entry *entry = self->entry; - int opt; - - /* Don't use the entry version since it may be dependent on key. */ - cmd_target_init(self, 0); - data = self->data; - - while ((opt = cmd_getopt(argc, argv, "t:", entry->chflags)) != -1) { - if (cmd_parse_flags(opt, entry->chflags, &data->chflags) == 0) - continue; - switch (opt) { - case 't': - if (data->target == NULL) - data->target = xstrdup(optarg); - break; - default: - goto usage; - } - } - argc -= optind; - argv += optind; - - if (cmd_fill_argument( - self->entry->flags, &data->arg, &data->arg2, argc, argv) != 0) - goto usage; - return (0); - -usage: - xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); - - self->entry->free(self); - return (-1); -} - -void -cmd_target_free(struct cmd *self) -{ - struct cmd_target_data *data = self->data; - - if (data->target != NULL) - xfree(data->target); - if (data->arg != NULL) - xfree(data->arg); - if (data->arg2 != NULL) - xfree(data->arg2); - xfree(data); -} - -size_t -cmd_target_print(struct cmd *self, char *buf, size_t len) -{ - struct cmd_target_data *data = self->data; - size_t off = 0; - - off += xsnprintf(buf, len, "%s", self->entry->name); - if (data == NULL) - return (off); - off += cmd_print_flags(buf, len, off, data->chflags); - if (off < len && data->target != NULL) - off += cmd_prarg(buf + off, len - off, " -t ", data->target); - if (off < len && data->arg != NULL) - off += cmd_prarg(buf + off, len - off, " ", data->arg); - if (off < len && data->arg2 != NULL) - off += cmd_prarg(buf + off, len - off, " ", data->arg2); - return (off); -} - -/* ARGSUSED */ -void -cmd_srcdst_init(struct cmd *self, unused int key) -{ - struct cmd_srcdst_data *data; - - self->data = data = xmalloc(sizeof *data); - data->chflags = 0; - data->src = NULL; - data->dst = NULL; - data->arg = NULL; - data->arg2 = NULL; -} - -int -cmd_srcdst_parse(struct cmd *self, int argc, char **argv, char **cause) -{ - struct cmd_srcdst_data *data; - const struct cmd_entry *entry = self->entry; - int opt; - - cmd_srcdst_init(self, 0); - data = self->data; - - while ((opt = cmd_getopt(argc, argv, "s:t:", entry->chflags)) != -1) { - if (cmd_parse_flags(opt, entry->chflags, &data->chflags) == 0) - continue; - switch (opt) { - case 's': - if (data->src == NULL) - data->src = xstrdup(optarg); - break; - case 't': - if (data->dst == NULL) - data->dst = xstrdup(optarg); - break; - default: - goto usage; - } - } - argc -= optind; - argv += optind; - - if (cmd_fill_argument( - self->entry->flags, &data->arg, &data->arg2, argc, argv) != 0) - goto usage; - return (0); - -usage: - xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); - - self->entry->free(self); - return (-1); -} - -void -cmd_srcdst_free(struct cmd *self) -{ - struct cmd_srcdst_data *data = self->data; - - if (data->src != NULL) - xfree(data->src); - if (data->dst != NULL) - xfree(data->dst); - if (data->arg != NULL) - xfree(data->arg); - if (data->arg2 != NULL) - xfree(data->arg2); - xfree(data); -} - -size_t -cmd_srcdst_print(struct cmd *self, char *buf, size_t len) -{ - struct cmd_srcdst_data *data = self->data; - size_t off = 0; - - off += xsnprintf(buf, len, "%s", self->entry->name); - if (data == NULL) - return (off); - off += cmd_print_flags(buf, len, off, data->chflags); - if (off < len && data->src != NULL) - off += xsnprintf(buf + off, len - off, " -s %s", data->src); - if (off < len && data->dst != NULL) - off += xsnprintf(buf + off, len - off, " -t %s", data->dst); - if (off < len && data->arg != NULL) - off += cmd_prarg(buf + off, len - off, " ", data->arg); - if (off < len && data->arg2 != NULL) - off += cmd_prarg(buf + off, len - off, " ", data->arg2); - return (off); -} - -/* ARGSUSED */ -void -cmd_buffer_init(struct cmd *self, unused int key) -{ - struct cmd_buffer_data *data; - - self->data = data = xmalloc(sizeof *data); - data->chflags = 0; - data->buffer = -1; - data->arg = NULL; - data->arg2 = NULL; -} - -int -cmd_buffer_parse(struct cmd *self, int argc, char **argv, char **cause) -{ - struct cmd_buffer_data *data; - const struct cmd_entry *entry = self->entry; - int opt, n; - const char *errstr; - - cmd_buffer_init(self, 0); - data = self->data; - - while ((opt = cmd_getopt(argc, argv, "b:", entry->chflags)) != -1) { - if (cmd_parse_flags(opt, entry->chflags, &data->chflags) == 0) - continue; - switch (opt) { - case 'b': - if (data->buffer == -1) { - n = strtonum(optarg, 0, INT_MAX, &errstr); - if (errstr != NULL) { - xasprintf(cause, "buffer %s", errstr); - goto error; - } - data->buffer = n; - } - break; - default: - goto usage; - } - } - argc -= optind; - argv += optind; - - if (cmd_fill_argument( - self->entry->flags, &data->arg, &data->arg2, argc, argv) != 0) - goto usage; - return (0); - -usage: - xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); - -error: - self->entry->free(self); - return (-1); -} - -void -cmd_buffer_free(struct cmd *self) -{ - struct cmd_buffer_data *data = self->data; - - if (data->arg != NULL) - xfree(data->arg); - if (data->arg2 != NULL) - xfree(data->arg2); - xfree(data); -} - -size_t -cmd_buffer_print(struct cmd *self, char *buf, size_t len) -{ - struct cmd_buffer_data *data = self->data; - size_t off = 0; - - off += xsnprintf(buf, len, "%s", self->entry->name); - if (data == NULL) - return (off); - off += cmd_print_flags(buf, len, off, data->chflags); - if (off < len && data->buffer != -1) - off += xsnprintf(buf + off, len - off, " -b %d", data->buffer); - if (off < len && data->arg != NULL) - off += cmd_prarg(buf + off, len - off, " ", data->arg); - if (off < len && data->arg2 != NULL) - off += cmd_prarg(buf + off, len - off, " ", data->arg2); - return (off); -} diff --git a/cmd-has-session.c b/cmd-has-session.c index 00f171b7..d5d806a1 100644 --- a/cmd-has-session.c +++ b/cmd-has-session.c @@ -28,21 +28,20 @@ int cmd_has_session_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_has_session_entry = { "has-session", "has", + "t:", 0, 0, CMD_TARGET_SESSION_USAGE, - 0, "", - cmd_target_init, - cmd_target_parse, - cmd_has_session_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_has_session_exec }; int cmd_has_session_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; - if (cmd_find_session(ctx, data->target) == NULL) + if (cmd_find_session(ctx, args_get(args, 't')) == NULL) return (-1); return (0); diff --git a/cmd-if-shell.c b/cmd-if-shell.c index bf60fb23..b7671332 100644 --- a/cmd-if-shell.c +++ b/cmd-if-shell.c @@ -35,13 +35,12 @@ void cmd_if_shell_free(void *); const struct cmd_entry cmd_if_shell_entry = { "if-shell", "if", + "", 2, 2, "shell-command command", - CMD_ARG2, "", - cmd_target_init, - cmd_target_parse, - cmd_if_shell_exec, - cmd_target_free, - cmd_target_print + 0, + NULL, + NULL, + cmd_if_shell_exec }; struct cmd_if_shell_data { @@ -52,12 +51,12 @@ struct cmd_if_shell_data { int cmd_if_shell_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; + struct args *args = self->args; struct cmd_if_shell_data *cdata; struct job *job; cdata = xmalloc(sizeof *cdata); - cdata->cmd = xstrdup(data->arg2); + cdata->cmd = xstrdup(args->argv[1]); memcpy(&cdata->ctx, ctx, sizeof cdata->ctx); if (ctx->cmdclient != NULL) @@ -66,7 +65,7 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_ctx *ctx) ctx->curclient->references++; job = job_add(NULL, 0, NULL, - data->arg, cmd_if_shell_callback, cmd_if_shell_free, cdata); + args->argv[0], cmd_if_shell_callback, cmd_if_shell_free, cdata); job_run(job); return (1); /* don't let client exit */ diff --git a/cmd-join-pane.c b/cmd-join-pane.c index d13c23e3..10b4dda3 100644 --- a/cmd-join-pane.c +++ b/cmd-join-pane.c @@ -28,139 +28,54 @@ * Join a pane into another (like split/swap/kill). */ -int cmd_join_pane_parse(struct cmd *, int, char **, char **); +void cmd_join_pane_key_binding(struct cmd *, int); int cmd_join_pane_exec(struct cmd *, struct cmd_ctx *); -void cmd_join_pane_free(struct cmd *); -void cmd_join_pane_init(struct cmd *, int); -size_t cmd_join_pane_print(struct cmd *, char *, size_t); - -struct cmd_join_pane_data { - char *src; - char *dst; - int flag_detached; - int flag_horizontal; - int percentage; - int size; -}; const struct cmd_entry cmd_join_pane_entry = { "join-pane", "joinp", + "dhvp:l:s:t:", 0, 0, "[-dhv] [-p percentage|-l size] [-s src-pane] [-t dst-pane]", - 0, "", - cmd_join_pane_init, - cmd_join_pane_parse, - cmd_join_pane_exec, - cmd_join_pane_free, - cmd_join_pane_print + 0, + cmd_join_pane_key_binding, + NULL, + cmd_join_pane_exec }; void -cmd_join_pane_init(struct cmd *self, int key) +cmd_join_pane_key_binding(struct cmd *self, int key) { - struct cmd_join_pane_data *data; - - self->data = data = xmalloc(sizeof *data); - data->src = NULL; - data->dst = NULL; - data->flag_detached = 0; - data->flag_horizontal = 0; - data->percentage = -1; - data->size = -1; - switch (key) { case '%': - data->flag_horizontal = 1; + self->args = args_create(0); + args_set(self->args, 'h', NULL); break; - case '"': - data->flag_horizontal = 0; + default: + self->args = args_create(0); break; } } -int -cmd_join_pane_parse(struct cmd *self, int argc, char **argv, char **cause) -{ - struct cmd_join_pane_data *data; - int opt; - const char *errstr; - - self->entry->init(self, KEYC_NONE); - data = self->data; - - while ((opt = getopt(argc, argv, "dhl:p:s:t:v")) != -1) { - switch (opt) { - case 'd': - data->flag_detached = 1; - break; - case 'h': - data->flag_horizontal = 1; - break; - case 's': - if (data->src == NULL) - data->src = xstrdup(optarg); - break; - case 't': - if (data->dst == NULL) - data->dst = xstrdup(optarg); - break; - case 'l': - if (data->percentage != -1 || data->size != -1) - break; - data->size = strtonum(optarg, 1, INT_MAX, &errstr); - if (errstr != NULL) { - xasprintf(cause, "size %s", errstr); - goto error; - } - break; - case 'p': - if (data->size != -1 || data->percentage != -1) - break; - data->percentage = strtonum(optarg, 1, 100, &errstr); - if (errstr != NULL) { - xasprintf(cause, "percentage %s", errstr); - goto error; - } - break; - case 'v': - data->flag_horizontal = 0; - break; - default: - goto usage; - } - } - argc -= optind; - argv += optind; - if (argc != 0) - goto usage; - - return (0); - -usage: - xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); - -error: - self->entry->free(self); - return (-1); -} - int cmd_join_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_join_pane_data *data = self->data; - struct session *dst_s; - struct winlink *src_wl, *dst_wl; - struct window *src_w, *dst_w; - struct window_pane *src_wp, *dst_wp; - int size, dst_idx; - enum layout_type type; - struct layout_cell *lc; - - if ((dst_wl = cmd_find_pane(ctx, data->dst, &dst_s, &dst_wp)) == NULL) + struct args *args = self->args; + struct session *dst_s; + struct winlink *src_wl, *dst_wl; + struct window *src_w, *dst_w; + struct window_pane *src_wp, *dst_wp; + char *cause; + int size, percentage, dst_idx; + enum layout_type type; + struct layout_cell *lc; + + dst_wl = cmd_find_pane(ctx, args_get(args, 't'), &dst_s, &dst_wp); + if (dst_wl == NULL) return (-1); dst_w = dst_wl->window; dst_idx = dst_wl->idx; - if ((src_wl = cmd_find_pane(ctx, data->src, NULL, &src_wp)) == NULL) + src_wl = cmd_find_pane(ctx, args_get(args, 's'), NULL, &src_wp); + if (src_wl == NULL) return (-1); src_w = src_wl->window; @@ -170,17 +85,28 @@ cmd_join_pane_exec(struct cmd *self, struct cmd_ctx *ctx) } type = LAYOUT_TOPBOTTOM; - if (data->flag_horizontal) + if (args_has(args, 'h')) type = LAYOUT_LEFTRIGHT; size = -1; - if (data->size != -1) - size = data->size; - else if (data->percentage != -1) { + if (args_has(args, 's')) { + size = args_strtonum(args, 's', 0, INT_MAX, &cause); + if (cause != NULL) { + ctx->error(ctx, "size %s", cause); + xfree(cause); + return (-1); + } + } else if (args_has(args, 'p')) { + percentage = args_strtonum(args, 'p', 0, INT_MAX, &cause); + if (cause != NULL) { + ctx->error(ctx, "percentage %s", cause); + xfree(cause); + return (-1); + } if (type == LAYOUT_TOPBOTTOM) - size = (dst_wp->sy * data->percentage) / 100; + size = (dst_wp->sy * percentage) / 100;