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