Annotation of src/usr.bin/tmux/cmd-queue.c, Revision 1.7
1.7 ! nicm 1: /* $OpenBSD: cmd-queue.c,v 1.6 2013/03/25 11:41:16 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;
38: cmdq->client_exit = 0;
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. */
60: void printflike2
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: va_start(ap, fmt);
73: evbuffer_add_vprintf(c->stdout_data, fmt, ap);
74: va_end(ap);
75:
76: evbuffer_add(c->stdout_data, "\n", 1);
77: server_push_stdout(c);
78: } else {
79: w = c->session->curw->window;
80: if (w->active->mode != &window_copy_mode) {
81: window_pane_reset_mode(w->active);
82: window_pane_set_mode(w->active, &window_copy_mode);
83: window_copy_init_for_output(w->active);
84: }
85: window_copy_vadd(w->active, fmt, ap);
86: }
87:
88: va_end(ap);
89: }
90:
91: /* Show info from command. */
92: void printflike2
93: cmdq_info(struct cmd_q *cmdq, const char *fmt, ...)
94: {
95: struct client *c = cmdq->client;
96: va_list ap;
97: char *msg;
98:
99: if (options_get_number(&global_options, "quiet"))
100: return;
101:
102: va_start(ap, fmt);
103:
104: if (c == NULL)
105: /* nothing */;
106: else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
107: va_start(ap, fmt);
108: evbuffer_add_vprintf(c->stdout_data, fmt, ap);
109: va_end(ap);
110:
111: evbuffer_add(c->stdout_data, "\n", 1);
112: server_push_stdout(c);
113: } else {
114: xvasprintf(&msg, fmt, ap);
115: *msg = toupper((u_char) *msg);
116: status_message_set(c, "%s", msg);
117: free(msg);
118: }
119:
120: va_end(ap);
121:
122: }
123:
124: /* Show error from command. */
125: void printflike2
126: cmdq_error(struct cmd_q *cmdq, const char *fmt, ...)
127: {
128: struct client *c = cmdq->client;
129: struct cmd *cmd = cmdq->cmd;
130: va_list ap;
131: char *msg, *cause;
132: size_t msglen;
133:
134: va_start(ap, fmt);
135: msglen = xvasprintf(&msg, fmt, ap);
136: va_end(ap);
137:
138: if (c == NULL) {
139: xasprintf(&cause, "%s:%u: %s", cmd->file, cmd->line, msg);
140: ARRAY_ADD(&cfg_causes, cause);
141: } else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
142: evbuffer_add(c->stderr_data, msg, msglen);
143: evbuffer_add(c->stderr_data, "\n", 1);
144:
145: server_push_stderr(c);
146: c->retcode = 1;
147: } else {
148: *msg = toupper((u_char) *msg);
149: status_message_set(c, "%s", msg);
150: }
151:
152: free(msg);
153: }
154:
1.4 nicm 155: /* Print a guard line. */
1.6 nicm 156: int
1.4 nicm 157: cmdq_guard(struct cmd_q *cmdq, const char *guard)
158: {
159: struct client *c = cmdq->client;
160:
161: if (c == NULL || c->session == NULL)
1.6 nicm 162: return 0;
1.4 nicm 163: if (!(c->flags & CLIENT_CONTROL))
1.6 nicm 164: return 0;
1.4 nicm 165:
166: evbuffer_add_printf(c->stdout_data, "%%%s %ld %u\n", guard,
1.5 nicm 167: (long) cmdq->time, cmdq->number);
1.4 nicm 168: server_push_stdout(c);
1.6 nicm 169: return 1;
1.4 nicm 170: }
171:
1.1 nicm 172: /* Add command list to queue and begin processing if needed. */
173: void
174: cmdq_run(struct cmd_q *cmdq, struct cmd_list *cmdlist)
175: {
176: cmdq_append(cmdq, cmdlist);
177:
178: if (cmdq->item == NULL) {
179: cmdq->cmd = NULL;
180: cmdq_continue(cmdq);
181: }
182: }
183:
184: /* Add command list to queue. */
185: void
186: cmdq_append(struct cmd_q *cmdq, struct cmd_list *cmdlist)
187: {
188: struct cmd_q_item *item;
189:
190: item = xcalloc(1, sizeof *item);
191: item->cmdlist = cmdlist;
192: TAILQ_INSERT_TAIL(&cmdq->queue, item, qentry);
193: cmdlist->references++;
194: }
195:
196: /* Continue processing command queue. Returns 1 if finishes empty. */
197: int
198: cmdq_continue(struct cmd_q *cmdq)
199: {
200: struct cmd_q_item *next;
201: enum cmd_retval retval;
1.6 nicm 202: int empty, guard;
1.3 nicm 203: char s[1024];
1.1 nicm 204:
205: notify_disable();
206:
207: empty = TAILQ_EMPTY(&cmdq->queue);
208: if (empty)
209: goto empty;
210:
211: if (cmdq->item == NULL) {
212: cmdq->item = TAILQ_FIRST(&cmdq->queue);
213: cmdq->cmd = TAILQ_FIRST(&cmdq->item->cmdlist->list);
214: } else
215: cmdq->cmd = TAILQ_NEXT(cmdq->cmd, qentry);
216:
217: do {
218: next = TAILQ_NEXT(cmdq->item, qentry);
219:
220: while (cmdq->cmd != NULL) {
1.3 nicm 221: cmd_print(cmdq->cmd, s, sizeof s);
222: log_debug("cmdq %p: %s (client %d)", cmdq, s,
223: cmdq->client != NULL ? cmdq->client->ibuf.fd : -1);
224:
1.4 nicm 225: cmdq->time = time(NULL);
226: cmdq->number++;
227:
1.6 nicm 228: guard = cmdq_guard(cmdq, "begin");
1.1 nicm 229: retval = cmdq->cmd->entry->exec(cmdq->cmd, cmdq);
1.6 nicm 230: if (guard) {
231: if (retval == CMD_RETURN_ERROR)
232: cmdq_guard(cmdq, "error");
233: else
234: cmdq_guard(cmdq, "end");
235: }
1.1 nicm 236:
237: if (retval == CMD_RETURN_ERROR)
238: break;
239: if (retval == CMD_RETURN_WAIT)
240: goto out;
241: if (retval == CMD_RETURN_STOP) {
242: cmdq_flush(cmdq);
243: goto empty;
244: }
245:
246: cmdq->cmd = TAILQ_NEXT(cmdq->cmd, qentry);
247: }
248:
249: TAILQ_REMOVE(&cmdq->queue, cmdq->item, qentry);
250: cmd_list_free(cmdq->item->cmdlist);
251: free(cmdq->item);
252:
253: cmdq->item = next;
254: if (cmdq->item != NULL)
255: cmdq->cmd = TAILQ_FIRST(&cmdq->item->cmdlist->list);
256: } while (cmdq->item != NULL);
257:
258: empty:
259: if (cmdq->client_exit)
260: cmdq->client->flags |= CLIENT_EXIT;
261: if (cmdq->emptyfn != NULL)
262: cmdq->emptyfn(cmdq); /* may free cmdq */
263: empty = 1;
264:
265: out:
266: notify_enable();
267: return (empty);
268: }
269:
270: /* Flush command queue. */
271: void
272: cmdq_flush(struct cmd_q *cmdq)
273: {
274: struct cmd_q_item *item, *item1;
275:
276: TAILQ_FOREACH_SAFE(item, &cmdq->queue, qentry, item1) {
277: TAILQ_REMOVE(&cmdq->queue, item, qentry);
278: cmd_list_free(item->cmdlist);
279: free(item);
280: }
281: cmdq->item = NULL;
282: }