2009-06-01 22:58:49 +00:00
|
|
|
/* $OpenBSD$ */
|
|
|
|
|
|
|
|
/*
|
2016-01-19 15:59:12 +00:00
|
|
|
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
2009-06-01 22:58:49 +00:00
|
|
|
*
|
|
|
|
* 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 <sys/types.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
|
2009-07-13 17:47:46 +00:00
|
|
|
#include <fnmatch.h>
|
|
|
|
#include <paths.h>
|
2012-01-31 15:52:21 +00:00
|
|
|
#include <pwd.h>
|
2009-06-01 22:58:49 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include "tmux.h"
|
|
|
|
|
2015-09-01 09:48:34 +00:00
|
|
|
extern const struct cmd_entry cmd_attach_session_entry;
|
|
|
|
extern const struct cmd_entry cmd_bind_key_entry;
|
|
|
|
extern const struct cmd_entry cmd_break_pane_entry;
|
|
|
|
extern const struct cmd_entry cmd_capture_pane_entry;
|
|
|
|
extern const struct cmd_entry cmd_choose_buffer_entry;
|
|
|
|
extern const struct cmd_entry cmd_choose_client_entry;
|
|
|
|
extern const struct cmd_entry cmd_choose_tree_entry;
|
|
|
|
extern const struct cmd_entry cmd_clear_history_entry;
|
|
|
|
extern const struct cmd_entry cmd_clock_mode_entry;
|
|
|
|
extern const struct cmd_entry cmd_command_prompt_entry;
|
|
|
|
extern const struct cmd_entry cmd_confirm_before_entry;
|
|
|
|
extern const struct cmd_entry cmd_copy_mode_entry;
|
|
|
|
extern const struct cmd_entry cmd_delete_buffer_entry;
|
|
|
|
extern const struct cmd_entry cmd_detach_client_entry;
|
2019-05-10 18:04:06 +00:00
|
|
|
extern const struct cmd_entry cmd_display_menu_entry;
|
2015-09-01 09:48:34 +00:00
|
|
|
extern const struct cmd_entry cmd_display_message_entry;
|
2020-03-24 08:09:43 +00:00
|
|
|
extern const struct cmd_entry cmd_display_popup_entry;
|
2015-09-01 09:48:34 +00:00
|
|
|
extern const struct cmd_entry cmd_display_panes_entry;
|
|
|
|
extern const struct cmd_entry cmd_down_pane_entry;
|
|
|
|
extern const struct cmd_entry cmd_find_window_entry;
|
|
|
|
extern const struct cmd_entry cmd_has_session_entry;
|
|
|
|
extern const struct cmd_entry cmd_if_shell_entry;
|
|
|
|
extern const struct cmd_entry cmd_join_pane_entry;
|
|
|
|
extern const struct cmd_entry cmd_kill_pane_entry;
|
|
|
|
extern const struct cmd_entry cmd_kill_server_entry;
|
|
|
|
extern const struct cmd_entry cmd_kill_session_entry;
|
|
|
|
extern const struct cmd_entry cmd_kill_window_entry;
|
|
|
|
extern const struct cmd_entry cmd_last_pane_entry;
|
|
|
|
extern const struct cmd_entry cmd_last_window_entry;
|
|
|
|
extern const struct cmd_entry cmd_link_window_entry;
|
|
|
|
extern const struct cmd_entry cmd_list_buffers_entry;
|
|
|
|
extern const struct cmd_entry cmd_list_clients_entry;
|
|
|
|
extern const struct cmd_entry cmd_list_commands_entry;
|
|
|
|
extern const struct cmd_entry cmd_list_keys_entry;
|
|
|
|
extern const struct cmd_entry cmd_list_panes_entry;
|
|
|
|
extern const struct cmd_entry cmd_list_sessions_entry;
|
|
|
|
extern const struct cmd_entry cmd_list_windows_entry;
|
|
|
|
extern const struct cmd_entry cmd_load_buffer_entry;
|
|
|
|
extern const struct cmd_entry cmd_lock_client_entry;
|
|
|
|
extern const struct cmd_entry cmd_lock_server_entry;
|
|
|
|
extern const struct cmd_entry cmd_lock_session_entry;
|
|
|
|
extern const struct cmd_entry cmd_move_pane_entry;
|
|
|
|
extern const struct cmd_entry cmd_move_window_entry;
|
|
|
|
extern const struct cmd_entry cmd_new_session_entry;
|
|
|
|
extern const struct cmd_entry cmd_new_window_entry;
|
|
|
|
extern const struct cmd_entry cmd_next_layout_entry;
|
|
|
|
extern const struct cmd_entry cmd_next_window_entry;
|
|
|
|
extern const struct cmd_entry cmd_paste_buffer_entry;
|
|
|
|
extern const struct cmd_entry cmd_pipe_pane_entry;
|
|
|
|
extern const struct cmd_entry cmd_previous_layout_entry;
|
|
|
|
extern const struct cmd_entry cmd_previous_window_entry;
|
|
|
|
extern const struct cmd_entry cmd_refresh_client_entry;
|
|
|
|
extern const struct cmd_entry cmd_rename_session_entry;
|
|
|
|
extern const struct cmd_entry cmd_rename_window_entry;
|
|
|
|
extern const struct cmd_entry cmd_resize_pane_entry;
|
Support for windows larger than visible on the attached client. This has
been a limitation for a long time.
There are two new options, window-size and default-size, and a new
command, resize-window. The force-width and force-height options and the
session_width and session_height formats have been removed.
The new window-size option tells tmux how to work out the size of
windows: largest means it picks the size of the largest session,
smallest the smallest session (similar to the old behaviour) and manual
means that it does not automatically resize windows. The default is
currently largest but this may change. aggressive-resize modifies the
choice of session for largest and smallest as it did before.
If a window is in a session attached to a client that is too small, only
part of the window is shown. tmux attempts to keep the cursor visible,
so the part of the window displayed is changed as the cursor moves (with
a small delay, to try and avoid excess redrawing when applications
redraw status lines or similar that are not currently visible). The
offset of the visible portion of the window is shown in status-right.
Drawing windows which are larger than the client is not as efficient as
those which fit, particularly when the cursor moves, so it is
recommended to avoid using this on slow machines or networks (set
window-size to smallest or manual).
The resize-window command can be used to resize a window manually. If it
is used, the window-size option is automatically set to manual for the
window (undo this with "setw -u window-size"). resize-window works in a
similar way to resize-pane (-U -D -L -R -x -y flags) but also has -a and
-A flags. -a sets the window to the size of the smallest client (what it
would be if window-size was smallest) and -A the largest.
For the same behaviour as force-width or force-height, use resize-window
-x or -y, and "setw -u window-size" to revert to automatic sizing..
If the global window-size option is set to manual, the default-size
option is used for new windows. If -x or -y is used with new-session,
that sets the default-size option for the new session.
The maximum size of a window is 10000x10000. But expect applications to
complain and much higher memory use if making a window excessively
big. The minimum size is the size required for the current layout
including borders.
The refresh-client command can be used to pan around a window, -U -D -L
-R moves up, down, left or right and -c returns to automatic cursor
tracking. The position is reset when the current window is changed.
2018-10-18 08:38:01 +00:00
|
|
|
extern const struct cmd_entry cmd_resize_window_entry;
|
2015-09-01 09:48:34 +00:00
|
|
|
extern const struct cmd_entry cmd_respawn_pane_entry;
|
|
|
|
extern const struct cmd_entry cmd_respawn_window_entry;
|
|
|
|
extern const struct cmd_entry cmd_rotate_window_entry;
|
|
|
|
extern const struct cmd_entry cmd_run_shell_entry;
|
|
|
|
extern const struct cmd_entry cmd_save_buffer_entry;
|
|
|
|
extern const struct cmd_entry cmd_select_layout_entry;
|
|
|
|
extern const struct cmd_entry cmd_select_pane_entry;
|
|
|
|
extern const struct cmd_entry cmd_select_window_entry;
|
|
|
|
extern const struct cmd_entry cmd_send_keys_entry;
|
|
|
|
extern const struct cmd_entry cmd_send_prefix_entry;
|
|
|
|
extern const struct cmd_entry cmd_set_buffer_entry;
|
|
|
|
extern const struct cmd_entry cmd_set_environment_entry;
|
2015-12-08 01:10:31 +00:00
|
|
|
extern const struct cmd_entry cmd_set_hook_entry;
|
2015-09-01 09:48:34 +00:00
|
|
|
extern const struct cmd_entry cmd_set_option_entry;
|
|
|
|
extern const struct cmd_entry cmd_set_window_option_entry;
|
|
|
|
extern const struct cmd_entry cmd_show_buffer_entry;
|
|
|
|
extern const struct cmd_entry cmd_show_environment_entry;
|
2015-12-08 01:10:31 +00:00
|
|
|
extern const struct cmd_entry cmd_show_hooks_entry;
|
2015-09-01 09:48:34 +00:00
|
|
|
extern const struct cmd_entry cmd_show_messages_entry;
|
|
|
|
extern const struct cmd_entry cmd_show_options_entry;
|
|
|
|
extern const struct cmd_entry cmd_show_window_options_entry;
|
|
|
|
extern const struct cmd_entry cmd_source_file_entry;
|
|
|
|
extern const struct cmd_entry cmd_split_window_entry;
|
|
|
|
extern const struct cmd_entry cmd_start_server_entry;
|
|
|
|
extern const struct cmd_entry cmd_suspend_client_entry;
|
|
|
|
extern const struct cmd_entry cmd_swap_pane_entry;
|
|
|
|
extern const struct cmd_entry cmd_swap_window_entry;
|
|
|
|
extern const struct cmd_entry cmd_switch_client_entry;
|
|
|
|
extern const struct cmd_entry cmd_unbind_key_entry;
|
|
|
|
extern const struct cmd_entry cmd_unlink_window_entry;
|
|
|
|
extern const struct cmd_entry cmd_up_pane_entry;
|
|
|
|
extern const struct cmd_entry cmd_wait_for_entry;
|
|
|
|
|
2009-06-01 22:58:49 +00:00
|
|
|
const struct cmd_entry *cmd_table[] = {
|
|
|
|
&cmd_attach_session_entry,
|
|
|
|
&cmd_bind_key_entry,
|
|
|
|
&cmd_break_pane_entry,
|
2009-12-01 18:42:38 +00:00
|
|
|
&cmd_capture_pane_entry,
|
2010-06-21 21:44:09 +00:00
|
|
|
&cmd_choose_buffer_entry,
|
2009-08-25 12:18:51 +00:00
|
|
|
&cmd_choose_client_entry,
|
2012-07-08 16:04:38 +00:00
|
|
|
&cmd_choose_tree_entry,
|
2009-06-01 22:58:49 +00:00
|
|
|
&cmd_clear_history_entry,
|
|
|
|
&cmd_clock_mode_entry,
|
|
|
|
&cmd_command_prompt_entry,
|
|
|
|
&cmd_confirm_before_entry,
|
|
|
|
&cmd_copy_mode_entry,
|
|
|
|
&cmd_delete_buffer_entry,
|
|
|
|
&cmd_detach_client_entry,
|
2019-05-10 18:04:06 +00:00
|
|
|
&cmd_display_menu_entry,
|
2009-07-17 18:45:08 +00:00
|
|
|
&cmd_display_message_entry,
|
2020-03-24 08:09:43 +00:00
|
|
|
&cmd_display_popup_entry,
|
2009-08-31 20:46:19 +00:00
|
|
|
&cmd_display_panes_entry,
|
2009-06-01 22:58:49 +00:00
|
|
|
&cmd_find_window_entry,
|
|
|
|
&cmd_has_session_entry,
|
2009-07-09 15:47:49 +00:00
|
|
|
&cmd_if_shell_entry,
|
2010-01-07 20:52:18 +00:00
|
|
|
&cmd_join_pane_entry,
|
2009-06-01 22:58:49 +00:00
|
|
|
&cmd_kill_pane_entry,
|
|
|
|
&cmd_kill_server_entry,
|
|
|
|
&cmd_kill_session_entry,
|
|
|
|
&cmd_kill_window_entry,
|
2010-10-23 13:04:34 +00:00
|
|
|
&cmd_last_pane_entry,
|
2009-06-01 22:58:49 +00:00
|
|
|
&cmd_last_window_entry,
|
|
|
|
&cmd_link_window_entry,
|
|
|
|
&cmd_list_buffers_entry,
|
|
|
|
&cmd_list_clients_entry,
|
|
|
|
&cmd_list_commands_entry,
|
|
|
|
&cmd_list_keys_entry,
|
2009-10-10 17:19:38 +00:00
|
|
|
&cmd_list_panes_entry,
|
2009-06-01 22:58:49 +00:00
|
|
|
&cmd_list_sessions_entry,
|
|
|
|
&cmd_list_windows_entry,
|
|
|
|
&cmd_load_buffer_entry,
|
2009-09-24 14:17:09 +00:00
|
|
|
&cmd_lock_client_entry,
|
2009-06-01 22:58:49 +00:00
|
|
|
&cmd_lock_server_entry,
|
2009-09-24 14:17:09 +00:00
|
|
|
&cmd_lock_session_entry,
|
2012-03-03 08:31:18 +00:00
|
|
|
&cmd_move_pane_entry,
|
2009-06-01 22:58:49 +00:00
|
|
|
&cmd_move_window_entry,
|
|
|
|
&cmd_new_session_entry,
|
|
|
|
&cmd_new_window_entry,
|
|
|
|
&cmd_next_layout_entry,
|
|
|
|
&cmd_next_window_entry,
|
|
|
|
&cmd_paste_buffer_entry,
|
2009-10-11 10:04:27 +00:00
|
|
|
&cmd_pipe_pane_entry,
|
2009-06-01 22:58:49 +00:00
|
|
|
&cmd_previous_layout_entry,
|
|
|
|
&cmd_previous_window_entry,
|
|
|
|
&cmd_refresh_client_entry,
|
|
|
|
&cmd_rename_session_entry,
|
|
|
|
&cmd_rename_window_entry,
|
|
|
|
&cmd_resize_pane_entry,
|
Support for windows larger than visible on the attached client. This has
been a limitation for a long time.
There are two new options, window-size and default-size, and a new
command, resize-window. The force-width and force-height options and the
session_width and session_height formats have been removed.
The new window-size option tells tmux how to work out the size of
windows: largest means it picks the size of the largest session,
smallest the smallest session (similar to the old behaviour) and manual
means that it does not automatically resize windows. The default is
currently largest but this may change. aggressive-resize modifies the
choice of session for largest and smallest as it did before.
If a window is in a session attached to a client that is too small, only
part of the window is shown. tmux attempts to keep the cursor visible,
so the part of the window displayed is changed as the cursor moves (with
a small delay, to try and avoid excess redrawing when applications
redraw status lines or similar that are not currently visible). The
offset of the visible portion of the window is shown in status-right.
Drawing windows which are larger than the client is not as efficient as
those which fit, particularly when the cursor moves, so it is
recommended to avoid using this on slow machines or networks (set
window-size to smallest or manual).
The resize-window command can be used to resize a window manually. If it
is used, the window-size option is automatically set to manual for the
window (undo this with "setw -u window-size"). resize-window works in a
similar way to resize-pane (-U -D -L -R -x -y flags) but also has -a and
-A flags. -a sets the window to the size of the smallest client (what it
would be if window-size was smallest) and -A the largest.
For the same behaviour as force-width or force-height, use resize-window
-x or -y, and "setw -u window-size" to revert to automatic sizing..
If the global window-size option is set to manual, the default-size
option is used for new windows. If -x or -y is used with new-session,
that sets the default-size option for the new session.
The maximum size of a window is 10000x10000. But expect applications to
complain and much higher memory use if making a window excessively
big. The minimum size is the size required for the current layout
including borders.
The refresh-client command can be used to pan around a window, -U -D -L
-R moves up, down, left or right and -c returns to automatic cursor
tracking. The position is reset when the current window is changed.
2018-10-18 08:38:01 +00:00
|
|
|
&cmd_resize_window_entry,
|
2011-06-05 11:19:03 +00:00
|
|
|
&cmd_respawn_pane_entry,
|
2009-06-01 22:58:49 +00:00
|
|
|
&cmd_respawn_window_entry,
|
|
|
|
&cmd_rotate_window_entry,
|
2009-09-20 19:15:01 +00:00
|
|
|
&cmd_run_shell_entry,
|
2009-06-01 22:58:49 +00:00
|
|
|
&cmd_save_buffer_entry,
|
|
|
|
&cmd_select_layout_entry,
|
|
|
|
&cmd_select_pane_entry,
|
|
|
|
&cmd_select_window_entry,
|
|
|
|
&cmd_send_keys_entry,
|
|
|
|
&cmd_send_prefix_entry,
|
|
|
|
&cmd_set_buffer_entry,
|
2009-08-08 21:52:43 +00:00
|
|
|
&cmd_set_environment_entry,
|
2015-12-08 01:10:31 +00:00
|
|
|
&cmd_set_hook_entry,
|
2009-06-01 22:58:49 +00:00
|
|
|
&cmd_set_option_entry,
|
|
|
|
&cmd_set_window_option_entry,
|
|
|
|
&cmd_show_buffer_entry,
|
2009-08-08 21:52:43 +00:00
|
|
|
&cmd_show_environment_entry,
|
2015-12-08 01:10:31 +00:00
|
|
|
&cmd_show_hooks_entry,
|
2009-11-18 13:16:33 +00:00
|
|
|
&cmd_show_messages_entry,
|
2009-06-01 22:58:49 +00:00
|
|
|
&cmd_show_options_entry,
|
|
|
|
&cmd_show_window_options_entry,
|
|
|
|
&cmd_source_file_entry,
|
|
|
|
&cmd_split_window_entry,
|
|
|
|
&cmd_start_server_entry,
|
|
|
|
&cmd_suspend_client_entry,
|
|
|
|
&cmd_swap_pane_entry,
|
|
|
|
&cmd_swap_window_entry,
|
|
|
|
&cmd_switch_client_entry,
|
|
|
|
&cmd_unbind_key_entry,
|
|
|
|
&cmd_unlink_window_entry,
|
2013-03-25 10:09:05 +00:00
|
|
|
&cmd_wait_for_entry,
|
2009-06-01 22:58:49 +00:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2020-04-13 08:26:27 +00:00
|
|
|
/* Instance of a command. */
|
|
|
|
struct cmd {
|
|
|
|
const struct cmd_entry *entry;
|
|
|
|
struct args *args;
|
|
|
|
u_int group;
|
|
|
|
|
|
|
|
char *file;
|
|
|
|
u_int line;
|
|
|
|
|
|
|
|
char *alias;
|
|
|
|
int argc;
|
|
|
|
char **argv;
|
|
|
|
|
|
|
|
TAILQ_ENTRY(cmd) qentry;
|
|
|
|
};
|
|
|
|
TAILQ_HEAD(cmds, cmd);
|
|
|
|
|
|
|
|
/* Next group number for new command list. */
|
2019-05-25 10:44:09 +00:00
|
|
|
static u_int cmd_list_next_group = 1;
|
|
|
|
|
2020-04-13 08:26:27 +00:00
|
|
|
/* Log an argument vector. */
|
2019-05-25 06:58:10 +00:00
|
|
|
void printflike(3, 4)
|
|
|
|
cmd_log_argv(int argc, char **argv, const char *fmt, ...)
|
2018-08-02 18:35:21 +00:00
|
|
|
{
|
2019-05-25 06:58:10 +00:00
|
|
|
char *prefix;
|
|
|
|
va_list ap;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
xvasprintf(&prefix, fmt, ap);
|
|
|
|
va_end(ap);
|
2018-08-02 18:35:21 +00:00
|
|
|
|
|
|
|
for (i = 0; i < argc; i++)
|
|
|
|
log_debug("%s: argv[%d]=%s", prefix, i, argv[i]);
|
2019-05-25 06:58:10 +00:00
|
|
|
free(prefix);
|
2018-08-02 18:35:21 +00:00
|
|
|
}
|
|
|
|
|
2020-04-13 08:26:27 +00:00
|
|
|
/* Prepend to an argument vector. */
|
2019-05-23 11:13:30 +00:00
|
|
|
void
|
|
|
|
cmd_prepend_argv(int *argc, char ***argv, char *arg)
|
|
|
|
{
|
|
|
|
char **new_argv;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
new_argv = xreallocarray(NULL, (*argc) + 1, sizeof *new_argv);
|
|
|
|
new_argv[0] = xstrdup(arg);
|
|
|
|
for (i = 0; i < *argc; i++)
|
|
|
|
new_argv[1 + i] = (*argv)[i];
|
|
|
|
|
|
|
|
free(*argv);
|
|
|
|
*argv = new_argv;
|
|
|
|
(*argc)++;
|
|
|
|
}
|
|
|
|
|
2020-04-13 08:26:27 +00:00
|
|
|
/* Append to an argument vector. */
|
2019-05-23 11:13:30 +00:00
|
|
|
void
|
|
|
|
cmd_append_argv(int *argc, char ***argv, char *arg)
|
|
|
|
{
|
|
|
|
*argv = xreallocarray(*argv, (*argc) + 1, sizeof **argv);
|
|
|
|
(*argv)[(*argc)++] = xstrdup(arg);
|
|
|
|
}
|
|
|
|
|
2020-04-13 08:26:27 +00:00
|
|
|
/* Pack an argument vector up into a buffer. */
|
2009-07-26 12:58:44 +00:00
|
|
|
int
|
|
|
|
cmd_pack_argv(int argc, char **argv, char *buf, size_t len)
|
|
|
|
{
|
|
|
|
size_t arglen;
|
|
|
|
int i;
|
|
|
|
|
2014-03-31 21:32:31 +00:00
|
|
|
if (argc == 0)
|
|
|
|
return (0);
|
2019-05-25 06:58:10 +00:00
|
|
|
cmd_log_argv(argc, argv, "%s", __func__);
|
2014-03-31 21:32:31 +00:00
|
|
|
|
2009-07-26 12:58:44 +00:00
|
|
|
*buf = '\0';
|
|
|
|
for (i = 0; i < argc; i++) {
|
|
|
|
if (strlcpy(buf, argv[i], len) >= len)
|
|
|
|
return (-1);
|
|
|
|
arglen = strlen(argv[i]) + 1;
|
|
|
|
buf += arglen;
|
|
|
|
len -= arglen;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2020-04-13 08:26:27 +00:00
|
|
|
/* Unpack an argument vector from a packed buffer. */
|
2009-07-26 12:58:44 +00:00
|
|
|
int
|
|
|
|
cmd_unpack_argv(char *buf, size_t len, int argc, char ***argv)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
size_t arglen;
|
|
|
|
|
|
|
|
if (argc == 0)
|
|
|
|
return (0);
|
|
|
|
*argv = xcalloc(argc, sizeof **argv);
|
|
|
|
|
|
|
|
buf[len - 1] = '\0';
|
|
|
|
for (i = 0; i < argc; i++) {
|
|
|
|
if (len == 0) {
|
|
|
|
cmd_free_argv(argc, *argv);
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
arglen = strlen(buf) + 1;
|
|
|
|
(*argv)[i] = xstrdup(buf);
|
2018-08-02 18:35:21 +00:00
|
|
|
|
2009-07-26 12:58:44 +00:00
|
|
|
buf += arglen;
|
|
|
|
len -= arglen;
|
|
|
|
}
|
2019-05-25 06:58:10 +00:00
|
|
|
cmd_log_argv(argc, *argv, "%s", __func__);
|
2009-07-26 12:58:44 +00:00
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2020-04-13 08:26:27 +00:00
|
|
|
/* Copy an argument vector, ensuring it is terminated by NULL. */
|
2010-10-29 20:11:57 +00:00
|
|
|
char **
|
2014-05-09 09:11:24 +00:00
|
|
|
cmd_copy_argv(int argc, char **argv)
|
2010-10-29 20:11:57 +00:00
|
|
|
{
|
|
|
|
char **new_argv;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (argc == 0)
|
|
|
|
return (NULL);
|
2014-05-13 08:08:32 +00:00
|
|
|
new_argv = xcalloc(argc + 1, sizeof *new_argv);
|
2010-10-29 20:11:57 +00:00
|
|
|
for (i = 0; i < argc; i++) {
|
|
|
|
if (argv[i] != NULL)
|
|
|
|
new_argv[i] = xstrdup(argv[i]);
|
|
|
|
}
|
|
|
|
return (new_argv);
|
|
|
|
}
|
|
|
|
|
2020-04-13 08:26:27 +00:00
|
|
|
/* Free an argument vector. */
|
2009-07-26 12:58:44 +00:00
|
|
|
void
|
|
|
|
cmd_free_argv(int argc, char **argv)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (argc == 0)
|
2009-12-03 22:50:09 +00:00
|
|
|
return;
|
2012-07-10 11:53:01 +00:00
|
|
|
for (i = 0; i < argc; i++)
|
|
|
|
free(argv[i]);
|
|
|
|
free(argv);
|
2009-07-26 12:58:44 +00:00
|
|
|
}
|
|
|
|
|
2020-04-13 08:26:27 +00:00
|
|
|
/* Convert argument vector to a string. */
|
2014-05-13 08:08:32 +00:00
|
|
|
char *
|
|
|
|
cmd_stringify_argv(int argc, char **argv)
|
|
|
|
{
|
|
|
|
char *buf;
|
|
|
|
int i;
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
if (argc == 0)
|
|
|
|
return (xstrdup(""));
|
|
|
|
|
|
|
|
len = 0;
|
|
|
|
buf = NULL;
|
|
|
|
|
|
|
|
for (i = 0; i < argc; i++) {
|
|
|
|
len += strlen(argv[i]) + 1;
|
2014-10-08 17:35:58 +00:00
|
|
|
buf = xrealloc(buf, len);
|
2014-05-13 08:08:32 +00:00
|
|
|
|
|
|
|
if (i == 0)
|
|
|
|
*buf = '\0';
|
|
|
|
else
|
|
|
|
strlcat(buf, " ", len);
|
|
|
|
strlcat(buf, argv[i], len);
|
|
|
|
}
|
|
|
|
return (buf);
|
|
|
|
}
|
|
|
|
|
2020-04-13 08:26:27 +00:00
|
|
|
/* Get entry for command. */
|
|
|
|
const struct cmd_entry *
|
|
|
|
cmd_get_entry(struct cmd *cmd)
|
|
|
|
{
|
|
|
|
return (cmd->entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get arguments for command. */
|
|
|
|
struct args *
|
|
|
|
cmd_get_args(struct cmd *cmd)
|
|
|
|
{
|
|
|
|
return (cmd->args);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get file and line for command. */
|
|
|
|
void
|
|
|
|
cmd_get_source(struct cmd *cmd, const char **file, u_int *line)
|
|
|
|
{
|
|
|
|
if (file != NULL)
|
|
|
|
*file = cmd->file;
|
|
|
|
if (line != NULL)
|
|
|
|
*line = cmd->line;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Look for an alias for a command. */
|
2019-05-23 11:13:30 +00:00
|
|
|
char *
|
|
|
|
cmd_get_alias(const char *name)
|
2017-01-24 19:59:19 +00:00
|
|
|
{
|
2019-05-23 11:13:30 +00:00
|
|
|
struct options_entry *o;
|
|
|
|
struct options_array_item *a;
|
|
|
|
union options_value *ov;
|
|
|
|
size_t wanted, n;
|
|
|
|
const char *equals;
|
2017-01-24 19:59:19 +00:00
|
|
|
|
|
|
|
o = options_get_only(global_options, "command-alias");
|
2019-03-18 11:58:40 +00:00
|
|
|
if (o == NULL)
|
2019-05-23 11:13:30 +00:00
|
|
|
return (NULL);
|
|
|
|
wanted = strlen(name);
|
2019-03-18 11:58:40 +00:00
|
|
|
|
|
|
|
a = options_array_first(o);
|
|
|
|
while (a != NULL) {
|
2019-04-23 20:36:55 +00:00
|
|
|
ov = options_array_item_value(a);
|
2019-05-23 11:13:30 +00:00
|
|
|
|
|
|
|
equals = strchr(ov->string, '=');
|
|
|
|
if (equals != NULL) {
|
|
|
|
n = equals - ov->string;
|
|
|
|
if (n == wanted && strncmp(name, ov->string, n) == 0)
|
|
|
|
return (xstrdup(equals + 1));
|
|
|
|
}
|
|
|
|
|
2019-03-18 11:58:40 +00:00
|
|
|
a = options_array_next(a);
|
2017-01-24 19:59:19 +00:00
|
|
|
}
|
2019-05-23 11:13:30 +00:00
|
|
|
return (NULL);
|
|
|
|
}
|
2017-01-24 19:59:19 +00:00
|
|
|
|
2020-04-13 08:26:27 +00:00
|
|
|
/* Look up a command entry by name. */
|
2019-05-23 11:13:30 +00:00
|
|
|
static const struct cmd_entry *
|
|
|
|
cmd_find(const char *name, char **cause)
|
|
|
|
{
|
2019-05-25 10:44:09 +00:00
|
|
|
const struct cmd_entry **loop, *entry, *found = NULL;
|
|
|
|
int ambiguous;
|
2019-10-03 10:24:05 +00:00
|
|
|
char s[8192];
|
2017-01-24 19:59:19 +00:00
|
|
|
|
2019-05-23 11:13:30 +00:00
|
|
|
ambiguous = 0;
|
|
|
|
for (loop = cmd_table; *loop != NULL; loop++) {
|
|
|
|
entry = *loop;
|
|
|
|
if (entry->alias != NULL && strcmp(entry->alias, name) == 0) {
|
|
|
|
ambiguous = 0;
|
|
|
|
found = entry;
|
|
|
|
break;
|
|
|
|
}
|
2017-01-24 19:59:19 +00:00
|
|
|
|
2019-05-23 11:13:30 +00:00
|
|
|
if (strncmp(entry->name, name, strlen(name)) != 0)
|
|
|
|
continue;
|
|
|
|
if (found != NULL)
|
|
|
|
ambiguous = 1;
|
|
|
|
found = entry;
|
2017-01-24 19:59:19 +00:00
|
|
|
|
2019-05-23 11:13:30 +00:00
|
|
|
if (strcmp(entry->name, name) == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (ambiguous)
|
|
|
|
goto ambiguous;
|
|
|
|
if (found == NULL) {
|
|
|
|
xasprintf(cause, "unknown command: %s", name);
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
return (found);
|
2017-01-24 19:59:19 +00:00
|
|
|
|
2019-05-23 11:13:30 +00:00
|
|
|
ambiguous:
|
|
|
|
*s = '\0';
|
|
|
|
for (loop = cmd_table; *loop != NULL; loop++) {
|
|
|
|
entry = *loop;
|
|
|
|
if (strncmp(entry->name, name, strlen(name)) != 0)
|
|
|
|
continue;
|
|
|
|
if (strlcat(s, entry->name, sizeof s) >= sizeof s)
|
|
|
|
break;
|
|
|
|
if (strlcat(s, ", ", sizeof s) >= sizeof s)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
s[strlen(s) - 2] = '\0';
|
|
|
|
xasprintf(cause, "ambiguous command: %s, could be: %s", name, s);
|
|
|
|
return (NULL);
|
2017-01-24 19:59:19 +00:00
|
|
|
}
|
|
|
|
|
2020-04-13 08:26:27 +00:00
|
|
|
/* Parse a single command from an argument vector. */
|
2009-06-01 22:58:49 +00:00
|
|
|
struct cmd *
|
2013-03-24 09:54:10 +00:00
|
|
|
cmd_parse(int argc, char **argv, const char *file, u_int line, char **cause)
|
2009-06-01 22:58:49 +00:00
|
|
|
{
|
2019-05-23 11:13:30 +00:00
|
|
|
const struct cmd_entry *entry;
|
2017-01-24 19:59:19 +00:00
|
|
|
const char *name;
|
2009-10-26 21:42:04 +00:00
|
|
|
struct cmd *cmd;
|
2011-01-04 00:42:46 +00:00
|
|
|
struct args *args;
|
2009-06-01 22:58:49 +00:00
|
|
|
|
2009-06-04 23:34:32 +00:00
|
|
|
if (argc == 0) {
|
|
|
|
xasprintf(cause, "no command");
|
2009-06-01 22:58:49 +00:00
|
|
|
return (NULL);
|
2009-06-04 23:34:32 +00:00
|
|
|
}
|
2017-01-24 19:59:19 +00:00
|
|
|
name = argv[0];
|
2009-06-01 22:58:49 +00:00
|
|
|
|
2019-05-23 11:13:30 +00:00
|
|
|
entry = cmd_find(name, cause);
|
|
|
|
if (entry == NULL)
|
2009-06-01 22:58:49 +00:00
|
|
|
return (NULL);
|
2019-05-25 06:58:10 +00:00
|
|
|
cmd_log_argv(argc, argv, "%s: %s", __func__, entry->name);
|
2009-06-01 22:58:49 +00:00
|
|
|
|
2015-12-13 21:53:57 +00:00
|
|
|
args = args_parse(entry->args.template, argc, argv);
|
2011-01-04 00:42:46 +00:00
|
|
|
if (args == NULL)
|
|
|
|
goto usage;
|
2015-12-13 21:53:57 +00:00
|
|
|
if (entry->args.lower != -1 && args->argc < entry->args.lower)
|
2011-01-04 00:42:46 +00:00
|
|
|
goto usage;
|
2015-12-13 21:53:57 +00:00
|
|
|
if (entry->args.upper != -1 && args->argc > entry->args.upper)
|
2011-01-04 00:42:46 +00:00
|
|
|
goto usage;
|
2009-06-01 22:58:49 +00:00
|
|
|
|
2013-03-24 09:54:10 +00:00
|
|
|
cmd = xcalloc(1, sizeof *cmd);
|
2009-06-01 22:58:49 +00:00
|
|
|
cmd->entry = entry;
|
2011-01-04 00:42:46 +00:00
|
|
|
cmd->args = args;
|
2013-03-24 09:54:10 +00:00
|
|
|
|
|
|
|
if (file != NULL)
|
|
|
|
cmd->file = xstrdup(file);
|
|
|
|
cmd->line = line;
|
|
|
|
|
2019-05-23 11:13:30 +00:00
|
|
|
cmd->alias = NULL;
|
|
|
|
cmd->argc = argc;
|
|
|
|
cmd->argv = cmd_copy_argv(argc, argv);
|
2009-06-01 22:58:49 +00:00
|
|
|
|
2019-05-23 11:13:30 +00:00
|
|
|
return (cmd);
|
2009-06-01 22:58:49 +00:00
|
|
|
|
|
|
|
usage:
|
2011-01-04 00:42:46 +00:00
|
|
|
if (args != NULL)
|
|
|
|
args_free(args);
|
2009-06-01 22:58:49 +00:00
|
|
|
xasprintf(cause, "usage: %s %s", entry->name, entry->usage);
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
2020-04-13 08:26:27 +00:00
|
|
|
/* Free a command. */
|
2019-05-23 11:13:30 +00:00
|
|
|
void
|
|
|
|
cmd_free(struct cmd *cmd)
|
|
|
|
{
|
|
|
|
free(cmd->alias);
|
|
|
|
cmd_free_argv(cmd->argc, cmd->argv);
|
|
|
|
|
|
|
|
free(cmd->file);
|
|
|
|
|
|
|
|
args_free(cmd->args);
|
|
|
|
free(cmd);
|
|
|
|
}
|
|
|
|
|
2020-04-13 08:26:27 +00:00
|
|
|
/* Get a command as a string. */
|
2015-11-27 15:06:43 +00:00
|
|
|
char *
|
|
|
|
cmd_print(struct cmd *cmd)
|
2009-06-01 22:58:49 +00:00
|
|
|
{
|
2015-11-27 15:06:43 +00:00
|
|
|
char *out, *s;
|
2011-01-04 00:42:46 +00:00
|
|
|
|
2015-11-27 15:06:43 +00:00
|
|
|
s = args_print(cmd->args);
|
|
|
|
if (*s != '\0')
|
|
|
|
xasprintf(&out, "%s %s", cmd->entry->name, s);
|
|
|
|
else
|
|
|
|
out = xstrdup(cmd->entry->name);
|
|
|
|
free(s);
|
|
|
|
|
|
|
|
return (out);
|
2009-06-01 22:58:49 +00:00
|
|
|
}
|
|
|
|
|
2020-04-13 08:26:27 +00:00
|
|
|
/* Create a new command list. */
|
2019-05-25 10:44:09 +00:00
|
|
|
struct cmd_list *
|
|
|
|
cmd_list_new(void)
|
|
|
|
{
|
|
|
|
struct cmd_list *cmdlist;
|
|
|
|
|
|
|
|
cmdlist = xcalloc(1, sizeof *cmdlist);
|
|
|
|
cmdlist->references = 1;
|
|
|
|
cmdlist->group = cmd_list_next_group++;
|
2020-04-13 08:26:27 +00:00
|
|
|
cmdlist->list = xcalloc(1, sizeof *cmdlist->list);
|
|
|
|
TAILQ_INIT(cmdlist->list);
|
2019-05-25 10:44:09 +00:00
|
|
|
return (cmdlist);
|
|
|
|
}
|
|
|
|
|
2020-04-13 08:26:27 +00:00
|
|
|
/* Append a command to a command list. */
|
2019-05-25 10:44:09 +00:00
|
|
|
void
|
|
|
|
cmd_list_append(struct cmd_list *cmdlist, struct cmd *cmd)
|
|
|
|
{
|
|
|
|
cmd->group = cmdlist->group;
|
2020-04-13 08:26:27 +00:00
|
|
|
TAILQ_INSERT_TAIL(cmdlist->list, cmd, qentry);
|
2019-05-25 10:44:09 +00:00
|
|
|
}
|
|
|
|
|
2020-04-13 08:26:27 +00:00
|
|
|
/* Move all commands from one command list to another */
|
2019-05-25 10:44:09 +00:00
|
|
|
void
|
|
|
|
cmd_list_move(struct cmd_list *cmdlist, struct cmd_list *from)
|
|
|
|
{
|
|
|
|
struct cmd *cmd, *cmd1;
|
|
|
|
|
2020-04-13 08:26:27 +00:00
|
|
|
TAILQ_FOREACH_SAFE(cmd, from->list, qentry, cmd1) {
|
|
|
|
TAILQ_REMOVE(from->list, cmd, qentry);
|
|
|
|
TAILQ_INSERT_TAIL(cmdlist->list, cmd, qentry);
|
2019-05-25 10:44:09 +00:00
|
|
|
}
|
|
|
|
cmdlist->group = cmd_list_next_group++;
|
|
|
|
}
|
|
|
|
|
2020-04-13 08:26:27 +00:00
|
|
|
/* Free a command list. */
|
2019-05-25 10:44:09 +00:00
|
|
|
void
|
|
|
|
cmd_list_free(struct cmd_list *cmdlist)
|
|
|
|
{
|
|
|
|
struct cmd *cmd, *cmd1;
|
|
|
|
|
|
|
|
if (--cmdlist->references != 0)
|
|
|
|
return;
|
|
|
|
|
2020-04-13 08:26:27 +00:00
|
|
|
TAILQ_FOREACH_SAFE(cmd, cmdlist->list, qentry, cmd1) {
|
|
|
|
TAILQ_REMOVE(cmdlist->list, cmd, qentry);
|
2019-05-25 10:44:09 +00:00
|
|
|
cmd_free(cmd);
|
|
|
|
}
|
2020-04-13 08:26:27 +00:00
|
|
|
free(cmdlist->list);
|
2019-05-25 10:44:09 +00:00
|
|
|
free(cmdlist);
|
|
|
|
}
|
|
|
|
|
2020-04-13 08:26:27 +00:00
|
|
|
/* Get a command list as a string. */
|
2019-05-25 10:44:09 +00:00
|
|
|
char *
|
|
|
|
cmd_list_print(struct cmd_list *cmdlist, int escaped)
|
|
|
|
{
|
|
|
|
struct cmd *cmd;
|
|
|
|
char *buf, *this;
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
len = 1;
|
|
|
|
buf = xcalloc(1, len);
|
|
|
|
|
2020-04-13 08:26:27 +00:00
|
|
|
TAILQ_FOREACH(cmd, cmdlist->list, qentry) {
|
2019-05-25 10:44:09 +00:00
|
|
|
this = cmd_print(cmd);
|
|
|
|
|
|
|
|
len += strlen(this) + 4;
|
|
|
|
buf = xrealloc(buf, len);
|
|
|
|
|
|
|
|
strlcat(buf, this, len);
|
|
|
|
if (TAILQ_NEXT(cmd, qentry) != NULL) {
|
|
|
|
if (escaped)
|
|
|
|
strlcat(buf, " \\; ", len);
|
|
|
|
else
|
|
|
|
strlcat(buf, " ; ", len);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (buf);
|
|
|
|
}
|
|
|
|
|
2020-04-13 08:26:27 +00:00
|
|
|
/* Get first command in list. */
|
|
|
|
struct cmd *
|
|
|
|
cmd_list_first(struct cmd_list *cmdlist, u_int *group)
|
|
|
|
{
|
|
|
|
struct cmd *cmd;
|
|
|
|
|
|
|
|
cmd = TAILQ_FIRST(cmdlist->list);
|
|
|
|
if (cmd != NULL && group != NULL)
|
|
|
|
*group = cmd->group;
|
|
|
|
return (cmd);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get next command in list. */
|
|
|
|
struct cmd *
|
|
|
|
cmd_list_next(struct cmd *cmd, u_int *group)
|
|
|
|
{
|
|
|
|
cmd = TAILQ_NEXT(cmd, qentry);
|
|
|
|
if (cmd != NULL && group != NULL)
|
|
|
|
*group = cmd->group;
|
|
|
|
return (cmd);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Do all of the commands in this command list have this flag? */
|
|
|
|
int
|
|
|
|
cmd_list_all_have(struct cmd_list *cmdlist, int flag)
|
|
|
|
{
|
|
|
|
struct cmd *cmd;
|
|
|
|
|
|
|
|
TAILQ_FOREACH(cmd, cmdlist->list, qentry) {
|
|
|
|
if (~cmd->entry->flags & flag)
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Do any of the commands in this command list have this flag? */
|
|
|
|
int
|
|
|
|
cmd_list_any_have(struct cmd_list *cmdlist, int flag)
|
|
|
|
{
|
|
|
|
struct cmd *cmd;
|
|
|
|
|
|
|
|
TAILQ_FOREACH(cmd, cmdlist->list, qentry) {
|
|
|
|
if (cmd->entry->flags & flag)
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2015-04-19 21:34:21 +00:00
|
|
|
/* Adjust current mouse position for a pane. */
|
|
|
|
int
|
|
|
|
cmd_mouse_at(struct window_pane *wp, struct mouse_event *m, u_int *xp,
|
|
|
|
u_int *yp, int last)
|
|
|
|
{
|
|
|
|
u_int x, y;
|
|
|
|
|
|
|
|
if (last) {
|
2019-05-03 16:51:29 +00:00
|
|
|
x = m->lx + m->ox;
|
|
|
|
y = m->ly + m->oy;
|
2015-04-19 21:34:21 +00:00
|
|
|
} else {
|
2019-05-03 18:42:40 +00:00
|
|
|
x = m->x + m->ox;
|
|
|
|
y = m->y + m->oy;
|
2015-04-19 21:34:21 +00:00
|
|
|
}
|
2019-05-03 16:51:29 +00:00
|
|
|
log_debug("%s: x=%u, y=%u%s", __func__, x, y, last ? " (last)" : "");
|
2015-04-19 21:34:21 +00:00
|
|
|
|
2019-07-06 20:56:34 +00:00
|
|
|
if (m->statusat == 0 && y >= m->statuslines)
|
|
|
|
y -= m->statuslines;
|
2015-04-19 21:34:21 +00:00
|
|
|
|
|
|
|
if (x < wp->xoff || x >= wp->xoff + wp->sx)
|
|
|
|
return (-1);
|
|
|
|
if (y < wp->yoff || y >= wp->yoff + wp->sy)
|
|
|
|
return (-1);
|
|
|
|
|
2016-10-05 12:32:13 +00:00
|
|
|
if (xp != NULL)
|
|
|
|
*xp = x - wp->xoff;
|
|
|
|
if (yp != NULL)
|
|
|
|
*yp = y - wp->yoff;
|
2015-04-19 21:34:21 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get current mouse window if any. */
|
|
|
|
struct winlink *
|
|
|
|
cmd_mouse_window(struct mouse_event *m, struct session **sp)
|
|
|
|
{
|
|
|
|
struct session *s;
|
|
|
|
struct window *w;
|
2019-05-08 18:05:03 +00:00
|
|
|
struct winlink *wl;
|
2015-04-19 21:34:21 +00:00
|
|
|
|
2019-05-08 18:05:03 +00:00
|
|
|
if (!m->valid)
|
2015-04-19 21:34:21 +00:00
|
|
|
return (NULL);
|
2019-05-08 18:05:03 +00:00
|
|
|
if (m->s == -1 || (s = session_find_by_id(m->s)) == NULL)
|
2015-04-19 21:34:21 +00:00
|
|
|
return (NULL);
|
2019-05-08 18:05:03 +00:00
|
|
|
if (m->w == -1)
|
|
|
|
wl = s->curw;
|
|
|
|
else {
|
|
|
|
if ((w = window_find_by_id(m->w)) == NULL)
|
|
|
|
return (NULL);
|
|
|
|
wl = winlink_find_by_window(&s->windows, w);
|
|
|
|
}
|
2015-04-19 21:34:21 +00:00
|
|
|
if (sp != NULL)
|
|
|
|
*sp = s;
|
2019-05-08 18:05:03 +00:00
|
|
|
return (wl);
|
2015-04-19 21:34:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Get current mouse pane if any. */
|
|
|
|
struct window_pane *
|
2015-04-27 16:25:57 +00:00
|
|
|
cmd_mouse_pane(struct mouse_event *m, struct session **sp,
|
|
|
|
struct winlink **wlp)
|
2015-04-19 21:34:21 +00:00
|
|
|
{
|
|
|
|
struct winlink *wl;
|
|
|
|
struct window_pane *wp;
|
|
|
|
|
|
|
|
if ((wl = cmd_mouse_window(m, sp)) == NULL)
|
|
|
|
return (NULL);
|
|
|
|
if ((wp = window_pane_find_by_id(m->wp)) == NULL)
|
|
|
|
return (NULL);
|
|
|
|
if (!window_has_pane(wl->window, wp))
|
|
|
|
return (NULL);
|
|
|
|
|
|
|
|
if (wlp != NULL)
|
|
|
|
*wlp = wl;
|
|
|
|
return (wp);
|
|
|
|
}
|
|
|
|
|
2009-08-25 12:18:51 +00:00
|
|
|
/* Replace the first %% or %idx in template by s. */
|
|
|
|
char *
|
2013-03-21 16:22:48 +00:00
|
|
|
cmd_template_replace(const char *template, const char *s, int idx)
|
2009-08-25 12:18:51 +00:00
|
|
|
{
|
2013-03-21 16:22:48 +00:00
|
|
|
char ch, *buf;
|
2020-01-04 18:01:56 +00:00
|
|
|
const char *ptr, *cp, quote[] = "\"\\$;~";
|
2016-10-21 13:51:59 +00:00
|
|
|
int replaced, quoted;
|
2013-03-25 11:53:54 +00:00
|
|
|
size_t len;
|
2009-08-25 12:18:51 +00:00
|
|
|
|
2013-03-21 16:22:48 +00:00
|
|
|
if (strchr(template, '%') == NULL)
|
2009-08-25 12:18:51 +00:00
|
|
|
return (xstrdup(template));
|
|
|
|
|
|
|
|
buf = xmalloc(1);
|
|
|
|
*buf = '\0';
|
|
|
|
len = 0;
|
|
|
|
replaced = 0;
|
|
|
|
|
|
|
|
ptr = template;
|
|
|
|
while (*ptr != '\0') {
|
|
|
|
switch (ch = *ptr++) {
|
|
|
|
case '%':
|
|
|
|
if (*ptr < '1' || *ptr > '9' || *ptr - '0' != idx) {
|
|
|
|
if (*ptr != '%' || replaced)
|
|
|
|
break;
|
|
|
|
replaced = 1;
|
|
|
|
}
|
|
|
|
ptr++;
|
|
|
|
|
2016-10-21 13:51:59 +00:00
|
|
|
quoted = (*ptr == '%');
|
|
|
|
if (quoted)
|
|
|
|
ptr++;
|
|
|
|
|
2017-01-10 18:10:24 +00:00
|
|
|
buf = xrealloc(buf, len + (strlen(s) * 3) + 1);
|
2016-10-21 13:51:59 +00:00
|
|
|
for (cp = s; *cp != '\0'; cp++) {
|
2017-01-10 11:58:30 +00:00
|
|
|
if (quoted && strchr(quote, *cp) != NULL)
|
2016-10-21 13:51:59 +00:00
|
|
|
buf[len++] = '\\';
|
|
|
|
buf[len++] = *cp;
|
|
|
|
}
|
|
|
|
buf[len] = '\0';
|
2009-08-25 12:18:51 +00:00
|
|
|
continue;
|
|
|
|
}
|
2014-10-08 17:35:58 +00:00
|
|
|
buf = xrealloc(buf, len + 2);
|
2009-08-25 12:18:51 +00:00
|
|
|
buf[len++] = ch;
|
|
|
|
buf[len] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
return (buf);
|
|
|
|
}
|