xref: /openbsd/usr.bin/tmux/cfg.c (revision a6445c1d)
1 /* $OpenBSD: cfg.c,v 1.33 2014/10/27 22:23:47 nicm Exp $ */
2 
3 /*
4  * Copyright (c) 2008 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 <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <util.h>
27 
28 #include "tmux.h"
29 
30 struct cmd_q		*cfg_cmd_q;
31 int			 cfg_finished;
32 int			 cfg_references;
33 ARRAY_DECL (, char *)	 cfg_causes = ARRAY_INITIALIZER;
34 struct client		*cfg_client;
35 
36 int
37 load_cfg(const char *path, struct cmd_q *cmdq, char **cause)
38 {
39 	FILE		*f;
40 	char		 delim[3] = { '\\', '\\', '\0' };
41 	u_int		 found;
42 	size_t		 line = 0;
43 	char		*buf, *cause1, *p;
44 	struct cmd_list	*cmdlist;
45 
46 	log_debug("loading %s", path);
47 	if ((f = fopen(path, "rb")) == NULL) {
48 		xasprintf(cause, "%s: %s", path, strerror(errno));
49 		return (-1);
50 	}
51 
52 	found = 0;
53 	while ((buf = fparseln(f, NULL, &line, delim, 0))) {
54 		log_debug("%s: %s", path, buf);
55 
56 		/* Skip empty lines. */
57 		p = buf;
58 		while (isspace((u_char) *p))
59 			p++;
60 		if (*p == '\0') {
61 			free(buf);
62 			continue;
63 		}
64 
65 		/* Parse and run the command. */
66 		if (cmd_string_parse(p, &cmdlist, path, line, &cause1) != 0) {
67 			free(buf);
68 			if (cause1 == NULL)
69 				continue;
70 			cfg_add_cause("%s:%zu: %s", path, line, cause1);
71 			free(cause1);
72 			continue;
73 		}
74 		free(buf);
75 
76 		if (cmdlist == NULL)
77 			continue;
78 		cmdq_append(cmdq, cmdlist);
79 		cmd_list_free(cmdlist);
80 		found++;
81 	}
82 	fclose(f);
83 
84 	return (found);
85 }
86 
87 void
88 cfg_default_done(unused struct cmd_q *cmdq)
89 {
90 	if (--cfg_references != 0)
91 		return;
92 	cfg_finished = 1;
93 
94 	if (!RB_EMPTY(&sessions))
95 		cfg_show_causes(RB_MIN(sessions, &sessions));
96 
97 	cmdq_free(cfg_cmd_q);
98 	cfg_cmd_q = NULL;
99 
100 	if (cfg_client != NULL) {
101 		/*
102 		 * The client command queue starts with client_exit set to 1 so
103 		 * only continue if not empty (that is, we have been delayed
104 		 * during configuration parsing for long enough that the
105 		 * MSG_COMMAND has arrived), else the client will exit before
106 		 * the MSG_COMMAND which might tell it not to.
107 		 */
108 		if (!TAILQ_EMPTY(&cfg_client->cmdq->queue))
109 			cmdq_continue(cfg_client->cmdq);
110 		cfg_client->references--;
111 		cfg_client = NULL;
112 	}
113 }
114 
115 void
116 cfg_add_cause(const char* fmt, ...)
117 {
118 	va_list	ap;
119 	char*	msg;
120 
121 	va_start(ap, fmt);
122 	xvasprintf(&msg, fmt, ap);
123 	va_end (ap);
124 
125 	ARRAY_ADD(&cfg_causes, msg);
126 }
127 
128 void
129 cfg_print_causes(struct cmd_q *cmdq)
130 {
131 	char	*cause;
132 	u_int	 i;
133 
134 	for (i = 0; i < ARRAY_LENGTH(&cfg_causes); i++) {
135 		cause = ARRAY_ITEM(&cfg_causes, i);
136 		cmdq_print(cmdq, "%s", cause);
137 		free(cause);
138 	}
139 	ARRAY_FREE(&cfg_causes);
140 }
141 
142 void
143 cfg_show_causes(struct session *s)
144 {
145 	struct window_pane	*wp;
146 	char			*cause;
147 	u_int			 i;
148 
149 	if (s == NULL || ARRAY_EMPTY(&cfg_causes))
150 		return;
151 	wp = s->curw->window->active;
152 
153 	window_pane_set_mode(wp, &window_copy_mode);
154 	window_copy_init_for_output(wp);
155 	for (i = 0; i < ARRAY_LENGTH(&cfg_causes); i++) {
156 		cause = ARRAY_ITEM(&cfg_causes, i);
157 		window_copy_add(wp, "%s", cause);
158 		free(cause);
159 	}
160 	ARRAY_FREE(&cfg_causes);
161 }
162