1/* $Id: cmd-list.c,v 1.1.1.2 2011/08/17 18:40:04 jmmv Exp $ */ 2 3/* 4 * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> 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 21#include <string.h> 22 23#include "tmux.h" 24 25struct cmd_list * 26cmd_list_parse(int argc, char **argv, char **cause) 27{ 28 struct cmd_list *cmdlist; 29 struct cmd *cmd; 30 int i, lastsplit; 31 size_t arglen, new_argc; 32 char **copy_argv, **new_argv; 33 34 copy_argv = cmd_copy_argv(argc, argv); 35 36 cmdlist = xmalloc(sizeof *cmdlist); 37 cmdlist->references = 1; 38 TAILQ_INIT(&cmdlist->list); 39 40 lastsplit = 0; 41 for (i = 0; i < argc; i++) { 42 arglen = strlen(copy_argv[i]); 43 if (arglen == 0 || copy_argv[i][arglen - 1] != ';') 44 continue; 45 copy_argv[i][arglen - 1] = '\0'; 46 47 if (arglen > 1 && copy_argv[i][arglen - 2] == '\\') { 48 copy_argv[i][arglen - 2] = ';'; 49 continue; 50 } 51 52 new_argc = i - lastsplit; 53 new_argv = copy_argv + lastsplit; 54 if (arglen != 1) 55 new_argc++; 56 57 cmd = cmd_parse(new_argc, new_argv, cause); 58 if (cmd == NULL) 59 goto bad; 60 TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry); 61 62 lastsplit = i + 1; 63 } 64 65 if (lastsplit != argc) { 66 cmd = cmd_parse(argc - lastsplit, copy_argv + lastsplit, cause); 67 if (cmd == NULL) 68 goto bad; 69 TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry); 70 } 71 72 cmd_free_argv(argc, copy_argv); 73 return (cmdlist); 74 75bad: 76 cmd_list_free(cmdlist); 77 cmd_free_argv(argc, copy_argv); 78 return (NULL); 79} 80 81int 82cmd_list_exec(struct cmd_list *cmdlist, struct cmd_ctx *ctx) 83{ 84 struct cmd *cmd; 85 int n, retval; 86 87 retval = 0; 88 TAILQ_FOREACH(cmd, &cmdlist->list, qentry) { 89 if ((n = cmd_exec(cmd, ctx)) == -1) 90 return (-1); 91 92 /* 93 * A 1 return value means the command client is being attached 94 * (sent MSG_READY). 95 */ 96 if (n == 1) { 97 retval = 1; 98 99 /* 100 * The command client has been attached, so mangle the 101 * context to treat any following commands as if they 102 * were called from inside. 103 */ 104 if (ctx->curclient == NULL) { 105 ctx->curclient = ctx->cmdclient; 106 ctx->cmdclient = NULL; 107 108 ctx->error = key_bindings_error; 109 ctx->print = key_bindings_print; 110 ctx->info = key_bindings_info; 111 } 112 } 113 } 114 return (retval); 115} 116 117void 118cmd_list_free(struct cmd_list *cmdlist) 119{ 120 struct cmd *cmd; 121 122 if (--cmdlist->references != 0) 123 return; 124 125 while (!TAILQ_EMPTY(&cmdlist->list)) { 126 cmd = TAILQ_FIRST(&cmdlist->list); 127 TAILQ_REMOVE(&cmdlist->list, cmd, qentry); 128 cmd_free(cmd); 129 } 130 xfree(cmdlist); 131} 132 133size_t 134cmd_list_print(struct cmd_list *cmdlist, char *buf, size_t len) 135{ 136 struct cmd *cmd; 137 size_t off; 138 139 off = 0; 140 TAILQ_FOREACH(cmd, &cmdlist->list, qentry) { 141 if (off >= len) 142 break; 143 off += cmd_print(cmd, buf + off, len - off); 144 if (off >= len) 145 break; 146 if (TAILQ_NEXT(cmd, qentry) != NULL) 147 off += xsnprintf(buf + off, len - off, " ; "); 148 } 149 return (off); 150} 151