mirror of
https://github.com/tmux/tmux.git
synced 2025-09-01 20:57:00 +00:00
Extend the modifiers allowed before formats: as well as the existing
#{=10:...} length limit, add #{t:...} to convert a time_t format to a string, #{b:...} for basename and #{d:...} for dirname. Remove all the foo_string time formats as they can now be replaced by "t:", for example #{window_activity_string} becomes #{t:window_activity}.
This commit is contained in:
243
format.c
243
format.c
@ -21,6 +21,7 @@
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
#include <netdb.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
@ -52,7 +53,9 @@ void format_cb_current_command(struct format_tree *, struct format_entry *);
|
||||
void format_cb_history_bytes(struct format_tree *, struct format_entry *);
|
||||
void format_cb_pane_tabs(struct format_tree *, struct format_entry *);
|
||||
|
||||
char *format_find(struct format_tree *, const char *, int);
|
||||
void format_add_cb(struct format_tree *, const char *, format_cb);
|
||||
void format_add_tv(struct format_tree *, const char *, struct timeval *);
|
||||
int format_replace(struct format_tree *, const char *, size_t, char **,
|
||||
size_t *, size_t *);
|
||||
char *format_time_string(time_t);
|
||||
@ -90,10 +93,16 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2)
|
||||
return (strcmp(fj1->cmd, fj2->cmd));
|
||||
}
|
||||
|
||||
/* Format modifiers. */
|
||||
#define FORMAT_TIMESTRING 0x1
|
||||
#define FORMAT_BASENAME 0x2
|
||||
#define FORMAT_DIRNAME 0x4
|
||||
|
||||
/* Entry in format tree. */
|
||||
struct format_entry {
|
||||
char *key;
|
||||
char *value;
|
||||
time_t t;
|
||||
format_cb cb;
|
||||
RB_ENTRY(format_entry) entry;
|
||||
};
|
||||
@ -503,12 +512,37 @@ format_add(struct format_tree *ft, const char *key, const char *fmt, ...)
|
||||
}
|
||||
|
||||
fe->cb = NULL;
|
||||
fe->t = 0;
|
||||
|
||||
va_start(ap, fmt);
|
||||
xvasprintf(&fe->value, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/* Add a key and time. */
|
||||
void
|
||||
format_add_tv(struct format_tree *ft, const char *key, struct timeval *tv)
|
||||
{
|
||||
struct format_entry *fe;
|
||||
struct format_entry *fe_now;
|
||||
|
||||
fe = xmalloc(sizeof *fe);
|
||||
fe->key = xstrdup(key);
|
||||
|
||||
fe_now = RB_INSERT(format_entry_tree, &ft->tree, fe);
|
||||
if (fe_now != NULL) {
|
||||
free(fe->key);
|
||||
free(fe);
|
||||
free(fe_now->value);
|
||||
fe = fe_now;
|
||||
}
|
||||
|
||||
fe->cb = NULL;
|
||||
fe->t = tv->tv_sec;
|
||||
|
||||
fe->value = NULL;
|
||||
}
|
||||
|
||||
/* Add a key and function. */
|
||||
void
|
||||
format_add_cb(struct format_tree *ft, const char *key, format_cb cb)
|
||||
@ -528,57 +562,99 @@ format_add_cb(struct format_tree *ft, const char *key, format_cb cb)
|
||||
}
|
||||
|
||||
fe->cb = cb;
|
||||
fe->t = 0;
|
||||
|
||||
fe->value = NULL;
|
||||
}
|
||||
|
||||
/* Find a format entry. */
|
||||
const char *
|
||||
format_find(struct format_tree *ft, const char *key)
|
||||
char *
|
||||
format_find(struct format_tree *ft, const char *key, int modifiers)
|
||||
{
|
||||
struct format_entry *fe, fe_find;
|
||||
struct options_entry *o;
|
||||
struct environ_entry *envent;
|
||||
static char s[16];
|
||||
static char s[64];
|
||||
const char *found;
|
||||
char *copy, *saved;
|
||||
|
||||
o = options_find(&global_options, key);
|
||||
if (o == NULL && ft->w != NULL)
|
||||
o = options_find(&ft->w->options, key);
|
||||
if (o == NULL)
|
||||
o = options_find(&global_w_options, key);
|
||||
if (o == NULL && ft->s != NULL)
|
||||
o = options_find(&ft->s->options, key);
|
||||
if (o == NULL)
|
||||
o = options_find(&global_s_options, key);
|
||||
if (o != NULL) {
|
||||
switch (o->type) {
|
||||
case OPTIONS_STRING:
|
||||
return (o->str);
|
||||
case OPTIONS_NUMBER:
|
||||
xsnprintf(s, sizeof s, "%lld", o->num);
|
||||
return (s);
|
||||
case OPTIONS_STYLE:
|
||||
return (style_tostring(&o->style));
|
||||
found = NULL;
|
||||
|
||||
if (~modifiers & FORMAT_TIMESTRING) {
|
||||
o = options_find(&global_options, key);
|
||||
if (o == NULL && ft->w != NULL)
|
||||
o = options_find(&ft->w->options, key);
|
||||
if (o == NULL)
|
||||
o = options_find(&global_w_options, key);
|
||||
if (o == NULL && ft->s != NULL)
|
||||
o = options_find(&ft->s->options, key);
|
||||
if (o == NULL)
|
||||
o = options_find(&global_s_options, key);
|
||||
if (o != NULL) {
|
||||
switch (o->type) {
|
||||
case OPTIONS_STRING:
|
||||
found = o->str;
|
||||
goto found;
|
||||
case OPTIONS_NUMBER:
|
||||
xsnprintf(s, sizeof s, "%lld", o->num);
|
||||
found = s;
|
||||
goto found;
|
||||
case OPTIONS_STYLE:
|
||||
found = style_tostring(&o->style);
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fe_find.key = (char *) key;
|
||||
fe = RB_FIND(format_entry_tree, &ft->tree, &fe_find);
|
||||
if (fe != NULL) {
|
||||
if (modifiers & FORMAT_TIMESTRING) {
|
||||
if (fe->t == 0)
|
||||
return (NULL);
|
||||
ctime_r(&fe->t, s);
|
||||
s[strcspn(s, "\n")] = '\0';
|
||||
found = s;
|
||||
goto found;
|
||||
}
|
||||
if (fe->t != 0) {
|
||||
xsnprintf(s, sizeof s, "%lld", (long long)fe->t);
|
||||
found = s;
|
||||
goto found;
|
||||
}
|
||||
if (fe->value == NULL && fe->cb != NULL)
|
||||
fe->cb(ft, fe);
|
||||
return (fe->value);
|
||||
found = fe->value;
|
||||
goto found;
|
||||
}
|
||||
|
||||
envent = NULL;
|
||||
if (ft->s != NULL)
|
||||
envent = environ_find(&ft->s->environ, key);
|
||||
if (envent == NULL)
|
||||
envent = environ_find(&global_environ, key);
|
||||
if (envent != NULL)
|
||||
return (envent->value);
|
||||
if (~modifiers & FORMAT_TIMESTRING) {
|
||||
envent = NULL;
|
||||
if (ft->s != NULL)
|
||||
envent = environ_find(&ft->s->environ, key);
|
||||
if (envent == NULL)
|
||||
envent = environ_find(&global_environ, key);
|
||||
if (envent != NULL) {
|
||||
found = envent->value;
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
|
||||
found:
|
||||
copy = xstrdup(found);
|
||||
if (modifiers & FORMAT_BASENAME) {
|
||||
saved = copy;
|
||||
copy = xstrdup(basename(saved));
|
||||
free(saved);
|
||||
}
|
||||
if (modifiers & FORMAT_DIRNAME) {
|
||||
saved = copy;
|
||||
copy = xstrdup(dirname(saved));
|
||||
free(saved);
|
||||
}
|
||||
return (copy);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -589,10 +665,10 @@ int
|
||||
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, *saved, *trimmed;
|
||||
const char *value;
|
||||
char *copy, *copy0, *endptr, *ptr, *saved, *trimmed, *value;
|
||||
size_t valuelen;
|
||||
u_long limit = 0;
|
||||
int modifiers = 0;
|
||||
|
||||
/* Make a copy of the key. */
|
||||
copy0 = copy = xmalloc(keylen + 1);
|
||||
@ -600,24 +676,34 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
|
||||
copy[keylen] = '\0';
|
||||
|
||||
/* Is there a length limit or whatnot? */
|
||||
if (!isalpha((u_char) *copy) && *copy != '@' && *copy != '?') {
|
||||
while (*copy != ':' && *copy != '\0') {
|
||||
switch (*copy) {
|
||||
case '=':
|
||||
errno = 0;
|
||||
limit = strtoul(copy + 1, &endptr, 10);
|
||||
if (errno == ERANGE && limit == ULONG_MAX)
|
||||
goto fail;
|
||||
copy = endptr;
|
||||
break;
|
||||
default:
|
||||
copy++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (*copy != ':')
|
||||
goto fail;
|
||||
copy++;
|
||||
switch (copy[0]) {
|
||||
case '=':
|
||||
errno = 0;
|
||||
limit = strtoul(copy + 1, &endptr, 10);
|
||||
if (errno == ERANGE && limit == ULONG_MAX)
|
||||
break;
|
||||
if (*endptr != ':')
|
||||
break;
|
||||
copy = endptr + 1;
|
||||
break;
|
||||
case 'b':
|
||||
if (copy[1] != ':')
|
||||
break;
|
||||
modifiers |= FORMAT_BASENAME;
|
||||
copy += 2;
|
||||
break;
|
||||
case 'd':
|
||||
if (copy[1] != ':')
|
||||
break;
|
||||
modifiers |= FORMAT_DIRNAME;
|
||||
copy += 2;
|
||||
break;
|
||||
case 't':
|
||||
if (copy[1] != ':')
|
||||
break;
|
||||
modifiers |= FORMAT_TIMESTRING;
|
||||
copy += 2;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -630,7 +716,7 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
|
||||
goto fail;
|
||||
*ptr = '\0';
|
||||
|
||||
value = format_find(ft, copy + 1);
|
||||
value = saved = format_find(ft, copy + 1, modifiers);
|
||||
if (value != NULL && *value != '\0' &&
|
||||
(value[0] != '0' || value[1] != '\0')) {
|
||||
value = ptr + 1;
|
||||
@ -644,13 +730,13 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
|
||||
goto fail;
|
||||
value = ptr + 1;
|
||||
}
|
||||
saved = format_expand(ft, value);
|
||||
value = saved;
|
||||
value = format_expand(ft, value);
|
||||
free(saved);
|
||||
saved = value;
|
||||
} else {
|
||||
value = format_find(ft, copy);
|
||||
saved = value = format_find(ft, copy, modifiers);
|
||||
if (value == NULL)
|
||||
value = "";
|
||||
saved = NULL;
|
||||
saved = value = xstrdup("");
|
||||
}
|
||||
|
||||
/* Truncate the value if needed. */
|
||||
@ -820,18 +906,6 @@ format_expand(struct format_tree *ft, const char *fmt)
|
||||
return (buf);
|
||||
}
|
||||
|
||||
/* Get time as a string. */
|
||||
char *
|
||||
format_time_string(time_t t)
|
||||
{
|
||||
char *tim;
|
||||
|
||||
tim = ctime(&t);
|
||||
*strchr(tim, '\n') = '\0';
|
||||
|
||||
return (tim);
|
||||
}
|
||||
|
||||
/* Set defaults for any of arguments that are not NULL. */
|
||||
void
|
||||
format_defaults(struct format_tree *ft, struct client *c, struct session *s,
|
||||
@ -859,7 +933,6 @@ void
|
||||
format_defaults_session(struct format_tree *ft, struct session *s)
|
||||
{
|
||||
struct session_group *sg;
|
||||
time_t t;
|
||||
|
||||
ft->s = s;
|
||||
|
||||
@ -874,20 +947,9 @@ format_defaults_session(struct format_tree *ft, struct session *s)
|
||||
if (sg != NULL)
|
||||
format_add(ft, "session_group", "%u", session_group_index(sg));
|
||||
|
||||
t = s->creation_time.tv_sec;
|
||||
format_add(ft, "session_created", "%lld", (long long) t);
|
||||
format_add(ft, "session_created_string", "%s", format_time_string(t));
|
||||
|
||||
t = s->last_attached_time.tv_sec;
|
||||
if (t != 0) { /* zero if never attached */
|
||||
format_add(ft, "session_last_attached", "%lld", (long long) t);
|
||||
format_add(ft, "session_last_attached_string", "%s",
|
||||
format_time_string(t));
|
||||
}
|
||||
|
||||
t = s->activity_time.tv_sec;
|
||||
format_add(ft, "session_activity", "%lld", (long long) t);
|
||||
format_add(ft, "session_activity_string", "%s", format_time_string(t));
|
||||
format_add_tv(ft, "session_created", &s->creation_time);
|
||||
format_add_tv(ft, "session_last_attached", &s->last_attached_time);
|
||||
format_add_tv(ft, "session_activity", &s->activity_time);
|
||||
|
||||
format_add(ft, "session_attached", "%u", s->attached);
|
||||
format_add(ft, "session_many_attached", "%d", s->attached > 1);
|
||||
@ -900,7 +962,6 @@ void
|
||||
format_defaults_client(struct format_tree *ft, struct client *c)
|
||||
{
|
||||
struct session *s;
|
||||
time_t t;
|
||||
|
||||
if (ft->s == NULL)
|
||||
ft->s = c->session;
|
||||
@ -915,13 +976,8 @@ format_defaults_client(struct format_tree *ft, struct client *c)
|
||||
format_add(ft, "client_control_mode", "%d",
|
||||
!!(c->flags & CLIENT_CONTROL));
|
||||
|
||||
t = c->creation_time.tv_sec;
|
||||
format_add(ft, "client_created", "%lld", (long long) t);
|
||||
format_add(ft, "client_created_string", "%s", format_time_string(t));
|
||||
|
||||
t = c->activity_time.tv_sec;
|
||||
format_add(ft, "client_activity", "%lld", (long long) t);
|
||||
format_add(ft, "client_activity_string", "%s", format_time_string(t));
|
||||
format_add_tv(ft, "client_created", &c->creation_time);
|
||||
format_add_tv(ft, "client_activity", &c->activity_time);
|
||||
|
||||
if (strcmp(c->keytable->name, "root") == 0)
|
||||
format_add(ft, "client_prefix", "%d", 0);
|
||||
@ -951,14 +1007,9 @@ format_defaults_client(struct format_tree *ft, struct client *c)
|
||||
void
|
||||
format_defaults_window(struct format_tree *ft, struct window *w)
|
||||
{
|
||||
time_t t;
|
||||
|
||||
ft->w = w;
|
||||
|
||||
t = w->activity_time.tv_sec;
|
||||
format_add(ft, "window_activity", "%lld", (long long) t);
|
||||
format_add(ft, "window_activity_string", "%s", format_time_string(t));
|
||||
|
||||
format_add_tv(ft, "window_activity", &w->activity_time);
|
||||
format_add(ft, "window_id", "@%u", w->id);
|
||||
format_add(ft, "window_name", "%s", w->name);
|
||||
format_add(ft, "window_width", "%u", w->sx);
|
||||
|
Reference in New Issue
Block a user