Merge branch 'obsd-master'

pull/714/head
Thomas Adam 2017-01-09 22:01:12 +00:00
commit 2c862b04af
4 changed files with 166 additions and 34 deletions

44
cfg.c
View File

@ -81,12 +81,14 @@ int
load_cfg(const char *path, struct client *c, struct cmdq_item *item, int quiet)
{
FILE *f;
char delim[3] = { '\\', '\\', '\0' };
u_int found;
const char delim[3] = { '\\', '\\', '\0' };
u_int found = 0;
size_t line = 0;
char *buf, *cause1, *p;
char *buf, *cause1, *p, *q, *s;
struct cmd_list *cmdlist;
struct cmdq_item *new_item;
int condition = 0;
struct format_tree *ft;
log_debug("loading %s", path);
if ((f = fopen(path, "rb")) == NULL) {
@ -96,20 +98,48 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item, int quiet)
return (-1);
}
found = 0;
while ((buf = fparseln(f, NULL, &line, delim, 0)) != NULL) {
log_debug("%s: %s", path, buf);
/* Skip empty lines. */
p = buf;
while (isspace((u_char) *p))
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 (condition != 0 && strcmp(p, "%endif") == 0) {
condition = 0;
continue;
}
if (strncmp(p, "%if ", 4) == 0) {
if (condition != 0) {
cfg_add_cause("%s:%zu: nested %%if", path,
line);
continue;
}
ft = format_create(NULL, FORMAT_NOJOBS);
s = p + 3;
while (isspace((u_char)*s))
s++;
s = format_expand(ft, s);
if (*s != '\0' && (s[0] != '0' || s[1] != '\0'))
condition = 1;
else
condition = -1;
free(s);
format_free(ft);
continue;
}
if (condition == -1)
continue;
/* Parse and run the command. */
if (cmd_string_parse(p, &cmdlist, path, line, &cause1) != 0) {
free(buf);
if (cause1 == NULL)

116
format.c
View File

@ -727,6 +727,50 @@ found:
return (copy);
}
/* Skip until comma. */
static char *
format_skip(char *s)
{
int brackets = 0;
for (; *s != '\0'; s++) {
if (*s == '{')
brackets++;
if (*s == '}')
brackets--;
if (*s == ',' && brackets == 0)
break;
}
if (*s == '\0')
return (NULL);
return (s);
}
/* Return left and right alternatives separated by commas. */
static int
format_choose(char *s, char **left, char **right)
{
char *cp;
cp = format_skip(s);
if (cp == NULL)
return (-1);
*cp = '\0';
*left = s;
*right = cp + 1;
return (0);
}
/* Is this true? */
static int
format_true(const char *s)
{
if (s != NULL && *s != '\0' && (s[0] != '0' || s[1] != '\0'))
return (1);
return (0);
}
/*
* Replace a key/value pair in buffer. #{blah} is expanded directly,
* #{?blah,a,b} is replace with a if blah exists and is nonzero else b.
@ -736,10 +780,10 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
char **buf, size_t *len, size_t *off)
{
char *copy, *copy0, *endptr, *ptr, *found, *new, *value;
char *from = NULL, *to = NULL;
char *from = NULL, *to = NULL, *left, *right;
size_t valuelen, newlen, fromlen, tolen, used;
long limit = 0;
int modifiers = 0, brackets;
int modifiers = 0, compare = 0;
/* Make a copy of the key. */
copy0 = copy = xmalloc(keylen + 1);
@ -748,7 +792,19 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
/* Is there a length limit or whatnot? */
switch (copy[0]) {
case '!':
if (copy[1] == '=' && copy[2] == ':') {
compare = -1;
copy += 3;
break;
}
break;
case '=':
if (copy[1] == '=' && copy[2] == ':') {
compare = 1;
copy += 3;
break;
}
errno = 0;
limit = strtol(copy + 1, &endptr, 10);
if (errno == ERANGE && (limit == LONG_MIN || limit == LONG_MAX))
@ -800,39 +856,42 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
break;
}
/*
* Is this a conditional? If so, check it exists and extract either the
* first or second element. If not, look up the key directly.
*/
if (*copy == '?') {
ptr = strchr(copy, ',');
/* Is this a comparison or a conditional? */
if (compare != 0) {
/* Comparison: compare comma-separated left and right. */
if (format_choose(copy, &left, &right) != 0)
goto fail;
left = format_expand(ft, left);
right = format_expand(ft, right);
if (compare == 1 && strcmp(left, right) == 0)
value = xstrdup("1");
else if (compare == -1 && strcmp(left, right) != 0)
value = xstrdup("1");
else
value = xstrdup("0");
free(right);
free(left);
} else if (*copy == '?') {
/* Conditional: check first and choose second or third. */
ptr = format_skip(copy);
if (ptr == NULL)
goto fail;
*ptr = '\0';
value = ptr + 1;
found = format_find(ft, copy + 1, modifiers);
brackets = 0;
for (ptr = ptr + 1; *ptr != '\0'; ptr++) {
if (*ptr == '{')
brackets++;
if (*ptr == '}')
brackets--;
if (*ptr == ',' && brackets == 0)
break;
}
if (*ptr == '\0')
if (found == NULL) {
log_debug("XXX %s", copy + 1);
found = format_expand(ft, copy + 1);}
if (format_choose(ptr + 1, &left, &right) != 0)
goto fail;
if (found != NULL && *found != '\0' &&
(found[0] != '0' || found[1] != '\0')) {
*ptr = '\0';
} else
value = ptr + 1;
value = format_expand(ft, value);
if (format_true(found))
value = format_expand(ft, left);
else
value = format_expand(ft, right);
free(found);
} else {
/* Neither: look up directly. */
value = format_find(ft, copy, modifiers);
if (value == NULL)
value = xstrdup("");
@ -954,7 +1013,10 @@ format_expand(struct format_tree *ft, const char *fmt)
break;
n = ptr - fmt;
out = format_job_get(ft, xstrndup(fmt, n));
if (ft->flags & FORMAT_NOJOBS)
out = xstrdup("");
else
out = format_job_get(ft, xstrndup(fmt, n));
outlen = strlen(out);
while (len - off < outlen + 1) {

39
tmux.1
View File

@ -934,6 +934,30 @@ If
is given, no error will be returned if
.Ar path
does not exist.
.Pp
Within a configuration file, commands may be made conditional by surrounding
them with
.Em %if
and
.Em %endif
lines.
The argument to
.Em %if
is expanded as a format and if it evaluates to false
.Ns ( Ql 0
or empty), subsequent lines are ignored until
.Em %endif .
For example:
.Bd -literal -offset indent
%if #{==:#{host},myhost}
set -g status-style bg=red
%endif
.Ed
.Pp
Will change the status line to red if running on
.Ql myhost .
.Em %if
may not be nested.
.It Ic start-server
.D1 (alias: Ic start )
Start the
@ -3401,6 +3425,21 @@ is enabled, or
.Ql no
if not.
.Pp
Simple comparisons may be expressed by prefixing two comma-separated
alternatives by
.Ql ==
or
.Ql !=
and a colon.
For example
.Ql #{==,#{host},myhost}
will be replaced by
.Ql 1
if running on
.Ql myhost ,
otherwise by
.Ql 0.
.Pp
A limit may be placed on the length of the resultant string by prefixing it
by an
.Ql = ,

1
tmux.h
View File

@ -1570,6 +1570,7 @@ char *paste_make_sample(struct paste_buffer *);
/* format.c */
#define FORMAT_STATUS 0x1
#define FORMAT_FORCE 0x2
#define FORMAT_NOJOBS 0x4
struct format_tree;
struct format_tree *format_create(struct cmdq_item *, int);
void format_free(struct format_tree *);