Merge branch 'obsd-master'

Also add a check for -lm via AC_SEARCH_LIBS in configure.ac for
portablility fixes.
pull/2097/head^2
Thomas Adam 2020-03-11 17:23:38 +00:00
commit e512a3642a
4 changed files with 151 additions and 4 deletions

View File

@ -122,6 +122,9 @@ AC_REPLACE_FUNCS([ \
]) ])
AC_FUNC_STRNLEN AC_FUNC_STRNLEN
# Look for libm
AC_SEARCH_LIBS(sqrt, m)
# Look for clock_gettime. Must come before event_init. # Look for clock_gettime. Must come before event_init.
AC_SEARCH_LIBS(clock_gettime, rt) AC_SEARCH_LIBS(clock_gettime, rt)

117
format.c
View File

@ -23,6 +23,7 @@
#include <errno.h> #include <errno.h>
#include <fnmatch.h> #include <fnmatch.h>
#include <libgen.h> #include <libgen.h>
#include <math.h>
#include <regex.h> #include <regex.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdlib.h> #include <stdlib.h>
@ -49,7 +50,6 @@ static void format_add_tv(struct format_tree *, const char *,
struct timeval *); struct timeval *);
static int format_replace(struct format_tree *, const char *, size_t, static int format_replace(struct format_tree *, const char *, size_t,
char **, size_t *, size_t *); char **, size_t *, size_t *);
static void format_defaults_session(struct format_tree *, static void format_defaults_session(struct format_tree *,
struct session *); struct session *);
static void format_defaults_client(struct format_tree *, struct client *); static void format_defaults_client(struct format_tree *, struct client *);
@ -1543,7 +1543,7 @@ format_build_modifiers(struct format_tree *ft, const char **s, u_int *count)
} }
/* Now try single character with arguments. */ /* Now try single character with arguments. */
if (strchr("mCs=p", cp[0]) == NULL) if (strchr("mCs=pe", cp[0]) == NULL)
break; break;
c = cp[0]; c = cp[0];
@ -1799,6 +1799,108 @@ format_loop_panes(struct format_tree *ft, const char *fmt)
return (value); return (value);
} }
static char *
format_replace_expression(struct format_modifier *mexp, struct format_tree *ft,
const char *copy)
{
int argc = mexp->argc;
const char *errstr;
char *endch, *value, *left = NULL, *right = NULL;
int use_fp = 0;
u_int prec = 0;
double mleft, mright, result;
enum { ADD, SUBTRACT, MULTIPLY, DIVIDE, MODULUS } operator;
if (strcmp(mexp->argv[0], "+") == 0)
operator = ADD;
else if (strcmp(mexp->argv[0], "-") == 0)
operator = SUBTRACT;
else if (strcmp(mexp->argv[0], "*") == 0)
operator = MULTIPLY;
else if (strcmp(mexp->argv[0], "/") == 0)
operator = DIVIDE;
else if (strcmp(mexp->argv[0], "%") == 0 ||
strcmp(mexp->argv[0], "m") == 0)
operator = MODULUS;
else {
format_log(ft, "expression has no valid operator: '%s'",
mexp->argv[0]);
goto fail;
}
/* The second argument may be flags. */
if (argc >= 2 && strchr(mexp->argv[1], 'f') != NULL) {
use_fp = 1;
prec = 2;
}
/* The third argument may be precision. */
if (argc >= 3) {
prec = strtonum(mexp->argv[2], INT_MIN, INT_MAX, &errstr);
if (errstr != NULL) {
format_log (ft, "expression precision %s: %s", errstr,
mexp->argv[2]);
goto fail;
}
}
if (format_choose(ft, copy, &left, &right, 1) != 0) {
format_log(ft, "expression syntax error");
goto fail;
}
mleft = strtod(left, &endch);
if (*endch != '\0') {
format_log(ft, "expression left side is invalid: %s", left);
goto fail;
}
mright = strtod(right, &endch);
if (*endch != '\0') {
format_log(ft, "expression right side is invalid: %s", right);
goto fail;
}
if (!use_fp) {
mleft = (long long)mleft;
mright = (long long)mright;
}
format_log(ft, "expression left side is: %.*f", prec, mleft);
format_log(ft, "expression right side is: %.*f", prec, mright);
switch (operator) {
case ADD:
result = mleft + mright;
break;
case SUBTRACT:
result = mleft - mright;
break;
case MULTIPLY:
result = mleft * mright;
break;
case DIVIDE:
result = mleft / mright;
break;
case MODULUS:
result = fmod(mleft, mright);
break;
}
if (use_fp)
xasprintf(&value, "%.*f", prec, result);
else
xasprintf(&value, "%.*f", prec, (double)(long long)result);
format_log(ft, "expression result is %s", value);
free(right);
free(left);
return value;
fail:
free(right);
free(left);
return (NULL);
}
/* Replace a key. */ /* Replace a key. */
static int static int
format_replace(struct format_tree *ft, const char *key, size_t keylen, format_replace(struct format_tree *ft, const char *key, size_t keylen,
@ -1811,7 +1913,7 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
size_t valuelen; size_t valuelen;
int modifiers = 0, limit = 0, width = 0, j; int modifiers = 0, limit = 0, width = 0, j;
struct format_modifier *list, *fm, *cmp = NULL, *search = NULL; struct format_modifier *list, *fm, *cmp = NULL, *search = NULL;
struct format_modifier **sub = NULL; struct format_modifier **sub = NULL, *mexp = NULL;
u_int i, count, nsub = 0; u_int i, count, nsub = 0;
/* Make a copy of the key. */ /* Make a copy of the key. */
@ -1863,6 +1965,11 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
if (errptr != NULL) if (errptr != NULL)
width = 0; width = 0;
break; break;
case 'e':
if (fm->argc < 1 || fm->argc > 3)
break;
mexp = fm;
break;
case 'l': case 'l':
modifiers |= FORMAT_LITERAL; modifiers |= FORMAT_LITERAL;
break; break;
@ -2039,6 +2146,10 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
free(condition); free(condition);
free(found); free(found);
} else if (mexp != NULL) {
value = format_replace_expression(mexp, ft, copy);
if (value == NULL)
value = xstrdup("");
} else { } else {
/* Neither: look up directly. */ /* Neither: look up directly. */
value = format_find(ft, copy, modifiers); value = format_find(ft, copy, modifiers);

34
tmux.1
View File

@ -4107,7 +4107,7 @@ specifies an
.Xr fnmatch 3 .Xr fnmatch 3
or regular expression comparison. or regular expression comparison.
The first argument is the pattern and the second the string to compare. The first argument is the pattern and the second the string to compare.
An optional third argument specifies flags: An optional argument specifies flags:
.Ql r .Ql r
means the pattern is a regular expression instead of the default means the pattern is a regular expression instead of the default
.Xr fnmatch 3 .Xr fnmatch 3
@ -4134,6 +4134,38 @@ ignores case.
For example: For example:
.Ql #{C/r:^Start} .Ql #{C/r:^Start}
.Pp .Pp
Numeric operators may be performed by prefixing two comma-separated alternatives with an
.Ql e
and an operator.
An optional
.Ql f
flag may be given after the operator to use floating point numbers, otherwise integers are used.
This may be followed by a number giving the number of decimal places to use for the result.
The available operators are:
addition
.Ql + ,
subtraction
.Ql - ,
multiplication
.Ql * ,
division
.Ql / ,
and modulus
.Ql m
or
.Ql %
(note that
.Ql %
must be escaped as
.Ql %%
in formats which are also expanded by
.Xr strftime 3 ) .
For example,
.Ql #{e|*|f|4:5.5,3}
multiplies 5.5 by 3 for a result with four decimal places and
.Ql #{e|%%:7,3}
returns the modulus of 7 and 3.
.Pp
A limit may be placed on the length of the resultant string by prefixing it A limit may be placed on the length of the resultant string by prefixing it
by an by an
.Ql = , .Ql = ,

1
tmux.h
View File

@ -1824,6 +1824,7 @@ char *paste_make_sample(struct paste_buffer *);
#define FORMAT_PANE 0x80000000U #define FORMAT_PANE 0x80000000U
#define FORMAT_WINDOW 0x40000000U #define FORMAT_WINDOW 0x40000000U
struct format_tree; struct format_tree;
struct format_modifier;
const char *format_skip(const char *, const char *); const char *format_skip(const char *, const char *);
int format_true(const char *); int format_true(const char *);
struct format_tree *format_create(struct client *, struct cmdq_item *, int, struct format_tree *format_create(struct client *, struct cmdq_item *, int,