xref: /minix/external/bsd/tmux/dist/cfg.c (revision 0a6a1f1d)
1 /* Id */
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 #include <sys/stat.h>
21 
22 #include <ctype.h>
23 #include <errno.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include "tmux.h"
29 
30 struct cmd_q		*cfg_cmd_q;
31 int			 cfg_finished;
32 int			 cfg_references;
33 struct causelist	 cfg_causes;
34 struct client		*cfg_client;
35 
36 int
load_cfg(const char * path,struct cmd_q * cmdq,char ** cause)37 load_cfg(const char *path, struct cmd_q *cmdq, char **cause)
38 {
39 	FILE		*f;
40 	u_int		 n, found;
41 	char		*buf, *copy, *line, *cause1, *msg;
42 	size_t		 len, oldlen;
43 	struct cmd_list	*cmdlist;
44 
45 	log_debug("loading %s", path);
46 	if ((f = fopen(path, "rb")) == NULL) {
47 		xasprintf(cause, "%s: %s", path, strerror(errno));
48 		return (-1);
49 	}
50 
51 	n = found = 0;
52 	line = NULL;
53 	while ((buf = fgetln(f, &len))) {
54 		/* Trim \n. */
55 		if (buf[len - 1] == '\n')
56 			len--;
57 		log_debug("%s: %.*s", path, (int)len, buf);
58 
59 		/* Current line is the continuation of the previous one. */
60 		if (line != NULL) {
61 			oldlen = strlen(line);
62 			line = xrealloc(line, 1, oldlen + len + 1);
63 		} else {
64 			oldlen = 0;
65 			line = xmalloc(len + 1);
66 		}
67 
68 		/* Append current line to the previous. */
69 		memcpy(line + oldlen, buf, len);
70 		line[oldlen + len] = '\0';
71 		n++;
72 
73 		/* Continuation: get next line? */
74 		len = strlen(line);
75 		if (len > 0 && line[len - 1] == '\\') {
76 			line[len - 1] = '\0';
77 
78 			/* Ignore escaped backslash at EOL. */
79 			if (len > 1 && line[len - 2] != '\\')
80 				continue;
81 		}
82 		copy = line;
83 		line = NULL;
84 
85 		/* Skip empty lines. */
86 		buf = copy;
87 		while (isspace((u_char)*buf))
88 			buf++;
89 		if (*buf == '\0') {
90 			free(copy);
91 			continue;
92 		}
93 
94 		/* Parse and run the command. */
95 		if (cmd_string_parse(buf, &cmdlist, path, n, &cause1) != 0) {
96 			free(copy);
97 			if (cause1 == NULL)
98 				continue;
99 			xasprintf(&msg, "%s:%u: %s", path, n, cause1);
100 			ARRAY_ADD(&cfg_causes, msg);
101 			free(cause1);
102 			continue;
103 		}
104 		free(copy);
105 
106 		if (cmdlist == NULL)
107 			continue;
108 		cmdq_append(cmdq, cmdlist);
109 		cmd_list_free(cmdlist);
110 		found++;
111 	}
112 	if (line != NULL)
113 		free(line);
114 	fclose(f);
115 
116 	return (found);
117 }
118 
119 void
cfg_default_done(unused struct cmd_q * cmdq)120 cfg_default_done(unused struct cmd_q *cmdq)
121 {
122 	if (--cfg_references != 0)
123 		return;
124 	cfg_finished = 1;
125 
126 	if (!RB_EMPTY(&sessions))
127 		cfg_show_causes(RB_MIN(sessions, &sessions));
128 
129 	cmdq_free(cfg_cmd_q);
130 	cfg_cmd_q = NULL;
131 
132 	if (cfg_client != NULL) {
133 		/*
134 		 * The client command queue starts with client_exit set to 1 so
135 		 * only continue if not empty (that is, we have been delayed
136 		 * during configuration parsing for long enough that the
137 		 * MSG_COMMAND has arrived), else the client will exit before
138 		 * the MSG_COMMAND which might tell it not to.
139 		 */
140 		if (!TAILQ_EMPTY(&cfg_client->cmdq->queue))
141 			cmdq_continue(cfg_client->cmdq);
142 		cfg_client->references--;
143 		cfg_client = NULL;
144 	}
145 }
146 
147 void
cfg_show_causes(struct session * s)148 cfg_show_causes(struct session *s)
149 {
150 	struct window_pane	*wp;
151 	char			*cause;
152 	u_int			 i;
153 
154 	if (s == NULL || ARRAY_EMPTY(&cfg_causes))
155 		return;
156 	wp = s->curw->window->active;
157 
158 	window_pane_set_mode(wp, &window_copy_mode);
159 	window_copy_init_for_output(wp);
160 	for (i = 0; i < ARRAY_LENGTH(&cfg_causes); i++) {
161 		cause = ARRAY_ITEM(&cfg_causes, i);
162 		window_copy_add(wp, "%s", cause);
163 		free(cause);
164 	}
165 	ARRAY_FREE(&cfg_causes);
166 }
167