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