-/* $OpenBSD: format.c,v 1.86 2015/10/25 08:59:26 nicm Exp $ */
+/* $OpenBSD: format.c,v 1.87 2015/10/25 22:29:17 nicm Exp $ */
/*
* Copyright (c) 2011 Nicholas Marriott <nicm@users.sourceforge.net>
#include <ctype.h>
#include <errno.h>
+#include <libgen.h>
#include <netdb.h>
#include <stdarg.h>
#include <stdlib.h>
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);
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;
};
}
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)
}
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];
-
- 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));
+ static char s[64];
+ const char *found;
+ char *copy, *saved;
+
+ 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);
}
/*
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);
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;
}
/*
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;
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. */
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,
format_defaults_session(struct format_tree *ft, struct session *s)
{
struct session_group *sg;
- time_t t;
ft->s = 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);
format_defaults_client(struct format_tree *ft, struct client *c)
{
struct session *s;
- time_t t;
if (ft->s == NULL)
ft->s = c->session;
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);
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);
-.\" $OpenBSD: tmux.1,v 1.452 2015/10/23 16:02:21 nicm Exp $
+.\" $OpenBSD: tmux.1,v 1.453 2015/10/25 22:29:17 nicm Exp $
.\"
.\" Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
.\"
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: October 23 2015 $
+.Dd $Mdocdate: October 25 2015 $
.Dt TMUX 1
.Os
.Sh NAME
is enabled, or
.Ql no
if not.
+.Pp
A limit may be placed on the length of the resultant string by prefixing it
by an
.Ql = ,
a number and a colon, so
.Ql #{=10:pane_title}
will include at most the first 10 characters of the pane title.
+Prefixing a time variable with
+.Ql t:
+will convert it to a string, so if
+.Ql #{window_activity}
+gives
+.Ql 1445765102,
+.Ql #{t:window_activity}
+gives
+.Ql Sun Oct 25 09:25:02 2015 .
+The
+.Ql b:
+and
+.Ql d:
+prefixes are
+.Xr basename 3
+and
+.Xr dirname 3
+of the variable respectively.
.Pp
In addition, the first line of a shell command's output may be inserted using
.Ql #() .
.It Li "buffer_sample" Ta "" Ta "Sample of start of buffer"
.It Li "buffer_size" Ta "" Ta "Size of the specified buffer in bytes"
.It Li "client_activity" Ta "" Ta "Integer time client last had activity"
-.It Li "client_activity_string" Ta "" Ta "String time client last had activity"
.It Li "client_created" Ta "" Ta "Integer time client created"
-.It Li "client_created_string" Ta "" Ta "String time client created"
.It Li "client_control_mode" Ta "" Ta "1 if client is in control mode"
.It Li "client_height" Ta "" Ta "Height of client"
.It Li "client_key_table" Ta "" Ta "Current key table"
.It Li "session_alerts" Ta "" Ta "List of window indexes with alerts"
.It Li "session_attached" Ta "" Ta "Number of clients session is attached to"
.It Li "session_activity" Ta "" Ta "Integer time of session last activity"
-.It Li "session_activity_string" Ta "" Ta "String time of session last activity"
.It Li "session_created" Ta "" Ta "Integer time session created"
-.It Li "session_created_string" Ta "" Ta "String time session created"
.It Li "session_last_attached" Ta "" Ta "Integer time session last attached"
-.It Li "session_last_attached_string" Ta "" Ta "String time session last attached"
.It Li "session_group" Ta "" Ta "Number of session group"
.It Li "session_grouped" Ta "" Ta "1 if session in a group"
.It Li "session_height" Ta "" Ta "Height of session"
.It Li "session_width" Ta "" Ta "Width of session"
.It Li "session_windows" Ta "" Ta "Number of windows in session"
.It Li "window_activity" Ta "" Ta "Integer time of window last activity"
-.It Li "window_activity_string" Ta "" Ta "String time of window last activity"
.It Li "window_active" Ta "" Ta "1 if window active"
-.It Li "window_activity_flag" Ta "" Ta "1 if window has activity alert"
.It Li "window_bell_flag" Ta "" Ta "1 if window has bell"
.It Li "window_find_matches" Ta "" Ta "Matched data from the find-window"
.It Li "window_flags" Ta "#F" Ta "Window flags"