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 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 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 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