Annotation of src/usr.bin/tmux/cmd-queue.c, Revision 1.13
1.13 ! nicm 1: /* $OpenBSD: cmd-queue.c,v 1.12 2013/10/10 12:07:36 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. */
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);
1.13 ! nicm 146: c->retval = 1;
1.1 nicm 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.10 nicm 157: cmdq_guard(struct cmd_q *cmdq, const char *guard, int flags)
1.4 nicm 158: {
159: struct client *c = cmdq->client;
160:
1.8 nicm 161: if (c == 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:
1.9 nicm 166: evbuffer_add_printf(c->stdout_data, "%%%s %ld %u %d\n", guard,
167: (long) cmdq->time, cmdq->number, flags);
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.10 nicm 202: int empty, guard, flags;
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.10 nicm 228: flags = !!(cmdq->cmd->flags & CMD_CONTROL);
229: guard = cmdq_guard(cmdq, "begin", flags);
230:
1.1 nicm 231: retval = cmdq->cmd->entry->exec(cmdq->cmd, cmdq);
1.10 nicm 232:
1.6 nicm 233: if (guard) {
234: if (retval == CMD_RETURN_ERROR)
1.10 nicm 235: cmdq_guard(cmdq, "error", flags);
1.6 nicm 236: else
1.10 nicm 237: cmdq_guard(cmdq, "end", flags);
1.6 nicm 238: }
1.1 nicm 239:
240: if (retval == CMD_RETURN_ERROR)
241: break;
242: if (retval == CMD_RETURN_WAIT)
243: goto out;
244: if (retval == CMD_RETURN_STOP) {
245: cmdq_flush(cmdq);
246: goto empty;
247: }
248:
249: cmdq->cmd = TAILQ_NEXT(cmdq->cmd, qentry);
250: }
251:
252: TAILQ_REMOVE(&cmdq->queue, cmdq->item, qentry);
253: cmd_list_free(cmdq->item->cmdlist);
254: free(cmdq->item);
255:
256: cmdq->item = next;
257: if (cmdq->item != NULL)
258: cmdq->cmd = TAILQ_FIRST(&cmdq->item->cmdlist->list);
259: } while (cmdq->item != NULL);
260:
261: empty:
1.11 nicm 262: if (cmdq->client_exit > 0)
1.1 nicm 263: cmdq->client->flags |= CLIENT_EXIT;
264: if (cmdq->emptyfn != NULL)
265: cmdq->emptyfn(cmdq); /* may free cmdq */
266: empty = 1;
267:
268: out:
269: notify_enable();
270: return (empty);
271: }
272:
273: /* Flush command queue. */
274: void
275: cmdq_flush(struct cmd_q *cmdq)
276: {
277: struct cmd_q_item *item, *item1;
278:
279: TAILQ_FOREACH_SAFE(item, &cmdq->queue, qentry, item1) {
280: TAILQ_REMOVE(&cmdq->queue, item, qentry);
281: cmd_list_free(item->cmdlist);
282: free(item);
283: }
284: cmdq->item = NULL;
1.12 nicm 285: }
286:
287: /* Get default path using command queue. */
288: const char *
289: cmdq_default_path(struct cmd_q *cmdq, const char *cwd)
290: {
291: struct client *c = cmdq->client;
292: struct session *s;
293: const char *current;
294:
295: if ((s = cmd_current_session(cmdq, 0)) == NULL)
296: return (NULL);
297:
298: if (cwd == NULL)
299: cwd = options_get_string(&s->options, "default-path");
300:
301: if (c != NULL && c->session == NULL && c->cwd != NULL)
302: current = c->cwd;
303: else if (s->curw != NULL)
304: current = get_proc_cwd(s->curw->window->active->fd);
305: else
306: current = NULL;
307:
308: return (cmd_default_path(s->cwd, current, cwd));
1.1 nicm 309: }