Merge branch 'obsd-master'

This commit is contained in:
Thomas Adam
2019-05-23 13:02:27 +01:00
19 changed files with 1821 additions and 900 deletions

236
cfg.c
View File

@ -26,17 +26,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;
@ -85,9 +74,8 @@ start_cfg(void)
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.
@ -102,11 +90,11 @@ start_cfg(void)
}
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);
@ -114,214 +102,54 @@ start_cfg(void)
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);
}
TAILQ_INIT(&conds);
if (new_item != NULL)
*new_item = NULL;
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