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