Annotation of embedaddon/tmux/cmd.c, revision 1.1
1.1 ! misho 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(¤t, item, targetflags);
! 514: if (error != 0) {
! 515: if (~targetflags & CMD_FIND_QUIET)
! 516: return (-1);
! 517: cmd_find_clear_state(¤t, NULL, 0);
! 518: }
! 519: if (!cmd_find_empty_state(¤t) && !cmd_find_valid_state(¤t))
! 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, ¤t, 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, ¤t, 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, ¤t, 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, ¤t, 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>