Annotation of src/usr.bin/tmux/cmd-queue.c, Revision 1.18
1.18 ! nicm 1: /* $OpenBSD: cmd-queue.c,v 1.17 2014/09/01 21:50:18 nicm Exp $ */
1.1 nicm 2:
3: /*
4: * Copyright (c) 2013 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 <ctype.h>
22: #include <stdlib.h>
1.7 nicm 23: #include <time.h>
1.1 nicm 24:
25: #include "tmux.h"
26:
27: /* Create new command queue. */
28: struct cmd_q *
29: cmdq_new(struct client *c)
30: {
31: struct cmd_q *cmdq;
32:
33: cmdq = xcalloc(1, sizeof *cmdq);
34: cmdq->references = 1;
35: cmdq->dead = 0;
36:
37: cmdq->client = c;
1.11 nicm 38: cmdq->client_exit = -1;
1.1 nicm 39:
40: TAILQ_INIT(&cmdq->queue);
41: cmdq->item = NULL;
42: cmdq->cmd = NULL;
43:
44: return (cmdq);
45: }
46:
47: /* Free command queue */
48: int
49: cmdq_free(struct cmd_q *cmdq)
50: {
51: if (--cmdq->references != 0)
52: return (cmdq->dead);
53:
54: cmdq_flush(cmdq);
55: free(cmdq);
56: return (1);
57: }
58:
59: /* Show message from command. */
1.18 ! nicm 60: void
1.1 nicm 61: cmdq_print(struct cmd_q *cmdq, const char *fmt, ...)
62: {
63: struct client *c = cmdq->client;
64: struct window *w;
65: va_list ap;
66:
67: va_start(ap, fmt);
68:
69: if (c == NULL)
70: /* nothing */;
71: else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
72: evbuffer_add_vprintf(c->stdout_data, fmt, ap);
73:
74: evbuffer_add(c->stdout_data, "\n", 1);
75: server_push_stdout(c);
76: } else {
77: w = c->session->curw->window;
78: if (w->active->mode != &window_copy_mode) {
79: window_pane_reset_mode(w->active);
80: window_pane_set_mode(w->active, &window_copy_mode);
81: window_copy_init_for_output(w->active);
82: }
83: window_copy_vadd(w->active, fmt, ap);
84: }
85:
86: va_end(ap);
87: }
88:
89: /* Show error from command. */
1.18 ! nicm 90: void
1.1 nicm 91: cmdq_error(struct cmd_q *cmdq, const char *fmt, ...)
92: {
93: struct client *c = cmdq->client;
94: struct cmd *cmd = cmdq->cmd;
95: va_list ap;
96: char *msg, *cause;
97: size_t msglen;
98:
99: va_start(ap, fmt);
100: msglen = xvasprintf(&msg, fmt, ap);
101: va_end(ap);
102:
103: if (c == NULL) {
104: xasprintf(&cause, "%s:%u: %s", cmd->file, cmd->line, msg);
105: ARRAY_ADD(&cfg_causes, cause);
106: } else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
107: evbuffer_add(c->stderr_data, msg, msglen);
108: evbuffer_add(c->stderr_data, "\n", 1);
109:
110: server_push_stderr(c);
1.13 nicm 111: c->retval = 1;
1.1 nicm 112: } else {
113: *msg = toupper((u_char) *msg);
114: status_message_set(c, "%s", msg);
115: }
116:
117: free(msg);
118: }
119:
1.4 nicm 120: /* Print a guard line. */
1.6 nicm 121: int
1.10 nicm 122: cmdq_guard(struct cmd_q *cmdq, const char *guard, int flags)
1.4 nicm 123: {
124: struct client *c = cmdq->client;
125:
1.8 nicm 126: if (c == NULL)
1.17 nicm 127: return (0);
1.4 nicm 128: if (!(c->flags & CLIENT_CONTROL))
1.17 nicm 129: return (0);
1.4 nicm 130:
1.9 nicm 131: evbuffer_add_printf(c->stdout_data, "%%%s %ld %u %d\n", guard,
132: (long) cmdq->time, cmdq->number, flags);
1.4 nicm 133: server_push_stdout(c);
1.17 nicm 134: return (1);
1.4 nicm 135: }
136:
1.1 nicm 137: /* Add command list to queue and begin processing if needed. */
138: void
139: cmdq_run(struct cmd_q *cmdq, struct cmd_list *cmdlist)
140: {
141: cmdq_append(cmdq, cmdlist);
142:
143: if (cmdq->item == NULL) {
144: cmdq->cmd = NULL;
145: cmdq_continue(cmdq);
146: }
147: }
148:
149: /* Add command list to queue. */
150: void
151: cmdq_append(struct cmd_q *cmdq, struct cmd_list *cmdlist)
152: {
153: struct cmd_q_item *item;
154:
155: item = xcalloc(1, sizeof *item);
156: item->cmdlist = cmdlist;
157: TAILQ_INSERT_TAIL(&cmdq->queue, item, qentry);
158: cmdlist->references++;
159: }
160:
161: /* Continue processing command queue. Returns 1 if finishes empty. */
162: int
163: cmdq_continue(struct cmd_q *cmdq)
164: {
165: struct cmd_q_item *next;
166: enum cmd_retval retval;
1.10 nicm 167: int empty, guard, flags;
1.3 nicm 168: char s[1024];
1.1 nicm 169:
170: notify_disable();
171:
172: empty = TAILQ_EMPTY(&cmdq->queue);
173: if (empty)
174: goto empty;
175:
176: if (cmdq->item == NULL) {
177: cmdq->item = TAILQ_FIRST(&cmdq->queue);
178: cmdq->cmd = TAILQ_FIRST(&cmdq->item->cmdlist->list);
179: } else
180: cmdq->cmd = TAILQ_NEXT(cmdq->cmd, qentry);
181:
182: do {
183: next = TAILQ_NEXT(cmdq->item, qentry);
184:
185: while (cmdq->cmd != NULL) {
1.3 nicm 186: cmd_print(cmdq->cmd, s, sizeof s);
187: log_debug("cmdq %p: %s (client %d)", cmdq, s,
188: cmdq->client != NULL ? cmdq->client->ibuf.fd : -1);
189:
1.4 nicm 190: cmdq->time = time(NULL);
191: cmdq->number++;
192:
1.10 nicm 193: flags = !!(cmdq->cmd->flags & CMD_CONTROL);
194: guard = cmdq_guard(cmdq, "begin", flags);
195:
1.1 nicm 196: retval = cmdq->cmd->entry->exec(cmdq->cmd, cmdq);
1.10 nicm 197:
1.6 nicm 198: if (guard) {
199: if (retval == CMD_RETURN_ERROR)
1.10 nicm 200: cmdq_guard(cmdq, "error", flags);
1.6 nicm 201: else
1.10 nicm 202: cmdq_guard(cmdq, "end", flags);
1.6 nicm 203: }
1.1 nicm 204:
205: if (retval == CMD_RETURN_ERROR)
206: break;
207: if (retval == CMD_RETURN_WAIT)
208: goto out;
209: if (retval == CMD_RETURN_STOP) {
210: cmdq_flush(cmdq);
211: goto empty;
212: }
213:
214: cmdq->cmd = TAILQ_NEXT(cmdq->cmd, qentry);
215: }
216:
217: TAILQ_REMOVE(&cmdq->queue, cmdq->item, qentry);
218: cmd_list_free(cmdq->item->cmdlist);
219: free(cmdq->item);
220:
221: cmdq->item = next;
222: if (cmdq->item != NULL)
223: cmdq->cmd = TAILQ_FIRST(&cmdq->item->cmdlist->list);
224: } while (cmdq->item != NULL);
225:
226: empty:
1.11 nicm 227: if (cmdq->client_exit > 0)
1.1 nicm 228: cmdq->client->flags |= CLIENT_EXIT;
229: if (cmdq->emptyfn != NULL)
230: cmdq->emptyfn(cmdq); /* may free cmdq */
231: empty = 1;
232:
233: out:
234: notify_enable();
235: return (empty);
236: }
237:
238: /* Flush command queue. */
239: void
240: cmdq_flush(struct cmd_q *cmdq)
241: {
242: struct cmd_q_item *item, *item1;
243:
244: TAILQ_FOREACH_SAFE(item, &cmdq->queue, qentry, item1) {
245: TAILQ_REMOVE(&cmdq->queue, item, qentry);
246: cmd_list_free(item->cmdlist);
247: free(item);
248: }
249: cmdq->item = NULL;
250: }