4 * Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
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>
29 struct client
*cfg_client
;
31 static char **cfg_causes
;
32 static u_int cfg_ncauses
;
33 static struct cmdq_item
*cfg_item
;
39 static enum cmd_retval
40 cfg_client_done(__unused
struct cmdq_item
*item
, __unused
void *data
)
43 return (CMD_RETURN_WAIT
);
44 return (CMD_RETURN_NORMAL
);
47 static enum cmd_retval
48 cfg_done(__unused
struct cmdq_item
*item
, __unused
void *data
)
51 return (CMD_RETURN_NORMAL
);
54 cfg_show_causes(NULL
);
57 cmdq_continue(cfg_item
);
59 status_prompt_load_history();
61 return (CMD_RETURN_NORMAL
);
72 * Configuration files are loaded without a client, so commands are run
73 * in the global queue with item->client NULL.
75 * However, we must block the initial client (but just the initial
76 * client) so that its command runs after the configuration is loaded.
77 * Because start_cfg() is called so early, we can be sure the client's
78 * command queue is currently empty and our callback will be at the
79 * front - we need to get in before MSG_COMMAND.
81 cfg_client
= c
= TAILQ_FIRST(&clients
);
83 cfg_item
= cmdq_get_callback(cfg_client_done
, NULL
);
84 cmdq_append(c
, cfg_item
);
88 flags
= CMD_PARSE_QUIET
;
89 for (i
= 0; i
< cfg_nfiles
; i
++)
90 load_cfg(cfg_files
[i
], c
, NULL
, NULL
, flags
, NULL
);
92 cmdq_append(NULL
, cmdq_get_callback(cfg_done
, NULL
));
96 load_cfg(const char *path
, struct client
*c
, struct cmdq_item
*item
,
97 struct cmd_find_state
*current
, int flags
, struct cmdq_item
**new_item
)
100 struct cmd_parse_input pi
;
101 struct cmd_parse_result
*pr
;
102 struct cmdq_item
*new_item0
;
103 struct cmdq_state
*state
;
105 if (new_item
!= NULL
)
108 log_debug("loading %s", path
);
109 if ((f
= fopen(path
, "rb")) == NULL
) {
110 if (errno
== ENOENT
&& (flags
& CMD_PARSE_QUIET
))
112 cfg_add_cause("%s: %s", path
, strerror(errno
));
116 memset(&pi
, 0, sizeof pi
);
123 pr
= cmd_parse_from_file(f
, &pi
);
125 if (pr
->status
== CMD_PARSE_ERROR
) {
126 cfg_add_cause("%s", pr
->error
);
130 if (flags
& CMD_PARSE_PARSEONLY
) {
131 cmd_list_free(pr
->cmdlist
);
136 state
= cmdq_copy_state(cmdq_get_state(item
), current
);
138 state
= cmdq_new_state(NULL
, NULL
, 0);
139 cmdq_add_format(state
, "current_file", "%s", pi
.file
);
141 new_item0
= cmdq_get_command(pr
->cmdlist
, state
);
143 new_item0
= cmdq_insert_after(item
, new_item0
);
145 new_item0
= cmdq_append(NULL
, new_item0
);
146 cmd_list_free(pr
->cmdlist
);
147 cmdq_free_state(state
);
149 if (new_item
!= NULL
)
150 *new_item
= new_item0
;
155 load_cfg_from_buffer(const void *buf
, size_t len
, const char *path
,
156 struct client
*c
, struct cmdq_item
*item
, struct cmd_find_state
*current
,
157 int flags
, struct cmdq_item
**new_item
)
159 struct cmd_parse_input pi
;
160 struct cmd_parse_result
*pr
;
161 struct cmdq_item
*new_item0
;
162 struct cmdq_state
*state
;
164 if (new_item
!= NULL
)
167 log_debug("loading %s", path
);
169 memset(&pi
, 0, sizeof pi
);
176 pr
= cmd_parse_from_buffer(buf
, len
, &pi
);
177 if (pr
->status
== CMD_PARSE_ERROR
) {
178 cfg_add_cause("%s", pr
->error
);
182 if (flags
& CMD_PARSE_PARSEONLY
) {
183 cmd_list_free(pr
->cmdlist
);
188 state
= cmdq_copy_state(cmdq_get_state(item
), current
);
190 state
= cmdq_new_state(NULL
, NULL
, 0);
191 cmdq_add_format(state
, "current_file", "%s", pi
.file
);
193 new_item0
= cmdq_get_command(pr
->cmdlist
, state
);
195 new_item0
= cmdq_insert_after(item
, new_item0
);
197 new_item0
= cmdq_append(NULL
, new_item0
);
198 cmd_list_free(pr
->cmdlist
);
199 cmdq_free_state(state
);
201 if (new_item
!= NULL
)
202 *new_item
= new_item0
;
207 cfg_add_cause(const char *fmt
, ...)
213 xvasprintf(&msg
, fmt
, ap
);
217 cfg_causes
= xreallocarray(cfg_causes
, cfg_ncauses
, sizeof *cfg_causes
);
218 cfg_causes
[cfg_ncauses
- 1] = msg
;
222 cfg_print_causes(struct cmdq_item
*item
)
226 for (i
= 0; i
< cfg_ncauses
; i
++) {
227 cmdq_print(item
, "%s", cfg_causes
[i
]);
237 cfg_show_causes(struct session
*s
)
239 struct client
*c
= TAILQ_FIRST(&clients
);
240 struct window_pane
*wp
;
241 struct window_mode_entry
*wme
;
244 if (cfg_ncauses
== 0)
247 if (c
!= NULL
&& (c
->flags
& CLIENT_CONTROL
)) {
248 for (i
= 0; i
< cfg_ncauses
; i
++) {
249 control_write(c
, "%%config-error %s", cfg_causes
[i
]);
256 if (c
!= NULL
&& c
->session
!= NULL
)
259 s
= RB_MIN(sessions
, &sessions
);
261 if (s
== NULL
|| s
->attached
== 0) /* wait for an attached session */
263 wp
= s
->curw
->window
->active
;
265 wme
= TAILQ_FIRST(&wp
->modes
);
266 if (wme
== NULL
|| wme
->mode
!= &window_view_mode
)
267 window_pane_set_mode(wp
, NULL
, &window_view_mode
, NULL
, NULL
);
268 for (i
= 0; i
< cfg_ncauses
; i
++) {
269 window_copy_add(wp
, 0, "%s", cfg_causes
[i
]);