=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/tmux/cfg.c,v retrieving revision 1.70 retrieving revision 1.71 diff -u -r1.70 -r1.71 --- src/usr.bin/tmux/cfg.c 2019/05/20 13:23:32 1.70 +++ src/usr.bin/tmux/cfg.c 2019/05/23 11:13:30 1.71 @@ -1,4 +1,4 @@ -/* $OpenBSD: cfg.c,v 1.70 2019/05/20 13:23:32 nicm Exp $ */ +/* $OpenBSD: cfg.c,v 1.71 2019/05/23 11:13:30 nicm Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -27,17 +27,6 @@ #include "tmux.h" -/* Condition for %if, %elif, %else and %endif. */ -struct cfg_cond { - size_t line; /* line number of %if */ - int met; /* condition was met */ - int skip; /* skip later %elif/%else */ - int saw_else; /* saw a %else */ - - TAILQ_ENTRY(cfg_cond) entry; -}; -TAILQ_HEAD(cfg_conds, cfg_cond); - struct client *cfg_client; static char *cfg_file; int cfg_finished; @@ -86,9 +75,8 @@ struct client *c; /* - * Configuration files are loaded without a client, so NULL is passed - * into load_cfg() and commands run in the global queue with - * item->client NULL. + * Configuration files are loaded without a client, so commands are run + * in the global queue with item->client NULL. * * However, we must block the initial client (but just the initial * client) so that its command runs after the configuration is loaded. @@ -103,11 +91,11 @@ } if (cfg_file == NULL) - load_cfg(TMUX_CONF, NULL, NULL, CFG_QUIET, NULL); + load_cfg(TMUX_CONF, NULL, NULL, CMD_PARSE_QUIET, NULL); if (cfg_file == NULL && (home = find_home()) != NULL) { xasprintf(&cfg_file, "%s/.tmux.conf", home); - flags = CFG_QUIET; + flags = CMD_PARSE_QUIET; } if (cfg_file != NULL) load_cfg(cfg_file, NULL, NULL, flags, NULL); @@ -115,214 +103,54 @@ cmdq_append(NULL, cmdq_get_callback(cfg_done, NULL)); } -static int -cfg_check_cond(const char *path, size_t line, const char *p, int *skip, - struct client *c, struct cmd_find_state *fs) -{ - struct format_tree *ft; - char *s; - int result; - - while (isspace((u_char)*p)) - p++; - if (p[0] == '\0') { - cfg_add_cause("%s:%zu: invalid condition", path, line); - *skip = 1; - return (0); - } - - ft = format_create(NULL, NULL, FORMAT_NONE, FORMAT_NOJOBS); - if (fs != NULL) - format_defaults(ft, c, fs->s, fs->wl, fs->wp); - else - format_defaults(ft, c, NULL, NULL, NULL); - s = format_expand(ft, p); - result = format_true(s); - free(s); - format_free(ft); - - *skip = result; - return (result); -} - -static void -cfg_handle_if(const char *path, size_t line, struct cfg_conds *conds, - const char *p, struct client *c, struct cmd_find_state *fs) -{ - struct cfg_cond *cond; - struct cfg_cond *parent = TAILQ_FIRST(conds); - - /* - * Add a new condition. If a previous condition exists and isn't - * currently met, this new one also can't be met. - */ - cond = xcalloc(1, sizeof *cond); - cond->line = line; - if (parent == NULL || parent->met) - cond->met = cfg_check_cond(path, line, p, &cond->skip, c, fs); - else - cond->skip = 1; - cond->saw_else = 0; - TAILQ_INSERT_HEAD(conds, cond, entry); -} - -static void -cfg_handle_elif(const char *path, size_t line, struct cfg_conds *conds, - const char *p, struct client *c, struct cmd_find_state *fs) -{ - struct cfg_cond *cond = TAILQ_FIRST(conds); - - /* - * If a previous condition exists and wasn't met, check this - * one instead and change the state. - */ - if (cond == NULL || cond->saw_else) - cfg_add_cause("%s:%zu: unexpected %%elif", path, line); - else if (!cond->skip) - cond->met = cfg_check_cond(path, line, p, &cond->skip, c, fs); - else - cond->met = 0; -} - -static void -cfg_handle_else(const char *path, size_t line, struct cfg_conds *conds) -{ - struct cfg_cond *cond = TAILQ_FIRST(conds); - - /* - * If a previous condition exists and wasn't met and wasn't already - * %else, use this one instead. - */ - if (cond == NULL || cond->saw_else) { - cfg_add_cause("%s:%zu: unexpected %%else", path, line); - return; - } - cond->saw_else = 1; - cond->met = !cond->skip; - cond->skip = 1; -} - -static void -cfg_handle_endif(const char *path, size_t line, struct cfg_conds *conds) -{ - struct cfg_cond *cond = TAILQ_FIRST(conds); - - /* - * Remove previous condition if one exists. - */ - if (cond == NULL) { - cfg_add_cause("%s:%zu: unexpected %%endif", path, line); - return; - } - TAILQ_REMOVE(conds, cond, entry); - free(cond); -} - -static void -cfg_handle_directive(const char *p, const char *path, size_t line, - struct cfg_conds *conds, struct client *c, struct cmd_find_state *fs) -{ - int n = 0; - - while (p[n] != '\0' && !isspace((u_char)p[n])) - n++; - if (strncmp(p, "%if", n) == 0) - cfg_handle_if(path, line, conds, p + n, c, fs); - else if (strncmp(p, "%elif", n) == 0) - cfg_handle_elif(path, line, conds, p + n, c, fs); - else if (strcmp(p, "%else") == 0) - cfg_handle_else(path, line, conds); - else if (strcmp(p, "%endif") == 0) - cfg_handle_endif(path, line, conds); - else - cfg_add_cause("%s:%zu: invalid directive: %s", path, line, p); -} - int load_cfg(const char *path, struct client *c, struct cmdq_item *item, int flags, struct cmdq_item **new_item) { FILE *f; - const char delim[3] = { '\\', '\\', '\0' }; - u_int found = 0; - size_t line = 0; - char *buf, *cause1, *p, *q; - struct cmd_list *cmdlist; + struct cmd_parse_input pi; + struct cmd_parse_result *pr; struct cmdq_item *new_item0; - struct cfg_cond *cond, *cond1; - struct cfg_conds conds; - struct cmd_find_state *fs = NULL; - struct client *fc = NULL; - if (item != NULL) { - fs = &item->target; - fc = cmd_find_client(item, NULL, 1); - } + if (new_item != NULL) + *new_item = NULL; - TAILQ_INIT(&conds); - log_debug("loading %s", path); if ((f = fopen(path, "rb")) == NULL) { - if (errno == ENOENT && (flags & CFG_QUIET)) + if (errno == ENOENT && (flags & CMD_PARSE_QUIET)) return (0); cfg_add_cause("%s: %s", path, strerror(errno)); return (-1); } - while ((buf = fparseln(f, NULL, &line, delim, 0)) != NULL) { - log_debug("%s: %s", path, buf); + memset(&pi, 0, sizeof pi); + pi.flags = flags; + pi.file = path; - p = buf; - while (isspace((u_char)*p)) - p++; - if (*p == '\0') { - free(buf); - continue; - } - q = p + strlen(p) - 1; - while (q != p && isspace((u_char)*q)) - *q-- = '\0'; - - if (*p == '%') { - cfg_handle_directive(p, path, line, &conds, fc, fs); - continue; - } - cond = TAILQ_FIRST(&conds); - if (cond != NULL && !cond->met) - continue; - - cmdlist = cmd_string_parse(p, path, line, &cause1); - if (cmdlist == NULL) { - free(buf); - if (cause1 == NULL) - continue; - cfg_add_cause("%s:%zu: %s", path, line, cause1); - free(cause1); - continue; - } - free(buf); - - new_item0 = cmdq_get_command(cmdlist, NULL, NULL, 0); - if (item != NULL) { - cmdq_insert_after(item, new_item0); - item = new_item0; - } else - cmdq_append(c, new_item0); - cmd_list_free(cmdlist); - - found++; - } + pr = cmd_parse_from_file(f, &pi); fclose(f); - - TAILQ_FOREACH_REVERSE_SAFE(cond, &conds, cfg_conds, entry, cond1) { - cfg_add_cause("%s:%zu: unterminated %%if", path, cond->line); - TAILQ_REMOVE(&conds, cond, entry); - free(cond); + if (pr->status == CMD_PARSE_EMPTY) + return (0); + if (pr->status == CMD_PARSE_ERROR) { + cfg_add_cause("%s", pr->error); + free(pr->error); + return (-1); } + if (flags & CMD_PARSE_PARSEONLY) { + cmd_list_free(pr->cmdlist); + return (0); + } + new_item0 = cmdq_get_command(pr->cmdlist, NULL, NULL, 0); + if (item != NULL) + cmdq_insert_after(item, new_item0); + else + cmdq_append(c, new_item0); + cmd_list_free(pr->cmdlist); + if (new_item != NULL) - *new_item = item; - return (found); + *new_item = new_item0; + return (0); } void