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>
30 struct client
*cfg_client
;
32 static char **cfg_causes
;
33 static u_int cfg_ncauses
;
34 static struct cmdq_item
*cfg_item
;
40 static enum cmd_retval
41 cfg_client_done(__unused
struct cmdq_item
*item
, __unused
void *data
)
44 return (CMD_RETURN_WAIT
);
45 return (CMD_RETURN_NORMAL
);
48 static enum cmd_retval
49 cfg_done(__unused
struct cmdq_item
*item
, __unused
void *data
)
52 return (CMD_RETURN_NORMAL
);
55 cfg_show_causes(NULL
);
58 cmdq_continue(cfg_item
);
60 status_prompt_load_history();
62 return (CMD_RETURN_NORMAL
);
73 * Configuration files are loaded without a client, so commands are run
74 * in the global queue with item->client NULL.
76 * However, we must block the initial client (but just the initial
77 * client) so that its command runs after the configuration is loaded.
78 * Because start_cfg() is called so early, we can be sure the client's
79 * command queue is currently empty and our callback will be at the
80 * front - we need to get in before MSG_COMMAND.
82 cfg_client
= c
= TAILQ_FIRST(&clients
);
84 cfg_item
= cmdq_get_callback(cfg_client_done
, NULL
);
85 cmdq_append(c
, cfg_item
);
89 flags
= CMD_PARSE_QUIET
;
90 for (i
= 0; i
< cfg_nfiles
; i
++)
91 load_cfg(cfg_files
[i
], c
, NULL
, NULL
, flags
, NULL
);
93 cmdq_append(NULL
, cmdq_get_callback(cfg_done
, NULL
));
97 load_cfg(const char *path
, struct client
*c
, struct cmdq_item
*item
,
98 struct cmd_find_state
*current
, int flags
, struct cmdq_item
**new_item
)
101 struct cmd_parse_input pi
;
102 struct cmd_parse_result
*pr
;
103 struct cmdq_item
*new_item0
;
104 struct cmdq_state
*state
;
106 if (new_item
!= NULL
)
109 log_debug("loading %s", path
);
110 if ((f
= fopen(path
, "rb")) == NULL
) {
111 if (errno
== ENOENT
&& (flags
& CMD_PARSE_QUIET
))
113 cfg_add_cause("%s: %s", path
, strerror(errno
));
117 memset(&pi
, 0, sizeof pi
);
124 pr
= cmd_parse_from_file(f
, &pi
);
126 if (pr
->status
== CMD_PARSE_ERROR
) {
127 cfg_add_cause("%s", pr
->error
);
131 if (flags
& CMD_PARSE_PARSEONLY
) {
132 cmd_list_free(pr
->cmdlist
);
137 state
= cmdq_copy_state(cmdq_get_state(item
), current
);
139 state
= cmdq_new_state(NULL
, NULL
, 0);
140 cmdq_add_format(state
, "current_file", "%s", pi
.file
);
142 new_item0
= cmdq_get_command(pr
->cmdlist
, state
);
144 new_item0
= cmdq_insert_after(item
, new_item0
);
146 new_item0
= cmdq_append(NULL
, new_item0
);
147 cmd_list_free(pr
->cmdlist
);
148 cmdq_free_state(state
);
150 if (new_item
!= NULL
)
151 *new_item
= new_item0
;
156 load_cfg_from_buffer(const void *buf
, size_t len
, const char *path
,
157 struct client
*c
, struct cmdq_item
*item
, struct cmd_find_state
*current
,
158 int flags
, struct cmdq_item
**new_item
)
160 struct cmd_parse_input pi
;
161 struct cmd_parse_result
*pr
;
162 struct cmdq_item
*new_item0
;
163 struct cmdq_state
*state
;
165 if (new_item
!= NULL
)
168 log_debug("loading %s", path
);
170 memset(&pi
, 0, sizeof pi
);
177 pr
= cmd_parse_from_buffer(buf
, len
, &pi
);
178 if (pr
->status
== CMD_PARSE_ERROR
) {
179 cfg_add_cause("%s", pr
->error
);
183 if (flags
& CMD_PARSE_PARSEONLY
) {
184 cmd_list_free(pr
->cmdlist
);
189 state
= cmdq_copy_state(cmdq_get_state(item
), current
);
191 state
= cmdq_new_state(NULL
, NULL
, 0);
192 cmdq_add_format(state
, "current_file", "%s", pi
.file
);
194 new_item0
= cmdq_get_command(pr
->cmdlist
, state
);
196 new_item0
= cmdq_insert_after(item
, new_item0
);
198 new_item0
= cmdq_append(NULL
, new_item0
);
199 cmd_list_free(pr
->cmdlist
);
200 cmdq_free_state(state
);
202 if (new_item
!= NULL
)
203 *new_item
= new_item0
;
208 cfg_add_cause(const char *fmt
, ...)
214 xvasprintf(&msg
, fmt
, ap
);
218 cfg_causes
= xreallocarray(cfg_causes
, cfg_ncauses
, sizeof *cfg_causes
);
219 cfg_causes
[cfg_ncauses
- 1] = msg
;
223 cfg_print_causes(struct cmdq_item
*item
)
227 for (i
= 0; i
< cfg_ncauses
; i
++) {
228 cmdq_print(item
, "%s", cfg_causes
[i
]);
238 cfg_show_causes(struct session
*s
)
240 struct client
*c
= TAILQ_FIRST(&clients
);
241 struct window_pane
*wp
;
242 struct window_mode_entry
*wme
;
245 if (cfg_ncauses
== 0)
248 if (c
!= NULL
&& (c
->flags
& CLIENT_CONTROL
)) {
249 for (i
= 0; i
< cfg_ncauses
; i
++) {
250 control_write(c
, "%%config-error %s", cfg_causes
[i
]);
257 if (c
!= NULL
&& c
->session
!= NULL
)
260 s
= RB_MIN(sessions
, &sessions
);
262 if (s
== NULL
|| s
->attached
== 0) /* wait for an attached session */
264 wp
= s
->curw
->window
->active
;
266 wme
= TAILQ_FIRST(&wp
->modes
);
267 if (wme
== NULL
|| wme
->mode
!= &window_view_mode
)
268 window_pane_set_mode(wp
, NULL
, &window_view_mode
, NULL
, NULL
);
269 for (i
= 0; i
< cfg_ncauses
; i
++) {
270 window_copy_add(wp
, 0, "%s", cfg_causes
[i
]);