4 * Copyright (c) 2013 Nicholas Marriott <nicm@users.sourceforge.net>
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.
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.
19 #include <sys/types.h>
27 /* Create new command queue. */
29 cmdq_new(struct client
*c
)
33 cmdq
= xcalloc(1, sizeof *cmdq
);
38 cmdq
->client_exit
= 0;
40 TAILQ_INIT(&cmdq
->queue
);
47 /* Free command queue */
49 cmdq_free(struct cmd_q
*cmdq
)
51 if (--cmdq
->references
!= 0)
59 /* Show message from command. */
61 cmdq_print(struct cmd_q
*cmdq
, const char *fmt
, ...)
63 struct client
*c
= cmdq
->client
;
71 else if (c
->session
== NULL
|| (c
->flags
& CLIENT_CONTROL
)) {
73 evbuffer_add_vprintf(c
->stdout_data
, fmt
, ap
);
76 evbuffer_add(c
->stdout_data
, "\n", 1);
77 server_push_stdout(c
);
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
);
85 window_copy_vadd(w
->active
, fmt
, ap
);
91 /* Show info from command. */
93 cmdq_info(struct cmd_q
*cmdq
, const char *fmt
, ...)
95 struct client
*c
= cmdq
->client
;
99 if (options_get_number(&global_options
, "quiet"))
106 else if (c
->session
== NULL
|| (c
->flags
& CLIENT_CONTROL
)) {
108 evbuffer_add_vprintf(c
->stdout_data
, fmt
, ap
);
111 evbuffer_add(c
->stdout_data
, "\n", 1);
112 server_push_stdout(c
);
114 xvasprintf(&msg
, fmt
, ap
);
115 *msg
= toupper((u_char
) *msg
);
116 status_message_set(c
, "%s", msg
);
124 /* Show error from command. */
126 cmdq_error(struct cmd_q
*cmdq
, const char *fmt
, ...)
128 struct client
*c
= cmdq
->client
;
129 struct cmd
*cmd
= cmdq
->cmd
;
135 msglen
= xvasprintf(&msg
, fmt
, ap
);
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);
145 server_push_stderr(c
);
148 *msg
= toupper((u_char
) *msg
);
149 status_message_set(c
, "%s", msg
);
155 /* Print a guard line. */
157 cmdq_guard(struct cmd_q
*cmdq
, const char *guard
, int flags
)
159 struct client
*c
= cmdq
->client
;
163 if (!(c
->flags
& CLIENT_CONTROL
))
166 evbuffer_add_printf(c
->stdout_data
, "%%%s %ld %u %d\n", guard
,
167 (long) cmdq
->time
, cmdq
->number
, flags
);
168 server_push_stdout(c
);
172 /* Add command list to queue and begin processing if needed. */
174 cmdq_run(struct cmd_q
*cmdq
, struct cmd_list
*cmdlist
)
176 cmdq_append(cmdq
, cmdlist
);
178 if (cmdq
->item
== NULL
) {
184 /* Add command list to queue. */
186 cmdq_append(struct cmd_q
*cmdq
, struct cmd_list
*cmdlist
)
188 struct cmd_q_item
*item
;
190 item
= xcalloc(1, sizeof *item
);
191 item
->cmdlist
= cmdlist
;
192 TAILQ_INSERT_TAIL(&cmdq
->queue
, item
, qentry
);
193 cmdlist
->references
++;
196 /* Continue processing command queue. Returns 1 if finishes empty. */
198 cmdq_continue(struct cmd_q
*cmdq
)
200 struct cmd_q_item
*next
;
201 enum cmd_retval retval
;
202 int empty
, guard
, flags
;
207 empty
= TAILQ_EMPTY(&cmdq
->queue
);
211 if (cmdq
->item
== NULL
) {
212 cmdq
->item
= TAILQ_FIRST(&cmdq
->queue
);
213 cmdq
->cmd
= TAILQ_FIRST(&cmdq
->item
->cmdlist
->list
);
215 cmdq
->cmd
= TAILQ_NEXT(cmdq
->cmd
, qentry
);
218 next
= TAILQ_NEXT(cmdq
->item
, qentry
);
220 while (cmdq
->cmd
!= NULL
) {
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);
225 cmdq
->time
= time(NULL
);
228 flags
= !!(cmdq
->cmd
->flags
& CMD_CONTROL
);
229 guard
= cmdq_guard(cmdq
, "begin", flags
);
231 retval
= cmdq
->cmd
->entry
->exec(cmdq
->cmd
, cmdq
);
234 if (retval
== CMD_RETURN_ERROR
)
235 cmdq_guard(cmdq
, "error", flags
);
237 cmdq_guard(cmdq
, "end", flags
);
240 if (retval
== CMD_RETURN_ERROR
)
242 if (retval
== CMD_RETURN_WAIT
)
244 if (retval
== CMD_RETURN_STOP
) {
249 cmdq
->cmd
= TAILQ_NEXT(cmdq
->cmd
, qentry
);
252 TAILQ_REMOVE(&cmdq
->queue
, cmdq
->item
, qentry
);
253 cmd_list_free(cmdq
->item
->cmdlist
);
257 if (cmdq
->item
!= NULL
)
258 cmdq
->cmd
= TAILQ_FIRST(&cmdq
->item
->cmdlist
->list
);
259 } while (cmdq
->item
!= NULL
);
262 if (cmdq
->client_exit
)
263 cmdq
->client
->flags
|= CLIENT_EXIT
;
264 if (cmdq
->emptyfn
!= NULL
)
265 cmdq
->emptyfn(cmdq
); /* may free cmdq */
273 /* Flush command queue. */
275 cmdq_flush(struct cmd_q
*cmdq
)
277 struct cmd_q_item
*item
, *item1
;
279 TAILQ_FOREACH_SAFE(item
, &cmdq
->queue
, qentry
, item1
) {
280 TAILQ_REMOVE(&cmdq
->queue
, item
, qentry
);
281 cmd_list_free(item
->cmdlist
);