1 /* $OpenBSD: cfg.c,v 1.53 2017/01/15 22:00:56 nicm Exp $ */ 2 3 /* 4 * Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com> 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 <unistd.h> 27 #include <util.h> 28 29 #include "tmux.h" 30 31 char *cfg_file; 32 int cfg_finished; 33 static char **cfg_causes; 34 static u_int cfg_ncauses; 35 struct client *cfg_client; 36 37 static enum cmd_retval 38 cfg_done(__unused struct cmdq_item *item, __unused void *data) 39 { 40 if (cfg_finished) 41 return (CMD_RETURN_NORMAL); 42 cfg_finished = 1; 43 44 if (!RB_EMPTY(&sessions)) 45 cfg_show_causes(RB_MIN(sessions, &sessions)); 46 47 if (cfg_client != NULL) 48 server_client_unref(cfg_client); 49 return (CMD_RETURN_NORMAL); 50 } 51 52 void 53 set_cfg_file(const char *path) 54 { 55 free(cfg_file); 56 cfg_file = xstrdup(path); 57 } 58 59 void 60 start_cfg(void) 61 { 62 const char *home; 63 int quiet = 0; 64 65 cfg_client = TAILQ_FIRST(&clients); 66 if (cfg_client != NULL) 67 cfg_client->references++; 68 69 load_cfg(TMUX_CONF, cfg_client, NULL, 1); 70 71 if (cfg_file == NULL && (home = find_home()) != NULL) { 72 xasprintf(&cfg_file, "%s/.tmux.conf", home); 73 quiet = 1; 74 } 75 if (cfg_file != NULL) 76 load_cfg(cfg_file, cfg_client, NULL, quiet); 77 78 cmdq_append(cfg_client, cmdq_get_callback(cfg_done, NULL)); 79 } 80 81 int 82 load_cfg(const char *path, struct client *c, struct cmdq_item *item, int quiet) 83 { 84 FILE *f; 85 const char delim[3] = { '\\', '\\', '\0' }; 86 u_int found = 0; 87 size_t line = 0; 88 char *buf, *cause1, *p, *q, *s; 89 struct cmd_list *cmdlist; 90 struct cmdq_item *new_item; 91 int condition = 0; 92 struct format_tree *ft; 93 94 log_debug("loading %s", path); 95 if ((f = fopen(path, "rb")) == NULL) { 96 if (errno == ENOENT && quiet) 97 return (0); 98 cfg_add_cause("%s: %s", path, strerror(errno)); 99 return (-1); 100 } 101 102 while ((buf = fparseln(f, NULL, &line, delim, 0)) != NULL) { 103 log_debug("%s: %s", path, buf); 104 105 p = buf; 106 while (isspace((u_char)*p)) 107 p++; 108 if (*p == '\0') { 109 free(buf); 110 continue; 111 } 112 q = p + strlen(p) - 1; 113 while (q != p && isspace((u_char)*q)) 114 *q-- = '\0'; 115 116 if (condition != 0 && strcmp(p, "%endif") == 0) { 117 condition = 0; 118 continue; 119 } 120 if (strncmp(p, "%if ", 4) == 0) { 121 if (condition != 0) { 122 cfg_add_cause("%s:%zu: nested %%if", path, 123 line); 124 continue; 125 } 126 ft = format_create(NULL, FORMAT_NOJOBS); 127 128 s = p + 3; 129 while (isspace((u_char)*s)) 130 s++; 131 s = format_expand(ft, s); 132 if (*s != '\0' && (s[0] != '0' || s[1] != '\0')) 133 condition = 1; 134 else 135 condition = -1; 136 free(s); 137 138 format_free(ft); 139 continue; 140 } 141 if (condition == -1) 142 continue; 143 144 cmdlist = cmd_string_parse(p, path, line, &cause1); 145 if (cmdlist == NULL) { 146 free(buf); 147 if (cause1 == NULL) 148 continue; 149 cfg_add_cause("%s:%zu: %s", path, line, cause1); 150 free(cause1); 151 continue; 152 } 153 free(buf); 154 155 if (cmdlist == NULL) 156 continue; 157 new_item = cmdq_get_command(cmdlist, NULL, NULL, 0); 158 if (item != NULL) 159 cmdq_insert_after(item, new_item); 160 else 161 cmdq_append(c, new_item); 162 cmd_list_free(cmdlist); 163 164 found++; 165 } 166 fclose(f); 167 168 return (found); 169 } 170 171 void 172 cfg_add_cause(const char *fmt, ...) 173 { 174 va_list ap; 175 char *msg; 176 177 va_start(ap, fmt); 178 xvasprintf(&msg, fmt, ap); 179 va_end(ap); 180 181 cfg_ncauses++; 182 cfg_causes = xreallocarray(cfg_causes, cfg_ncauses, sizeof *cfg_causes); 183 cfg_causes[cfg_ncauses - 1] = msg; 184 } 185 186 void 187 cfg_print_causes(struct cmdq_item *item) 188 { 189 u_int i; 190 191 for (i = 0; i < cfg_ncauses; i++) { 192 cmdq_print(item, "%s", cfg_causes[i]); 193 free(cfg_causes[i]); 194 } 195 196 free(cfg_causes); 197 cfg_causes = NULL; 198 cfg_ncauses = 0; 199 } 200 201 void 202 cfg_show_causes(struct session *s) 203 { 204 struct window_pane *wp; 205 u_int i; 206 207 if (s == NULL || cfg_ncauses == 0) 208 return; 209 wp = s->curw->window->active; 210 211 window_pane_set_mode(wp, &window_copy_mode); 212 window_copy_init_for_output(wp); 213 for (i = 0; i < cfg_ncauses; i++) { 214 window_copy_add(wp, "%s", cfg_causes[i]); 215 free(cfg_causes[i]); 216 } 217 218 free(cfg_causes); 219 cfg_causes = NULL; 220 cfg_ncauses = 0; 221 } 222