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
# Look for libm
AC_SEARCH_LIBS(sqrt, m)
# Look for clock_gettime. Must come before event_init.
AC_SEARCH_LIBS(clock_gettime, rt)

117
format.c
View File

@ -23,6 +23,7 @@
#include <errno.h>
#include <fnmatch.h>
#include <libgen.h>
#include <math.h>
#include <regex.h>
#include <stdarg.h>
#include <stdlib.h>
@ -49,7 +50,6 @@ static void format_add_tv(struct format_tree *, const char *,
struct timeval *);
static int format_replace(struct format_tree *, const char *, size_t,
char **, size_t *, size_t *);
static void format_defaults_session(struct format_tree *,
struct session *);
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. */
if (strchr("mCs=p", cp[0]) == NULL)
if (strchr("mCs=pe", cp[0]) == NULL)
break;
c = cp[0];
@ -1799,6 +1799,108 @@ format_loop_panes(struct format_tree *ft, const char *fmt)
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. */
static int
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;
int modifiers = 0, limit = 0, width = 0, j;
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;
/* 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)
width = 0;
break;
case 'e':
if (fm->argc < 1 || fm->argc > 3)
break;
mexp = fm;
break;
case 'l':
modifiers |= FORMAT_LITERAL;
break;
@ -2039,6 +2146,10 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
free(condition);
free(found);
} else if (mexp != NULL) {
value = format_replace_expression(mexp, ft, copy);
if (value == NULL)
value = xstrdup("");
} else {
/* Neither: look up directly. */
value = format_find(ft, copy, modifiers);

34
tmux.1
View File

@ -4107,7 +4107,7 @@ specifies an
.Xr fnmatch 3
or regular expression comparison.
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
means the pattern is a regular expression instead of the default
.Xr fnmatch 3
@ -4134,6 +4134,38 @@ ignores case.
For example:
.Ql #{C/r:^Start}
.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
by an
.Ql = ,

1
tmux.h
View File

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