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
= -1;
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
)) {
72 evbuffer_add_vprintf(c
->stdout_data
, fmt
, ap
);
74 evbuffer_add(c
->stdout_data
, "\n", 1);
75 server_push_stdout(c
);
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
);
83 window_copy_vadd(w
->active
, fmt
, ap
);
89 /* Show info from command. */
91 cmdq_info(struct cmd_q
*cmdq
, const char *fmt
, ...)
93 struct client
*c
= cmdq
->client
;
97 if (options_get_number(&global_options
, "quiet"))
104 else if (c
->session
== NULL
|| (c
->flags
& CLIENT_CONTROL
)) {
105 evbuffer_add_vprintf(c
->stdout_data
, fmt
, ap
);
107 evbuffer_add(c
->stdout_data
, "\n", 1);
108 server_push_stdout(c
);
110 xvasprintf(&msg
, fmt
, ap
);
111 *msg
= toupper((u_char
) *msg
);
112 status_message_set(c
, "%s", msg
);
120 /* Show error from command. */
122 cmdq_error(struct cmd_q
*cmdq
, const char *fmt
, ...)
124 struct client
*c
= cmdq
->client
;
125 struct cmd
*cmd
= cmdq
->cmd
;
131 msglen
= xvasprintf(&msg
, fmt
, ap
);
135 xasprintf(&cause
, "%s:%u: %s", cmd
->file
, cmd
->line
, msg
);
136 ARRAY_ADD(&cfg_causes
, cause
);
137 } else if (c
->session
== NULL
|| (c
->flags
& CLIENT_CONTROL
)) {
138 evbuffer_add(c
->stderr_data
, msg
, msglen
);
139 evbuffer_add(c
->stderr_data
, "\n", 1);
141 server_push_stderr(c
);
144 *msg
= toupper((u_char
) *msg
);
145 status_message_set(c
, "%s", msg
);
151 /* Print a guard line. */
153 cmdq_guard(struct cmd_q
*cmdq
, const char *guard
, int flags
)
155 struct client
*c
= cmdq
->client
;
159 if (!(c
->flags
& CLIENT_CONTROL
))
162 evbuffer_add_printf(c
->stdout_data
, "%%%s %ld %u %d\n", guard
,
163 (long) cmdq
->time
, cmdq
->number
, flags
);
164 server_push_stdout(c
);
168 /* Add command list to queue and begin processing if needed. */
170 cmdq_run(struct cmd_q
*cmdq
, struct cmd_list
*cmdlist
)
172 cmdq_append(cmdq
, cmdlist
);
174 if (cmdq
->item
== NULL
) {
180 /* Add command list to queue. */
182 cmdq_append(struct cmd_q
*cmdq
, struct cmd_list
*cmdlist
)
184 struct cmd_q_item
*item
;
186 item
= xcalloc(1, sizeof *item
);
187 item
->cmdlist
= cmdlist
;
188 TAILQ_INSERT_TAIL(&cmdq
->queue
, item
, qentry
);
189 cmdlist
->references
++;
192 /* Continue processing command queue. Returns 1 if finishes empty. */
194 cmdq_continue(struct cmd_q
*cmdq
)
196 struct cmd_q_item
*next
;
197 enum cmd_retval retval
;
198 int empty
, guard
, flags
;
203 empty
= TAILQ_EMPTY(&cmdq
->queue
);
207 if (cmdq
->item
== NULL
) {
208 cmdq
->item
= TAILQ_FIRST(&cmdq
->queue
);
209 cmdq
->cmd
= TAILQ_FIRST(&cmdq
->item
->cmdlist
->list
);
211 cmdq
->cmd
= TAILQ_NEXT(cmdq
->cmd
, qentry
);
214 next
= TAILQ_NEXT(cmdq
->item
, qentry
);
216 while (cmdq
->cmd
!= NULL
) {
217 cmd_print(cmdq
->cmd
, s
, sizeof s
);
218 log_debug("cmdq %p: %s (client %d)", cmdq
, s
,
219 cmdq
->client
!= NULL
? cmdq
->client
->ibuf
.fd
: -1);
221 cmdq
->time
= time(NULL
);
224 flags
= !!(cmdq
->cmd
->flags
& CMD_CONTROL
);
225 guard
= cmdq_guard(cmdq
, "begin", flags
);
227 retval
= cmdq
->cmd
->entry
->exec(cmdq
->cmd
, cmdq
);
230 if (retval
== CMD_RETURN_ERROR
)
231 cmdq_guard(cmdq
, "error", flags
);
233 cmdq_guard(cmdq
, "end", flags
);
236 if (retval
== CMD_RETURN_ERROR
)
238 if (retval
== CMD_RETURN_WAIT
)
240 if (retval
== CMD_RETURN_STOP
) {
245 cmdq
->cmd
= TAILQ_NEXT(cmdq
->cmd
, qentry
);
248 TAILQ_REMOVE(&cmdq
->queue
, cmdq
->item
, qentry
);
249 cmd_list_free(cmdq
->item
->cmdlist
);
253 if (cmdq
->item
!= NULL
)
254 cmdq
->cmd
= TAILQ_FIRST(&cmdq
->item
->cmdlist
->list
);
255 } while (cmdq
->item
!= NULL
);
258 if (cmdq
->client_exit
> 0)
259 cmdq
->client
->flags
|= CLIENT_EXIT
;
260 if (cmdq
->emptyfn
!= NULL
)
261 cmdq
->emptyfn(cmdq
); /* may free cmdq */
269 /* Flush command queue. */
271 cmdq_flush(struct cmd_q
*cmdq
)
273 struct cmd_q_item
*item
, *item1
;
275 TAILQ_FOREACH_SAFE(item
, &cmdq
->queue
, qentry
, item1
) {
276 TAILQ_REMOVE(&cmdq
->queue
, item
, qentry
);
277 cmd_list_free(item
->cmdlist
);