File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / tmux / cmd.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 14 12:22:44 2017 UTC (7 years ago) by misho
Branches: tmux, MAIN
CVS tags: v2_4p0, v2_4, HEAD
tmux 2.4

    1: /* $OpenBSD$ */
    2: 
    3: /*
    4:  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
    5:  *
    6:  * Permission to use, copy, modify, and distribute this software for any
    7:  * purpose with or without fee is hereby granted, provided that the above
    8:  * copyright notice and this permission notice appear in all copies.
    9:  *
   10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   14:  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
   15:  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
   16:  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   17:  */
   18: 
   19: #include <sys/types.h>
   20: #include <sys/time.h>
   21: 
   22: #include <fnmatch.h>
   23: #include <pwd.h>
   24: #include <stdlib.h>
   25: #include <string.h>
   26: #include <unistd.h>
   27: 
   28: #include "tmux.h"
   29: 
   30: extern const struct cmd_entry cmd_attach_session_entry;
   31: extern const struct cmd_entry cmd_bind_key_entry;
   32: extern const struct cmd_entry cmd_break_pane_entry;
   33: extern const struct cmd_entry cmd_capture_pane_entry;
   34: extern const struct cmd_entry cmd_choose_buffer_entry;
   35: extern const struct cmd_entry cmd_choose_client_entry;
   36: extern const struct cmd_entry cmd_choose_session_entry;
   37: extern const struct cmd_entry cmd_choose_tree_entry;
   38: extern const struct cmd_entry cmd_choose_window_entry;
   39: extern const struct cmd_entry cmd_clear_history_entry;
   40: extern const struct cmd_entry cmd_clock_mode_entry;
   41: extern const struct cmd_entry cmd_command_prompt_entry;
   42: extern const struct cmd_entry cmd_confirm_before_entry;
   43: extern const struct cmd_entry cmd_copy_mode_entry;
   44: extern const struct cmd_entry cmd_delete_buffer_entry;
   45: extern const struct cmd_entry cmd_detach_client_entry;
   46: extern const struct cmd_entry cmd_display_message_entry;
   47: extern const struct cmd_entry cmd_display_panes_entry;
   48: extern const struct cmd_entry cmd_down_pane_entry;
   49: extern const struct cmd_entry cmd_find_window_entry;
   50: extern const struct cmd_entry cmd_has_session_entry;
   51: extern const struct cmd_entry cmd_if_shell_entry;
   52: extern const struct cmd_entry cmd_join_pane_entry;
   53: extern const struct cmd_entry cmd_kill_pane_entry;
   54: extern const struct cmd_entry cmd_kill_server_entry;
   55: extern const struct cmd_entry cmd_kill_session_entry;
   56: extern const struct cmd_entry cmd_kill_window_entry;
   57: extern const struct cmd_entry cmd_last_pane_entry;
   58: extern const struct cmd_entry cmd_last_window_entry;
   59: extern const struct cmd_entry cmd_link_window_entry;
   60: extern const struct cmd_entry cmd_list_buffers_entry;
   61: extern const struct cmd_entry cmd_list_clients_entry;
   62: extern const struct cmd_entry cmd_list_commands_entry;
   63: extern const struct cmd_entry cmd_list_keys_entry;
   64: extern const struct cmd_entry cmd_list_panes_entry;
   65: extern const struct cmd_entry cmd_list_sessions_entry;
   66: extern const struct cmd_entry cmd_list_windows_entry;
   67: extern const struct cmd_entry cmd_load_buffer_entry;
   68: extern const struct cmd_entry cmd_lock_client_entry;
   69: extern const struct cmd_entry cmd_lock_server_entry;
   70: extern const struct cmd_entry cmd_lock_session_entry;
   71: extern const struct cmd_entry cmd_move_pane_entry;
   72: extern const struct cmd_entry cmd_move_window_entry;
   73: extern const struct cmd_entry cmd_new_session_entry;
   74: extern const struct cmd_entry cmd_new_window_entry;
   75: extern const struct cmd_entry cmd_next_layout_entry;
   76: extern const struct cmd_entry cmd_next_window_entry;
   77: extern const struct cmd_entry cmd_paste_buffer_entry;
   78: extern const struct cmd_entry cmd_pipe_pane_entry;
   79: extern const struct cmd_entry cmd_previous_layout_entry;
   80: extern const struct cmd_entry cmd_previous_window_entry;
   81: extern const struct cmd_entry cmd_refresh_client_entry;
   82: extern const struct cmd_entry cmd_rename_session_entry;
   83: extern const struct cmd_entry cmd_rename_window_entry;
   84: extern const struct cmd_entry cmd_resize_pane_entry;
   85: extern const struct cmd_entry cmd_respawn_pane_entry;
   86: extern const struct cmd_entry cmd_respawn_window_entry;
   87: extern const struct cmd_entry cmd_rotate_window_entry;
   88: extern const struct cmd_entry cmd_run_shell_entry;
   89: extern const struct cmd_entry cmd_save_buffer_entry;
   90: extern const struct cmd_entry cmd_select_layout_entry;
   91: extern const struct cmd_entry cmd_select_pane_entry;
   92: extern const struct cmd_entry cmd_select_window_entry;
   93: extern const struct cmd_entry cmd_send_keys_entry;
   94: extern const struct cmd_entry cmd_send_prefix_entry;
   95: extern const struct cmd_entry cmd_set_buffer_entry;
   96: extern const struct cmd_entry cmd_set_environment_entry;
   97: extern const struct cmd_entry cmd_set_hook_entry;
   98: extern const struct cmd_entry cmd_set_option_entry;
   99: extern const struct cmd_entry cmd_set_window_option_entry;
  100: extern const struct cmd_entry cmd_show_buffer_entry;
  101: extern const struct cmd_entry cmd_show_environment_entry;
  102: extern const struct cmd_entry cmd_show_hooks_entry;
  103: extern const struct cmd_entry cmd_show_messages_entry;
  104: extern const struct cmd_entry cmd_show_options_entry;
  105: extern const struct cmd_entry cmd_show_window_options_entry;
  106: extern const struct cmd_entry cmd_source_file_entry;
  107: extern const struct cmd_entry cmd_split_window_entry;
  108: extern const struct cmd_entry cmd_start_server_entry;
  109: extern const struct cmd_entry cmd_suspend_client_entry;
  110: extern const struct cmd_entry cmd_swap_pane_entry;
  111: extern const struct cmd_entry cmd_swap_window_entry;
  112: extern const struct cmd_entry cmd_switch_client_entry;
  113: extern const struct cmd_entry cmd_unbind_key_entry;
  114: extern const struct cmd_entry cmd_unlink_window_entry;
  115: extern const struct cmd_entry cmd_up_pane_entry;
  116: extern const struct cmd_entry cmd_wait_for_entry;
  117: 
  118: const struct cmd_entry *cmd_table[] = {
  119: 	&cmd_attach_session_entry,
  120: 	&cmd_bind_key_entry,
  121: 	&cmd_break_pane_entry,
  122: 	&cmd_capture_pane_entry,
  123: 	&cmd_choose_buffer_entry,
  124: 	&cmd_choose_client_entry,
  125: 	&cmd_choose_session_entry,
  126: 	&cmd_choose_tree_entry,
  127: 	&cmd_choose_window_entry,
  128: 	&cmd_clear_history_entry,
  129: 	&cmd_clock_mode_entry,
  130: 	&cmd_command_prompt_entry,
  131: 	&cmd_confirm_before_entry,
  132: 	&cmd_copy_mode_entry,
  133: 	&cmd_delete_buffer_entry,
  134: 	&cmd_detach_client_entry,
  135: 	&cmd_display_message_entry,
  136: 	&cmd_display_panes_entry,
  137: 	&cmd_find_window_entry,
  138: 	&cmd_has_session_entry,
  139: 	&cmd_if_shell_entry,
  140: 	&cmd_join_pane_entry,
  141: 	&cmd_kill_pane_entry,
  142: 	&cmd_kill_server_entry,
  143: 	&cmd_kill_session_entry,
  144: 	&cmd_kill_window_entry,
  145: 	&cmd_last_pane_entry,
  146: 	&cmd_last_window_entry,
  147: 	&cmd_link_window_entry,
  148: 	&cmd_list_buffers_entry,
  149: 	&cmd_list_clients_entry,
  150: 	&cmd_list_commands_entry,
  151: 	&cmd_list_keys_entry,
  152: 	&cmd_list_panes_entry,
  153: 	&cmd_list_sessions_entry,
  154: 	&cmd_list_windows_entry,
  155: 	&cmd_load_buffer_entry,
  156: 	&cmd_lock_client_entry,
  157: 	&cmd_lock_server_entry,
  158: 	&cmd_lock_session_entry,
  159: 	&cmd_move_pane_entry,
  160: 	&cmd_move_window_entry,
  161: 	&cmd_new_session_entry,
  162: 	&cmd_new_window_entry,
  163: 	&cmd_next_layout_entry,
  164: 	&cmd_next_window_entry,
  165: 	&cmd_paste_buffer_entry,
  166: 	&cmd_pipe_pane_entry,
  167: 	&cmd_previous_layout_entry,
  168: 	&cmd_previous_window_entry,
  169: 	&cmd_refresh_client_entry,
  170: 	&cmd_rename_session_entry,
  171: 	&cmd_rename_window_entry,
  172: 	&cmd_resize_pane_entry,
  173: 	&cmd_respawn_pane_entry,
  174: 	&cmd_respawn_window_entry,
  175: 	&cmd_rotate_window_entry,
  176: 	&cmd_run_shell_entry,
  177: 	&cmd_save_buffer_entry,
  178: 	&cmd_select_layout_entry,
  179: 	&cmd_select_pane_entry,
  180: 	&cmd_select_window_entry,
  181: 	&cmd_send_keys_entry,
  182: 	&cmd_send_prefix_entry,
  183: 	&cmd_set_buffer_entry,
  184: 	&cmd_set_environment_entry,
  185: 	&cmd_set_hook_entry,
  186: 	&cmd_set_option_entry,
  187: 	&cmd_set_window_option_entry,
  188: 	&cmd_show_buffer_entry,
  189: 	&cmd_show_environment_entry,
  190: 	&cmd_show_hooks_entry,
  191: 	&cmd_show_messages_entry,
  192: 	&cmd_show_options_entry,
  193: 	&cmd_show_window_options_entry,
  194: 	&cmd_source_file_entry,
  195: 	&cmd_split_window_entry,
  196: 	&cmd_start_server_entry,
  197: 	&cmd_suspend_client_entry,
  198: 	&cmd_swap_pane_entry,
  199: 	&cmd_swap_window_entry,
  200: 	&cmd_switch_client_entry,
  201: 	&cmd_unbind_key_entry,
  202: 	&cmd_unlink_window_entry,
  203: 	&cmd_wait_for_entry,
  204: 	NULL
  205: };
  206: 
  207: int
  208: cmd_pack_argv(int argc, char **argv, char *buf, size_t len)
  209: {
  210: 	size_t	arglen;
  211: 	int	i;
  212: 
  213: 	if (argc == 0)
  214: 		return (0);
  215: 
  216: 	*buf = '\0';
  217: 	for (i = 0; i < argc; i++) {
  218: 		if (strlcpy(buf, argv[i], len) >= len)
  219: 			return (-1);
  220: 		arglen = strlen(argv[i]) + 1;
  221: 		buf += arglen;
  222: 		len -= arglen;
  223: 	}
  224: 
  225: 	return (0);
  226: }
  227: 
  228: int
  229: cmd_unpack_argv(char *buf, size_t len, int argc, char ***argv)
  230: {
  231: 	int	i;
  232: 	size_t	arglen;
  233: 
  234: 	if (argc == 0)
  235: 		return (0);
  236: 	*argv = xcalloc(argc, sizeof **argv);
  237: 
  238: 	buf[len - 1] = '\0';
  239: 	for (i = 0; i < argc; i++) {
  240: 		if (len == 0) {
  241: 			cmd_free_argv(argc, *argv);
  242: 			return (-1);
  243: 		}
  244: 
  245: 		arglen = strlen(buf) + 1;
  246: 		(*argv)[i] = xstrdup(buf);
  247: 		buf += arglen;
  248: 		len -= arglen;
  249: 	}
  250: 
  251: 	return (0);
  252: }
  253: 
  254: char **
  255: cmd_copy_argv(int argc, char **argv)
  256: {
  257: 	char	**new_argv;
  258: 	int	  i;
  259: 
  260: 	if (argc == 0)
  261: 		return (NULL);
  262: 	new_argv = xcalloc(argc + 1, sizeof *new_argv);
  263: 	for (i = 0; i < argc; i++) {
  264: 		if (argv[i] != NULL)
  265: 			new_argv[i] = xstrdup(argv[i]);
  266: 	}
  267: 	return (new_argv);
  268: }
  269: 
  270: void
  271: cmd_free_argv(int argc, char **argv)
  272: {
  273: 	int	i;
  274: 
  275: 	if (argc == 0)
  276: 		return;
  277: 	for (i = 0; i < argc; i++)
  278: 		free(argv[i]);
  279: 	free(argv);
  280: }
  281: 
  282: char *
  283: cmd_stringify_argv(int argc, char **argv)
  284: {
  285: 	char	*buf;
  286: 	int	 i;
  287: 	size_t	 len;
  288: 
  289: 	if (argc == 0)
  290: 		return (xstrdup(""));
  291: 
  292: 	len = 0;
  293: 	buf = NULL;
  294: 
  295: 	for (i = 0; i < argc; i++) {
  296: 		len += strlen(argv[i]) + 1;
  297: 		buf = xrealloc(buf, len);
  298: 
  299: 		if (i == 0)
  300: 			*buf = '\0';
  301: 		else
  302: 			strlcat(buf, " ", len);
  303: 		strlcat(buf, argv[i], len);
  304: 	}
  305: 	return (buf);
  306: }
  307: 
  308: static int
  309: cmd_try_alias(int *argc, char ***argv)
  310: {
  311: 	struct options_entry	 *o;
  312: 	int			  old_argc = *argc, new_argc;
  313: 	char			**old_argv = *argv, **new_argv;
  314: 	u_int			  size, idx;
  315: 	int			  i;
  316: 	size_t			  wanted;
  317: 	const char		 *s, *cp = NULL;
  318: 
  319: 	o = options_get_only(global_options, "command-alias");
  320: 	if (o == NULL || options_array_size(o, &size) == -1 || size == 0)
  321: 		return (-1);
  322: 
  323: 	wanted = strlen(old_argv[0]);
  324: 	for (idx = 0; idx < size; idx++) {
  325: 		s = options_array_get(o, idx);
  326: 		if (s == NULL)
  327: 			continue;
  328: 
  329: 		cp = strchr(s, '=');
  330: 		if (cp == NULL || (size_t)(cp - s) != wanted)
  331: 			continue;
  332: 		if (strncmp(old_argv[0], s, wanted) == 0)
  333: 			break;
  334: 	}
  335: 	if (idx == size)
  336: 		return (-1);
  337: 
  338: 	if (cmd_string_split(cp + 1, &new_argc, &new_argv) != 0)
  339: 		return (-1);
  340: 
  341: 	*argc = new_argc + old_argc - 1;
  342: 	*argv = xcalloc((*argc) + 1, sizeof **argv);
  343: 
  344: 	for (i = 0; i < new_argc; i++)
  345: 		(*argv)[i] = xstrdup(new_argv[i]);
  346: 	for (i = 1; i < old_argc; i++)
  347: 		(*argv)[new_argc + i - 1] = xstrdup(old_argv[i]);
  348: 
  349: 	log_debug("alias: %s=%s", old_argv[0], cp + 1);
  350: 	for (i = 0; i < *argc; i++)
  351: 		log_debug("alias: argv[%d] = %s", i, (*argv)[i]);
  352: 
  353: 	cmd_free_argv(new_argc, new_argv);
  354: 	return (0);
  355: }
  356: 
  357: struct cmd *
  358: cmd_parse(int argc, char **argv, const char *file, u_int line, char **cause)
  359: {
  360: 	const char		*name;
  361: 	const struct cmd_entry **entryp, *entry;
  362: 	struct cmd		*cmd;
  363: 	struct args		*args;
  364: 	char			 s[BUFSIZ];
  365: 	int			 ambiguous, allocated = 0;
  366: 
  367: 	*cause = NULL;
  368: 	if (argc == 0) {
  369: 		xasprintf(cause, "no command");
  370: 		return (NULL);
  371: 	}
  372: 	name = argv[0];
  373: 
  374: retry:
  375: 	ambiguous = 0;
  376: 	entry = NULL;
  377: 	for (entryp = cmd_table; *entryp != NULL; entryp++) {
  378: 		if ((*entryp)->alias != NULL &&
  379: 		    strcmp((*entryp)->alias, argv[0]) == 0) {
  380: 			ambiguous = 0;
  381: 			entry = *entryp;
  382: 			break;
  383: 		}
  384: 
  385: 		if (strncmp((*entryp)->name, argv[0], strlen(argv[0])) != 0)
  386: 			continue;
  387: 		if (entry != NULL)
  388: 			ambiguous = 1;
  389: 		entry = *entryp;
  390: 
  391: 		/* Bail now if an exact match. */
  392: 		if (strcmp(entry->name, argv[0]) == 0)
  393: 			break;
  394: 	}
  395: 	if ((ambiguous || entry == NULL) &&
  396: 	    server_proc != NULL &&
  397: 	    !allocated &&
  398: 	    cmd_try_alias(&argc, &argv) == 0) {
  399: 		allocated = 1;
  400: 		goto retry;
  401: 	}
  402: 	if (ambiguous)
  403: 		goto ambiguous;
  404: 	if (entry == NULL) {
  405: 		xasprintf(cause, "unknown command: %s", name);
  406: 		return (NULL);
  407: 	}
  408: 
  409: 	args = args_parse(entry->args.template, argc, argv);
  410: 	if (args == NULL)
  411: 		goto usage;
  412: 	if (entry->args.lower != -1 && args->argc < entry->args.lower)
  413: 		goto usage;
  414: 	if (entry->args.upper != -1 && args->argc > entry->args.upper)
  415: 		goto usage;
  416: 
  417: 	cmd = xcalloc(1, sizeof *cmd);
  418: 	cmd->entry = entry;
  419: 	cmd->args = args;
  420: 
  421: 	if (file != NULL)
  422: 		cmd->file = xstrdup(file);
  423: 	cmd->line = line;
  424: 
  425: 	if (allocated)
  426: 		cmd_free_argv(argc, argv);
  427: 	return (cmd);
  428: 
  429: ambiguous:
  430: 	*s = '\0';
  431: 	for (entryp = cmd_table; *entryp != NULL; entryp++) {
  432: 		if (strncmp((*entryp)->name, argv[0], strlen(argv[0])) != 0)
  433: 			continue;
  434: 		if (strlcat(s, (*entryp)->name, sizeof s) >= sizeof s)
  435: 			break;
  436: 		if (strlcat(s, ", ", sizeof s) >= sizeof s)
  437: 			break;
  438: 	}
  439: 	s[strlen(s) - 2] = '\0';
  440: 	xasprintf(cause, "ambiguous command: %s, could be: %s", name, s);
  441: 	return (NULL);
  442: 
  443: usage:
  444: 	if (args != NULL)
  445: 		args_free(args);
  446: 	xasprintf(cause, "usage: %s %s", entry->name, entry->usage);
  447: 	return (NULL);
  448: }
  449: 
  450: static int
  451: cmd_prepare_state_flag(char c, const char *target, enum cmd_entry_flag flag,
  452:     struct cmdq_item *item)
  453: {
  454: 	int			 targetflags, error;
  455: 	struct cmd_find_state	*fs = NULL;
  456: 	struct cmd_find_state	 current;
  457: 
  458: 	if (flag == CMD_NONE ||
  459: 	    flag == CMD_CLIENT ||
  460: 	    flag == CMD_CLIENT_CANFAIL)
  461: 		return (0);
  462: 
  463: 	if (c == 't')
  464: 		fs = &item->state.tflag;
  465: 	else if (c == 's')
  466: 		fs = &item->state.sflag;
  467: 
  468: 	if (flag == CMD_SESSION_WITHPANE) {
  469: 		if (target != NULL && target[strcspn(target, ":.")] != '\0')
  470: 			flag = CMD_PANE;
  471: 		else
  472: 			flag = CMD_SESSION_PREFERUNATTACHED;
  473: 	}
  474: 
  475: 	targetflags = 0;
  476: 	switch (flag) {
  477: 	case CMD_SESSION:
  478: 	case CMD_SESSION_CANFAIL:
  479: 	case CMD_SESSION_PREFERUNATTACHED:
  480: 	case CMD_SESSION_WITHPANE:
  481: 		if (flag == CMD_SESSION_CANFAIL)
  482: 			targetflags |= CMD_FIND_QUIET;
  483: 		if (flag == CMD_SESSION_PREFERUNATTACHED)
  484: 			targetflags |= CMD_FIND_PREFER_UNATTACHED;
  485: 		break;
  486: 	case CMD_MOVEW_R:
  487: 		flag = CMD_WINDOW_INDEX;
  488: 		/* FALLTHROUGH */
  489: 	case CMD_WINDOW:
  490: 	case CMD_WINDOW_CANFAIL:
  491: 	case CMD_WINDOW_MARKED:
  492: 	case CMD_WINDOW_INDEX:
  493: 		if (flag == CMD_WINDOW_CANFAIL)
  494: 			targetflags |= CMD_FIND_QUIET;
  495: 		if (flag == CMD_WINDOW_MARKED)
  496: 			targetflags |= CMD_FIND_DEFAULT_MARKED;
  497: 		if (flag == CMD_WINDOW_INDEX)
  498: 			targetflags |= CMD_FIND_WINDOW_INDEX;
  499: 		break;
  500: 	case CMD_PANE:
  501: 	case CMD_PANE_CANFAIL:
  502: 	case CMD_PANE_MARKED:
  503: 		if (flag == CMD_PANE_CANFAIL)
  504: 			targetflags |= CMD_FIND_QUIET;
  505: 		if (flag == CMD_PANE_MARKED)
  506: 			targetflags |= CMD_FIND_DEFAULT_MARKED;
  507: 		break;
  508: 	default:
  509: 		fatalx("unknown %cflag %d", c, flag);
  510: 	}
  511: 	log_debug("%s: flag %c %d %#x", __func__, c, flag, targetflags);
  512: 
  513: 	error = cmd_find_current(&current, item, targetflags);
  514: 	if (error != 0) {
  515: 		if (~targetflags & CMD_FIND_QUIET)
  516: 			return (-1);
  517: 		cmd_find_clear_state(&current, NULL, 0);
  518: 	}
  519: 	if (!cmd_find_empty_state(&current) && !cmd_find_valid_state(&current))
  520: 		fatalx("invalid current state");
  521: 
  522: 	switch (flag) {
  523: 	case CMD_NONE:
  524: 	case CMD_CLIENT:
  525: 	case CMD_CLIENT_CANFAIL:
  526: 		return (0);
  527: 	case CMD_SESSION:
  528: 	case CMD_SESSION_CANFAIL:
  529: 	case CMD_SESSION_PREFERUNATTACHED:
  530: 	case CMD_SESSION_WITHPANE:
  531: 		error = cmd_find_target(fs, &current, item, target,
  532: 		    CMD_FIND_SESSION, targetflags);
  533: 		if (error != 0)
  534: 			goto error;
  535: 		break;
  536: 	case CMD_MOVEW_R:
  537: 		error = cmd_find_target(fs, &current, item, target,
  538: 		    CMD_FIND_SESSION, CMD_FIND_QUIET);
  539: 		if (error == 0)
  540: 			break;
  541: 		/* FALLTHROUGH */
  542: 	case CMD_WINDOW:
  543: 	case CMD_WINDOW_CANFAIL:
  544: 	case CMD_WINDOW_MARKED:
  545: 	case CMD_WINDOW_INDEX:
  546: 		error = cmd_find_target(fs, &current, item, target,
  547: 		    CMD_FIND_WINDOW, targetflags);
  548: 		if (error != 0)
  549: 			goto error;
  550: 		break;
  551: 	case CMD_PANE:
  552: 	case CMD_PANE_CANFAIL:
  553: 	case CMD_PANE_MARKED:
  554: 		error = cmd_find_target(fs, &current, item, target,
  555: 		    CMD_FIND_PANE, targetflags);
  556: 		if (error != 0)
  557: 			goto error;
  558: 		break;
  559: 	default:
  560: 		fatalx("unknown %cflag %d", c, flag);
  561: 	}
  562: 	return (0);
  563: 
  564: error:
  565: 	if (~targetflags & CMD_FIND_QUIET)
  566: 		return (-1);
  567: 	cmd_find_clear_state(fs, NULL, 0);
  568: 	return (0);
  569: }
  570: 
  571: int
  572: cmd_prepare_state(struct cmd *cmd, struct cmdq_item *item)
  573: {
  574: 	const struct cmd_entry	*entry = cmd->entry;
  575: 	struct cmd_state	*state = &item->state;
  576: 	char			*tmp;
  577: 	enum cmd_entry_flag	 flag;
  578: 	const char		*s;
  579: 	int			 error;
  580: 
  581: 	tmp = cmd_print(cmd);
  582: 	log_debug("preparing state for %s (client %p)", tmp, item->client);
  583: 	free(tmp);
  584: 
  585: 	state->c = NULL;
  586: 	cmd_find_clear_state(&state->tflag, NULL, 0);
  587: 	cmd_find_clear_state(&state->sflag, NULL, 0);
  588: 
  589: 	flag = cmd->entry->cflag;
  590: 	if (flag == CMD_NONE) {
  591: 		flag = cmd->entry->tflag;
  592: 		if (flag == CMD_CLIENT || flag == CMD_CLIENT_CANFAIL)
  593: 			s = args_get(cmd->args, 't');
  594: 		else
  595: 			s = NULL;
  596: 	} else
  597: 		s = args_get(cmd->args, 'c');
  598: 	switch (flag) {
  599: 	case CMD_CLIENT:
  600: 		state->c = cmd_find_client(item, s, 0);
  601: 		if (state->c == NULL)
  602: 			return (-1);
  603: 		break;
  604: 	default:
  605: 		state->c = cmd_find_client(item, s, 1);
  606: 		break;
  607: 	}
  608: 	log_debug("using client %p", state->c);
  609: 
  610: 	s = args_get(cmd->args, 't');
  611: 	log_debug("preparing -t state: target %s", s == NULL ? "none" : s);
  612: 
  613: 	error = cmd_prepare_state_flag('t', s, entry->tflag, item);
  614: 	if (error != 0)
  615: 		return (error);
  616: 
  617: 	s = args_get(cmd->args, 's');
  618: 	log_debug("preparing -s state: target %s", s == NULL ? "none" : s);
  619: 
  620: 	error = cmd_prepare_state_flag('s', s, entry->sflag, item);
  621: 	if (error != 0)
  622: 		return (error);
  623: 
  624: 	if (!cmd_find_empty_state(&state->tflag) &&
  625: 	    !cmd_find_valid_state(&state->tflag))
  626: 		fatalx("invalid -t state");
  627: 	if (!cmd_find_empty_state(&state->sflag) &&
  628: 	    !cmd_find_valid_state(&state->sflag))
  629: 		fatalx("invalid -s state");
  630: 
  631: 	return (0);
  632: }
  633: 
  634: char *
  635: cmd_print(struct cmd *cmd)
  636: {
  637: 	char	*out, *s;
  638: 
  639: 	s = args_print(cmd->args);
  640: 	if (*s != '\0')
  641: 		xasprintf(&out, "%s %s", cmd->entry->name, s);
  642: 	else
  643: 		out = xstrdup(cmd->entry->name);
  644: 	free(s);
  645: 
  646: 	return (out);
  647: }
  648: 
  649: /* Adjust current mouse position for a pane. */
  650: int
  651: cmd_mouse_at(struct window_pane *wp, struct mouse_event *m, u_int *xp,
  652:     u_int *yp, int last)
  653: {
  654: 	u_int	x, y;
  655: 
  656: 	if (last) {
  657: 		x = m->lx;
  658: 		y = m->ly;
  659: 	} else {
  660: 		x = m->x;
  661: 		y = m->y;
  662: 	}
  663: 
  664: 	if (m->statusat == 0 && y > 0)
  665: 		y--;
  666: 	else if (m->statusat > 0 && y >= (u_int)m->statusat)
  667: 		y = m->statusat - 1;
  668: 
  669: 	if (x < wp->xoff || x >= wp->xoff + wp->sx)
  670: 		return (-1);
  671: 	if (y < wp->yoff || y >= wp->yoff + wp->sy)
  672: 		return (-1);
  673: 
  674: 	if (xp != NULL)
  675: 		*xp = x - wp->xoff;
  676: 	if (yp != NULL)
  677: 		*yp = y - wp->yoff;
  678: 	return (0);
  679: }
  680: 
  681: /* Get current mouse window if any. */
  682: struct winlink *
  683: cmd_mouse_window(struct mouse_event *m, struct session **sp)
  684: {
  685: 	struct session	*s;
  686: 	struct window	*w;
  687: 
  688: 	if (!m->valid || m->s == -1 || m->w == -1)
  689: 		return (NULL);
  690: 	if ((s = session_find_by_id(m->s)) == NULL)
  691: 		return (NULL);
  692: 	if ((w = window_find_by_id(m->w)) == NULL)
  693: 		return (NULL);
  694: 
  695: 	if (sp != NULL)
  696: 		*sp = s;
  697: 	return (winlink_find_by_window(&s->windows, w));
  698: }
  699: 
  700: /* Get current mouse pane if any. */
  701: struct window_pane *
  702: cmd_mouse_pane(struct mouse_event *m, struct session **sp,
  703:     struct winlink **wlp)
  704: {
  705: 	struct winlink		*wl;
  706: 	struct window_pane     	*wp;
  707: 
  708: 	if ((wl = cmd_mouse_window(m, sp)) == NULL)
  709: 		return (NULL);
  710: 	if ((wp = window_pane_find_by_id(m->wp)) == NULL)
  711: 		return (NULL);
  712: 	if (!window_has_pane(wl->window, wp))
  713: 		return (NULL);
  714: 
  715: 	if (wlp != NULL)
  716: 		*wlp = wl;
  717: 	return (wp);
  718: }
  719: 
  720: /* Replace the first %% or %idx in template by s. */
  721: char *
  722: cmd_template_replace(const char *template, const char *s, int idx)
  723: {
  724: 	char		 ch, *buf;
  725: 	const char	*ptr, *cp, quote[] = "\"\\$";
  726: 	int		 replaced, quoted;
  727: 	size_t		 len;
  728: 
  729: 	if (strchr(template, '%') == NULL)
  730: 		return (xstrdup(template));
  731: 
  732: 	buf = xmalloc(1);
  733: 	*buf = '\0';
  734: 	len = 0;
  735: 	replaced = 0;
  736: 
  737: 	ptr = template;
  738: 	while (*ptr != '\0') {
  739: 		switch (ch = *ptr++) {
  740: 		case '%':
  741: 			if (*ptr < '1' || *ptr > '9' || *ptr - '0' != idx) {
  742: 				if (*ptr != '%' || replaced)
  743: 					break;
  744: 				replaced = 1;
  745: 			}
  746: 			ptr++;
  747: 
  748: 			quoted = (*ptr == '%');
  749: 			if (quoted)
  750: 				ptr++;
  751: 
  752: 			buf = xrealloc(buf, len + (strlen(s) * 3) + 1);
  753: 			for (cp = s; *cp != '\0'; cp++) {
  754: 				if (quoted && strchr(quote, *cp) != NULL)
  755: 					buf[len++] = '\\';
  756: 				if (quoted && *cp == ';') {
  757: 					buf[len++] = '\\';
  758: 					buf[len++] = '\\';
  759: 				}
  760: 				buf[len++] = *cp;
  761: 			}
  762: 			buf[len] = '\0';
  763: 			continue;
  764: 		}
  765: 		buf = xrealloc(buf, len + 2);
  766: 		buf[len++] = ch;
  767: 		buf[len] = '\0';
  768: 	}
  769: 
  770: 	return (buf);
  771: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>