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