xref: /minix3/external/bsd/tmux/dist/cmd-queue.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /* Id */
2*0a6a1f1dSLionel Sambuc 
3*0a6a1f1dSLionel Sambuc /*
4*0a6a1f1dSLionel Sambuc  * Copyright (c) 2013 Nicholas Marriott <nicm@users.sourceforge.net>
5*0a6a1f1dSLionel Sambuc  *
6*0a6a1f1dSLionel Sambuc  * Permission to use, copy, modify, and distribute this software for any
7*0a6a1f1dSLionel Sambuc  * purpose with or without fee is hereby granted, provided that the above
8*0a6a1f1dSLionel Sambuc  * copyright notice and this permission notice appear in all copies.
9*0a6a1f1dSLionel Sambuc  *
10*0a6a1f1dSLionel Sambuc  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11*0a6a1f1dSLionel Sambuc  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12*0a6a1f1dSLionel Sambuc  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13*0a6a1f1dSLionel Sambuc  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14*0a6a1f1dSLionel Sambuc  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15*0a6a1f1dSLionel Sambuc  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16*0a6a1f1dSLionel Sambuc  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*0a6a1f1dSLionel Sambuc  */
18*0a6a1f1dSLionel Sambuc 
19*0a6a1f1dSLionel Sambuc #include <sys/types.h>
20*0a6a1f1dSLionel Sambuc 
21*0a6a1f1dSLionel Sambuc #include <ctype.h>
22*0a6a1f1dSLionel Sambuc #include <stdlib.h>
23*0a6a1f1dSLionel Sambuc #include <time.h>
24*0a6a1f1dSLionel Sambuc 
25*0a6a1f1dSLionel Sambuc #include "tmux.h"
26*0a6a1f1dSLionel Sambuc 
27*0a6a1f1dSLionel Sambuc /* Create new command queue. */
28*0a6a1f1dSLionel Sambuc struct cmd_q *
cmdq_new(struct client * c)29*0a6a1f1dSLionel Sambuc cmdq_new(struct client *c)
30*0a6a1f1dSLionel Sambuc {
31*0a6a1f1dSLionel Sambuc 	struct cmd_q	*cmdq;
32*0a6a1f1dSLionel Sambuc 
33*0a6a1f1dSLionel Sambuc 	cmdq = xcalloc(1, sizeof *cmdq);
34*0a6a1f1dSLionel Sambuc 	cmdq->references = 1;
35*0a6a1f1dSLionel Sambuc 	cmdq->dead = 0;
36*0a6a1f1dSLionel Sambuc 
37*0a6a1f1dSLionel Sambuc 	cmdq->client = c;
38*0a6a1f1dSLionel Sambuc 	cmdq->client_exit = -1;
39*0a6a1f1dSLionel Sambuc 
40*0a6a1f1dSLionel Sambuc 	TAILQ_INIT(&cmdq->queue);
41*0a6a1f1dSLionel Sambuc 	cmdq->item = NULL;
42*0a6a1f1dSLionel Sambuc 	cmdq->cmd = NULL;
43*0a6a1f1dSLionel Sambuc 
44*0a6a1f1dSLionel Sambuc 	return (cmdq);
45*0a6a1f1dSLionel Sambuc }
46*0a6a1f1dSLionel Sambuc 
47*0a6a1f1dSLionel Sambuc /* Free command queue */
48*0a6a1f1dSLionel Sambuc int
cmdq_free(struct cmd_q * cmdq)49*0a6a1f1dSLionel Sambuc cmdq_free(struct cmd_q *cmdq)
50*0a6a1f1dSLionel Sambuc {
51*0a6a1f1dSLionel Sambuc 	if (--cmdq->references != 0)
52*0a6a1f1dSLionel Sambuc 		return (cmdq->dead);
53*0a6a1f1dSLionel Sambuc 
54*0a6a1f1dSLionel Sambuc 	cmdq_flush(cmdq);
55*0a6a1f1dSLionel Sambuc 	free(cmdq);
56*0a6a1f1dSLionel Sambuc 	return (1);
57*0a6a1f1dSLionel Sambuc }
58*0a6a1f1dSLionel Sambuc 
59*0a6a1f1dSLionel Sambuc /* Show message from command. */
60*0a6a1f1dSLionel Sambuc void printflike2
cmdq_print(struct cmd_q * cmdq,const char * fmt,...)61*0a6a1f1dSLionel Sambuc cmdq_print(struct cmd_q *cmdq, const char *fmt, ...)
62*0a6a1f1dSLionel Sambuc {
63*0a6a1f1dSLionel Sambuc 	struct client	*c = cmdq->client;
64*0a6a1f1dSLionel Sambuc 	struct window	*w;
65*0a6a1f1dSLionel Sambuc 	va_list		 ap;
66*0a6a1f1dSLionel Sambuc 
67*0a6a1f1dSLionel Sambuc 	va_start(ap, fmt);
68*0a6a1f1dSLionel Sambuc 
69*0a6a1f1dSLionel Sambuc 	if (c == NULL)
70*0a6a1f1dSLionel Sambuc 		/* nothing */;
71*0a6a1f1dSLionel Sambuc 	else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
72*0a6a1f1dSLionel Sambuc 		evbuffer_add_vprintf(c->stdout_data, fmt, ap);
73*0a6a1f1dSLionel Sambuc 
74*0a6a1f1dSLionel Sambuc 		evbuffer_add(c->stdout_data, "\n", 1);
75*0a6a1f1dSLionel Sambuc 		server_push_stdout(c);
76*0a6a1f1dSLionel Sambuc 	} else {
77*0a6a1f1dSLionel Sambuc 		w = c->session->curw->window;
78*0a6a1f1dSLionel Sambuc 		if (w->active->mode != &window_copy_mode) {
79*0a6a1f1dSLionel Sambuc 			window_pane_reset_mode(w->active);
80*0a6a1f1dSLionel Sambuc 			window_pane_set_mode(w->active, &window_copy_mode);
81*0a6a1f1dSLionel Sambuc 			window_copy_init_for_output(w->active);
82*0a6a1f1dSLionel Sambuc 		}
83*0a6a1f1dSLionel Sambuc 		window_copy_vadd(w->active, fmt, ap);
84*0a6a1f1dSLionel Sambuc 	}
85*0a6a1f1dSLionel Sambuc 
86*0a6a1f1dSLionel Sambuc 	va_end(ap);
87*0a6a1f1dSLionel Sambuc }
88*0a6a1f1dSLionel Sambuc 
89*0a6a1f1dSLionel Sambuc /* Show info from command. */
90*0a6a1f1dSLionel Sambuc void printflike2
cmdq_info(struct cmd_q * cmdq,const char * fmt,...)91*0a6a1f1dSLionel Sambuc cmdq_info(struct cmd_q *cmdq, const char *fmt, ...)
92*0a6a1f1dSLionel Sambuc {
93*0a6a1f1dSLionel Sambuc 	struct client	*c = cmdq->client;
94*0a6a1f1dSLionel Sambuc 	va_list		 ap;
95*0a6a1f1dSLionel Sambuc 	char		*msg;
96*0a6a1f1dSLionel Sambuc 
97*0a6a1f1dSLionel Sambuc 	if (options_get_number(&global_options, "quiet"))
98*0a6a1f1dSLionel Sambuc 		return;
99*0a6a1f1dSLionel Sambuc 
100*0a6a1f1dSLionel Sambuc 	va_start(ap, fmt);
101*0a6a1f1dSLionel Sambuc 
102*0a6a1f1dSLionel Sambuc 	if (c == NULL)
103*0a6a1f1dSLionel Sambuc 		/* nothing */;
104*0a6a1f1dSLionel Sambuc 	else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
105*0a6a1f1dSLionel Sambuc 		evbuffer_add_vprintf(c->stdout_data, fmt, ap);
106*0a6a1f1dSLionel Sambuc 
107*0a6a1f1dSLionel Sambuc 		evbuffer_add(c->stdout_data, "\n", 1);
108*0a6a1f1dSLionel Sambuc 		server_push_stdout(c);
109*0a6a1f1dSLionel Sambuc 	} else {
110*0a6a1f1dSLionel Sambuc 		xvasprintf(&msg, fmt, ap);
111*0a6a1f1dSLionel Sambuc 		*msg = toupper((u_char) *msg);
112*0a6a1f1dSLionel Sambuc 		status_message_set(c, "%s", msg);
113*0a6a1f1dSLionel Sambuc 		free(msg);
114*0a6a1f1dSLionel Sambuc 	}
115*0a6a1f1dSLionel Sambuc 
116*0a6a1f1dSLionel Sambuc 	va_end(ap);
117*0a6a1f1dSLionel Sambuc 
118*0a6a1f1dSLionel Sambuc }
119*0a6a1f1dSLionel Sambuc 
120*0a6a1f1dSLionel Sambuc /* Show error from command. */
121*0a6a1f1dSLionel Sambuc void printflike2
cmdq_error(struct cmd_q * cmdq,const char * fmt,...)122*0a6a1f1dSLionel Sambuc cmdq_error(struct cmd_q *cmdq, const char *fmt, ...)
123*0a6a1f1dSLionel Sambuc {
124*0a6a1f1dSLionel Sambuc 	struct client	*c = cmdq->client;
125*0a6a1f1dSLionel Sambuc 	struct cmd	*cmd = cmdq->cmd;
126*0a6a1f1dSLionel Sambuc 	va_list		 ap;
127*0a6a1f1dSLionel Sambuc 	char		*msg, *cause;
128*0a6a1f1dSLionel Sambuc 	size_t		 msglen;
129*0a6a1f1dSLionel Sambuc 
130*0a6a1f1dSLionel Sambuc 	va_start(ap, fmt);
131*0a6a1f1dSLionel Sambuc 	msglen = xvasprintf(&msg, fmt, ap);
132*0a6a1f1dSLionel Sambuc 	va_end(ap);
133*0a6a1f1dSLionel Sambuc 
134*0a6a1f1dSLionel Sambuc 	if (c == NULL) {
135*0a6a1f1dSLionel Sambuc 		xasprintf(&cause, "%s:%u: %s", cmd->file, cmd->line, msg);
136*0a6a1f1dSLionel Sambuc 		ARRAY_ADD(&cfg_causes, cause);
137*0a6a1f1dSLionel Sambuc 	} else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
138*0a6a1f1dSLionel Sambuc 		evbuffer_add(c->stderr_data, msg, msglen);
139*0a6a1f1dSLionel Sambuc 		evbuffer_add(c->stderr_data, "\n", 1);
140*0a6a1f1dSLionel Sambuc 
141*0a6a1f1dSLionel Sambuc 		server_push_stderr(c);
142*0a6a1f1dSLionel Sambuc 		c->retval = 1;
143*0a6a1f1dSLionel Sambuc 	} else {
144*0a6a1f1dSLionel Sambuc 		*msg = toupper((u_char) *msg);
145*0a6a1f1dSLionel Sambuc 		status_message_set(c, "%s", msg);
146*0a6a1f1dSLionel Sambuc 	}
147*0a6a1f1dSLionel Sambuc 
148*0a6a1f1dSLionel Sambuc 	free(msg);
149*0a6a1f1dSLionel Sambuc }
150*0a6a1f1dSLionel Sambuc 
151*0a6a1f1dSLionel Sambuc /* Print a guard line. */
152*0a6a1f1dSLionel Sambuc int
cmdq_guard(struct cmd_q * cmdq,const char * guard,int flags)153*0a6a1f1dSLionel Sambuc cmdq_guard(struct cmd_q *cmdq, const char *guard, int flags)
154*0a6a1f1dSLionel Sambuc {
155*0a6a1f1dSLionel Sambuc 	struct client	*c = cmdq->client;
156*0a6a1f1dSLionel Sambuc 
157*0a6a1f1dSLionel Sambuc 	if (c == NULL)
158*0a6a1f1dSLionel Sambuc 		return 0;
159*0a6a1f1dSLionel Sambuc 	if (!(c->flags & CLIENT_CONTROL))
160*0a6a1f1dSLionel Sambuc 		return 0;
161*0a6a1f1dSLionel Sambuc 
162*0a6a1f1dSLionel Sambuc 	evbuffer_add_printf(c->stdout_data, "%%%s %ld %u %d\n", guard,
163*0a6a1f1dSLionel Sambuc 	    (long) cmdq->time, cmdq->number, flags);
164*0a6a1f1dSLionel Sambuc 	server_push_stdout(c);
165*0a6a1f1dSLionel Sambuc 	return 1;
166*0a6a1f1dSLionel Sambuc }
167*0a6a1f1dSLionel Sambuc 
168*0a6a1f1dSLionel Sambuc /* Add command list to queue and begin processing if needed. */
169*0a6a1f1dSLionel Sambuc void
cmdq_run(struct cmd_q * cmdq,struct cmd_list * cmdlist)170*0a6a1f1dSLionel Sambuc cmdq_run(struct cmd_q *cmdq, struct cmd_list *cmdlist)
171*0a6a1f1dSLionel Sambuc {
172*0a6a1f1dSLionel Sambuc 	cmdq_append(cmdq, cmdlist);
173*0a6a1f1dSLionel Sambuc 
174*0a6a1f1dSLionel Sambuc 	if (cmdq->item == NULL) {
175*0a6a1f1dSLionel Sambuc 		cmdq->cmd = NULL;
176*0a6a1f1dSLionel Sambuc 		cmdq_continue(cmdq);
177*0a6a1f1dSLionel Sambuc 	}
178*0a6a1f1dSLionel Sambuc }
179*0a6a1f1dSLionel Sambuc 
180*0a6a1f1dSLionel Sambuc /* Add command list to queue. */
181*0a6a1f1dSLionel Sambuc void
cmdq_append(struct cmd_q * cmdq,struct cmd_list * cmdlist)182*0a6a1f1dSLionel Sambuc cmdq_append(struct cmd_q *cmdq, struct cmd_list *cmdlist)
183*0a6a1f1dSLionel Sambuc {
184*0a6a1f1dSLionel Sambuc 	struct cmd_q_item	*item;
185*0a6a1f1dSLionel Sambuc 
186*0a6a1f1dSLionel Sambuc 	item = xcalloc(1, sizeof *item);
187*0a6a1f1dSLionel Sambuc 	item->cmdlist = cmdlist;
188*0a6a1f1dSLionel Sambuc 	TAILQ_INSERT_TAIL(&cmdq->queue, item, qentry);
189*0a6a1f1dSLionel Sambuc 	cmdlist->references++;
190*0a6a1f1dSLionel Sambuc }
191*0a6a1f1dSLionel Sambuc 
192*0a6a1f1dSLionel Sambuc /* Continue processing command queue. Returns 1 if finishes empty. */
193*0a6a1f1dSLionel Sambuc int
cmdq_continue(struct cmd_q * cmdq)194*0a6a1f1dSLionel Sambuc cmdq_continue(struct cmd_q *cmdq)
195*0a6a1f1dSLionel Sambuc {
196*0a6a1f1dSLionel Sambuc 	struct cmd_q_item	*next;
197*0a6a1f1dSLionel Sambuc 	enum cmd_retval		 retval;
198*0a6a1f1dSLionel Sambuc 	int			 empty, guard, flags;
199*0a6a1f1dSLionel Sambuc 	char			 s[1024];
200*0a6a1f1dSLionel Sambuc 
201*0a6a1f1dSLionel Sambuc 	notify_disable();
202*0a6a1f1dSLionel Sambuc 
203*0a6a1f1dSLionel Sambuc 	empty = TAILQ_EMPTY(&cmdq->queue);
204*0a6a1f1dSLionel Sambuc 	if (empty)
205*0a6a1f1dSLionel Sambuc 		goto empty;
206*0a6a1f1dSLionel Sambuc 
207*0a6a1f1dSLionel Sambuc 	if (cmdq->item == NULL) {
208*0a6a1f1dSLionel Sambuc 		cmdq->item = TAILQ_FIRST(&cmdq->queue);
209*0a6a1f1dSLionel Sambuc 		cmdq->cmd = TAILQ_FIRST(&cmdq->item->cmdlist->list);
210*0a6a1f1dSLionel Sambuc 	} else
211*0a6a1f1dSLionel Sambuc 		cmdq->cmd = TAILQ_NEXT(cmdq->cmd, qentry);
212*0a6a1f1dSLionel Sambuc 
213*0a6a1f1dSLionel Sambuc 	do {
214*0a6a1f1dSLionel Sambuc 		next = TAILQ_NEXT(cmdq->item, qentry);
215*0a6a1f1dSLionel Sambuc 
216*0a6a1f1dSLionel Sambuc 		while (cmdq->cmd != NULL) {
217*0a6a1f1dSLionel Sambuc 			cmd_print(cmdq->cmd, s, sizeof s);
218*0a6a1f1dSLionel Sambuc 			log_debug("cmdq %p: %s (client %d)", cmdq, s,
219*0a6a1f1dSLionel Sambuc 			    cmdq->client != NULL ? cmdq->client->ibuf.fd : -1);
220*0a6a1f1dSLionel Sambuc 
221*0a6a1f1dSLionel Sambuc 			cmdq->time = time(NULL);
222*0a6a1f1dSLionel Sambuc 			cmdq->number++;
223*0a6a1f1dSLionel Sambuc 
224*0a6a1f1dSLionel Sambuc 			flags = !!(cmdq->cmd->flags & CMD_CONTROL);
225*0a6a1f1dSLionel Sambuc 			guard = cmdq_guard(cmdq, "begin", flags);
226*0a6a1f1dSLionel Sambuc 
227*0a6a1f1dSLionel Sambuc 			retval = cmdq->cmd->entry->exec(cmdq->cmd, cmdq);
228*0a6a1f1dSLionel Sambuc 
229*0a6a1f1dSLionel Sambuc 			if (guard) {
230*0a6a1f1dSLionel Sambuc 				if (retval == CMD_RETURN_ERROR)
231*0a6a1f1dSLionel Sambuc 					cmdq_guard(cmdq, "error", flags);
232*0a6a1f1dSLionel Sambuc 				else
233*0a6a1f1dSLionel Sambuc 					cmdq_guard(cmdq, "end", flags);
234*0a6a1f1dSLionel Sambuc 			}
235*0a6a1f1dSLionel Sambuc 
236*0a6a1f1dSLionel Sambuc 			if (retval == CMD_RETURN_ERROR)
237*0a6a1f1dSLionel Sambuc 				break;
238*0a6a1f1dSLionel Sambuc 			if (retval == CMD_RETURN_WAIT)
239*0a6a1f1dSLionel Sambuc 				goto out;
240*0a6a1f1dSLionel Sambuc 			if (retval == CMD_RETURN_STOP) {
241*0a6a1f1dSLionel Sambuc 				cmdq_flush(cmdq);
242*0a6a1f1dSLionel Sambuc 				goto empty;
243*0a6a1f1dSLionel Sambuc 			}
244*0a6a1f1dSLionel Sambuc 
245*0a6a1f1dSLionel Sambuc 			cmdq->cmd = TAILQ_NEXT(cmdq->cmd, qentry);
246*0a6a1f1dSLionel Sambuc 		}
247*0a6a1f1dSLionel Sambuc 
248*0a6a1f1dSLionel Sambuc 		TAILQ_REMOVE(&cmdq->queue, cmdq->item, qentry);
249*0a6a1f1dSLionel Sambuc 		cmd_list_free(cmdq->item->cmdlist);
250*0a6a1f1dSLionel Sambuc 		free(cmdq->item);
251*0a6a1f1dSLionel Sambuc 
252*0a6a1f1dSLionel Sambuc 		cmdq->item = next;
253*0a6a1f1dSLionel Sambuc 		if (cmdq->item != NULL)
254*0a6a1f1dSLionel Sambuc 			cmdq->cmd = TAILQ_FIRST(&cmdq->item->cmdlist->list);
255*0a6a1f1dSLionel Sambuc 	} while (cmdq->item != NULL);
256*0a6a1f1dSLionel Sambuc 
257*0a6a1f1dSLionel Sambuc empty:
258*0a6a1f1dSLionel Sambuc 	if (cmdq->client_exit > 0)
259*0a6a1f1dSLionel Sambuc 		cmdq->client->flags |= CLIENT_EXIT;
260*0a6a1f1dSLionel Sambuc 	if (cmdq->emptyfn != NULL)
261*0a6a1f1dSLionel Sambuc 		cmdq->emptyfn(cmdq); /* may free cmdq */
262*0a6a1f1dSLionel Sambuc 	empty = 1;
263*0a6a1f1dSLionel Sambuc 
264*0a6a1f1dSLionel Sambuc out:
265*0a6a1f1dSLionel Sambuc 	notify_enable();
266*0a6a1f1dSLionel Sambuc 	return (empty);
267*0a6a1f1dSLionel Sambuc }
268*0a6a1f1dSLionel Sambuc 
269*0a6a1f1dSLionel Sambuc /* Flush command queue. */
270*0a6a1f1dSLionel Sambuc void
cmdq_flush(struct cmd_q * cmdq)271*0a6a1f1dSLionel Sambuc cmdq_flush(struct cmd_q *cmdq)
272*0a6a1f1dSLionel Sambuc {
273*0a6a1f1dSLionel Sambuc 	struct cmd_q_item	*item, *item1;
274*0a6a1f1dSLionel Sambuc 
275*0a6a1f1dSLionel Sambuc 	TAILQ_FOREACH_SAFE(item, &cmdq->queue, qentry, item1) {
276*0a6a1f1dSLionel Sambuc 		TAILQ_REMOVE(&cmdq->queue, item, qentry);
277*0a6a1f1dSLionel Sambuc 		cmd_list_free(item->cmdlist);
278*0a6a1f1dSLionel Sambuc 		free(item);
279*0a6a1f1dSLionel Sambuc 	}
280*0a6a1f1dSLionel Sambuc 	cmdq->item = NULL;
281*0a6a1f1dSLionel Sambuc }
282