mirror of
https://github.com/tmux/tmux.git
synced 2025-01-05 23:38:48 +00:00
Add some number operators for formats, from Tyler Culp.
This commit is contained in:
parent
2991f4aad0
commit
c820585dd0
4
Makefile
4
Makefile
@ -130,7 +130,7 @@ CDIAGFLAGS+= -Wundef -Wbad-function-cast -Winline -Wcast-align
|
||||
|
||||
CFLAGS += -I${.CURDIR}
|
||||
|
||||
LDADD= -lutil -lcurses -levent
|
||||
DPADD= ${LIBUTIL} ${LIBCURSES} ${LIBEVENT}
|
||||
LDADD= -lutil -lcurses -levent -lm
|
||||
DPADD= ${LIBUTIL} ${LIBCURSES} ${LIBEVENT} ${LIBM}
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
117
format.c
117
format.c
@ -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 *);
|
||||
@ -1528,7 +1528,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];
|
||||
|
||||
@ -1784,6 +1784,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,
|
||||
@ -1796,7 +1898,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. */
|
||||
@ -1848,6 +1950,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;
|
||||
@ -2024,6 +2131,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
34
tmux.1
@ -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
1
tmux.h
@ -1822,6 +1822,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,
|
||||
|
Loading…
Reference in New Issue
Block a user