aboutsummaryrefslogtreecommitdiff
path: root/format.c
diff options
context:
space:
mode:
Diffstat (limited to 'format.c')
-rw-r--r--format.c250
1 files changed, 189 insertions, 61 deletions
diff --git a/format.c b/format.c
index f0a5a3b1..3af7ae69 100644
--- a/format.c
+++ b/format.c
@@ -44,10 +44,7 @@ typedef void (*format_cb)(struct format_tree *, struct format_entry *);
static char *format_job_get(struct format_tree *, const char *);
static void format_job_timer(int, short, void *);
-static char *format_find(struct format_tree *, const char *, int);
static void format_add_cb(struct format_tree *, const char *, format_cb);
-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 *,
@@ -100,6 +97,7 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2)
#define FORMAT_SESSIONS 0x80
#define FORMAT_WINDOWS 0x100
#define FORMAT_PANES 0x200
+#define FORMAT_PRETTY 0x400
/* Limit on recursion. */
#define FORMAT_LOOP_LIMIT 10
@@ -123,8 +121,8 @@ struct format_tree {
struct cmdq_item *item;
struct client *client;
- u_int tag;
int flags;
+ u_int tag;
time_t time;
u_int loop;
@@ -728,7 +726,7 @@ format_cb_current_command(struct format_tree *ft, struct format_entry *fe)
if (wp == NULL || wp->shell == NULL)
return;
- cmd = get_proc_name(wp->fd, wp->tty);
+ cmd = osdep_get_name(wp->fd, wp->tty);
if (cmd == NULL || *cmd == '\0') {
free(cmd);
cmd = cmd_stringify_argv(wp->argc, wp->argv);
@@ -751,7 +749,7 @@ format_cb_current_path(struct format_tree *ft, struct format_entry *fe)
if (wp == NULL)
return;
- cwd = get_proc_cwd(wp->fd);
+ cwd = osdep_get_cwd(wp->fd);
if (cwd != NULL)
fe->value = xstrdup(cwd);
}
@@ -1259,7 +1257,7 @@ format_add(struct format_tree *ft, const char *key, const char *fmt, ...)
}
/* Add a key and time. */
-static void
+void
format_add_tv(struct format_tree *ft, const char *key, struct timeval *tv)
{
struct format_entry *fe, *fe_now;
@@ -1322,49 +1320,87 @@ format_quote(const char *s)
return (out);
}
+/* Make a prettier time. */
+static char *
+format_pretty_time(time_t t)
+{
+ struct tm now_tm, tm;
+ time_t now, age;
+ char s[6];
+ int m;
+
+ time(&now);
+ if (now < t)
+ now = t;
+ age = now - t;
+
+ localtime_r(&now, &now_tm);
+ localtime_r(&t, &tm);
+
+ /* Last 24 hours. */
+ if (age < 24 * 3600) {
+ strftime(s, sizeof s, "%H:%M", &tm);
+ return (xstrdup(s));
+ }
+
+ /* This month or last 28 days. */
+ if ((tm.tm_year == now_tm.tm_year && tm.tm_mon == now_tm.tm_mon) ||
+ age < 28 * 24 * 3600) {
+ strftime(s, sizeof s, "%a%d", &tm);
+ return (xstrdup(s));
+ }
+
+ /* Last 12 months. */
+ if (now_tm.tm_mon == 0)
+ m = 11;
+ else
+ m = now_tm.tm_mon - 1;
+ if ((tm.tm_year == now_tm.tm_year && tm.tm_mon < now_tm.tm_mon) ||
+ (tm.tm_year == now_tm.tm_year - 1 && tm.tm_mon > now_tm.tm_mon)) {
+ strftime(s, sizeof s, "%d%b", &tm);
+ return (xstrdup(s));
+ }
+
+ /* Older than that. */
+ strftime(s, sizeof s, "%h%y", &tm);
+ return (xstrdup(s));
+}
+
/* Find a format entry. */
static char *
-format_find(struct format_tree *ft, const char *key, int modifiers)
+format_find(struct format_tree *ft, const char *key, int modifiers,
+ const char *time_format)
{
struct format_entry *fe, fe_find;
struct environ_entry *envent;
- static char s[64];
struct options_entry *o;
int idx;
- char *found, *saved;
-
- if (~modifiers & FORMAT_TIMESTRING) {
- o = options_parse_get(global_options, key, &idx, 0);
- if (o == NULL && ft->wp != NULL)
- o = options_parse_get(ft->wp->options, key, &idx, 0);
- if (o == NULL && ft->w != NULL)
- o = options_parse_get(ft->w->options, key, &idx, 0);
- if (o == NULL)
- o = options_parse_get(global_w_options, key, &idx, 0);
- if (o == NULL && ft->s != NULL)
- o = options_parse_get(ft->s->options, key, &idx, 0);
- if (o == NULL)
- o = options_parse_get(global_s_options, key, &idx, 0);
- if (o != NULL) {
- found = options_tostring(o, idx, 1);
- goto found;
- }
+ char *found = NULL, *saved, s[512];
+ const char *errstr;
+ time_t t = 0;
+ struct tm tm;
+
+ o = options_parse_get(global_options, key, &idx, 0);
+ if (o == NULL && ft->wp != NULL)
+ o = options_parse_get(ft->wp->options, key, &idx, 0);
+ if (o == NULL && ft->w != NULL)
+ o = options_parse_get(ft->w->options, key, &idx, 0);
+ if (o == NULL)
+ o = options_parse_get(global_w_options, key, &idx, 0);
+ if (o == NULL && ft->s != NULL)
+ o = options_parse_get(ft->s->options, key, &idx, 0);
+ if (o == NULL)
+ o = options_parse_get(global_s_options, key, &idx, 0);
+ if (o != NULL) {
+ found = options_to_string(o, idx, 1);
+ goto found;
}
- found = NULL;
- fe_find.key = (char *) key;
+ 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 = xstrdup(s);
- goto found;
- }
if (fe->t != 0) {
- xasprintf(&found, "%lld", (long long)fe->t);
+ t = fe->t;
goto found;
}
if (fe->value == NULL && fe->cb != NULL)
@@ -1390,7 +1426,33 @@ format_find(struct format_tree *ft, const char *key, int modifiers)
return (NULL);
found:
- if (found == NULL)
+ if (modifiers & FORMAT_TIMESTRING) {
+ if (t == 0 && found != NULL) {
+ t = strtonum(found, 0, INT64_MAX, &errstr);
+ if (errstr != NULL)
+ t = 0;
+ free(found);
+ }
+ if (t == 0)
+ return (NULL);
+ if (modifiers & FORMAT_PRETTY)
+ found = format_pretty_time(t);
+ else {
+ if (time_format != NULL) {
+ localtime_r(&t, &tm);
+ strftime(s, sizeof s, time_format, &tm);
+ } else {
+ ctime_r(&t, s);
+ s[strcspn(s, "\n")] = '\0';
+ }
+ found = xstrdup(s);
+ }
+ return (found);
+ }
+
+ if (t != 0)
+ xasprintf(&found, "%lld", (long long)t);
+ else if (found == NULL)
return (NULL);
if (modifiers & FORMAT_BASENAME) {
saved = found;
@@ -1410,6 +1472,30 @@ found:
return (found);
}
+/* Remove escaped characters from string. */
+static char *
+format_strip(const char *s)
+{
+ char *out, *cp;
+ int brackets = 0;
+
+ cp = out = xmalloc(strlen(s) + 1);
+ for (; *s != '\0'; s++) {
+ if (*s == '#' && s[1] == '{')
+ brackets++;
+ if (*s == '#' && strchr(",#{}:", s[1]) != NULL) {
+ if (brackets != 0)
+ *cp++ = *s;
+ continue;
+ }
+ if (*s == '}')
+ brackets--;
+ *cp++ = *s;
+ }
+ *cp = '\0';
+ return (out);
+}
+
/* Skip until end. */
const char *
format_skip(const char *s, const char *end)
@@ -1419,7 +1505,7 @@ format_skip(const char *s, const char *end)
for (; *s != '\0'; s++) {
if (*s == '#' && s[1] == '{')
brackets++;
- if (*s == '#' && strchr(",#{}", s[1]) != NULL) {
+ if (*s == '#' && strchr(",#{}:", s[1]) != NULL) {
s++;
continue;
}
@@ -1527,12 +1613,12 @@ format_build_modifiers(struct format_tree *ft, const char **s, u_int *count)
*count = 0;
while (*cp != '\0' && *cp != ':') {
- /* Skip and separator character. */
+ /* Skip any separator character. */
if (*cp == ';')
cp++;
/* Check single character modifiers with no arguments. */
- if (strchr("lbdtqETSWP<>", cp[0]) != NULL &&
+ if (strchr("lbdqETSWP<>", cp[0]) != NULL &&
format_is_end(cp[1])) {
format_add_modifier(&list, count, cp, 1, NULL, 0);
cp++;
@@ -1553,7 +1639,7 @@ format_build_modifiers(struct format_tree *ft, const char **s, u_int *count)
}
/* Now try single character with arguments. */
- if (strchr("mCs=pe", cp[0]) == NULL)
+ if (strchr("mCst=pe", cp[0]) == NULL)
break;
c = cp[0];
@@ -1918,6 +2004,7 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
{
struct window_pane *wp = ft->wp;
const char *errptr, *copy, *cp, *marker = NULL;
+ const char *time_format = NULL;
char *copy0, *condition, *found, *new;
char *value, *left, *right;
size_t valuelen;
@@ -1978,7 +2065,7 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
case 'e':
if (fm->argc < 1 || fm->argc > 3)
break;
- mexp = fm;
+ mexp = fm;
break;
case 'l':
modifiers |= FORMAT_LITERAL;
@@ -1991,6 +2078,13 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
break;
case 't':
modifiers |= FORMAT_TIMESTRING;
+ if (fm->argc < 1)
+ break;
+ if (strchr(fm->argv[0], 'p') != NULL)
+ modifiers |= FORMAT_PRETTY;
+ else if (fm->argc >= 2 &&
+ strchr(fm->argv[0], 'f') != NULL)
+ time_format = format_strip(fm->argv[1]);
break;
case 'q':
modifiers |= FORMAT_QUOTE;
@@ -2117,7 +2211,7 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
condition = xstrndup(copy + 1, cp - (copy + 1));
format_log(ft, "condition is: %s", condition);
- found = format_find(ft, condition, modifiers);
+ found = format_find(ft, condition, modifiers, time_format);
if (found == NULL) {
/*
* If the condition not found, try to expand it. If
@@ -2162,7 +2256,7 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
value = xstrdup("");
} else {
/* Neither: look up directly. */
- value = format_find(ft, copy, modifiers);
+ value = format_find(ft, copy, modifiers, time_format);
if (value == NULL) {
format_log(ft, "format '%s' not found", copy);
value = xstrdup("");
@@ -2416,25 +2510,59 @@ format_single(struct cmdq_item *item, const char *fmt, struct client *c,
struct format_tree *ft;
char *expanded;
- if (item != NULL)
- ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
- else
- ft = format_create(NULL, item, FORMAT_NONE, 0);
- format_defaults(ft, c, s, wl, wp);
-
+ ft = format_create_defaults(item, c, s, wl, wp);
expanded = format_expand(ft, fmt);
format_free(ft);
return (expanded);
}
+/* Expand a single string using state. */
+char *
+format_single_from_state(struct cmdq_item *item, const char *fmt,
+ struct client *c, struct cmd_find_state *fs)
+{
+ return (format_single(item, fmt, c, fs->s, fs->wl, fs->wp));
+}
+
/* Expand a single string using target. */
char *
format_single_from_target(struct cmdq_item *item, const char *fmt)
{
- struct cmd_find_state *target = cmdq_get_target(item);
- struct client *tc = cmdq_get_target_client(item);
+ struct client *tc = cmdq_get_target_client(item);
+
+ return (format_single_from_state(item, fmt, tc, cmdq_get_target(item)));
+}
+
+/* Create and add defaults. */
+struct format_tree *
+format_create_defaults(struct cmdq_item *item, struct client *c,
+ struct session *s, struct winlink *wl, struct window_pane *wp)
+{
+ struct format_tree *ft;
- return (format_single(item, fmt, tc, target->s, target->wl, target->wp));
+ if (item != NULL)
+ ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
+ else
+ ft = format_create(NULL, item, FORMAT_NONE, 0);
+ format_defaults(ft, c, s, wl, wp);
+ return (ft);
+}
+
+/* Create and add defaults using state. */
+struct format_tree *
+format_create_from_state(struct cmdq_item *item, struct client *c,
+ struct cmd_find_state *fs)
+{
+ return (format_create_defaults(item, c, fs->s, fs->wl, fs->wp));
+}
+
+/* Create and add defaults using target. */
+struct format_tree *
+format_create_from_target(struct cmdq_item *item)
+{
+ struct client *tc = cmdq_get_target_client(item);
+
+ return (format_create_from_state(item, tc, cmdq_get_target(item)));
}
/* Set defaults for any of arguments that are not NULL. */
@@ -2453,7 +2581,7 @@ format_defaults(struct format_tree *ft, struct client *c, struct session *s,
else
log_debug("%s: s=none", __func__);
if (wl != NULL)
- log_debug("%s: wl=%u w=@%u", __func__, wl->idx, wl->window->id);
+ log_debug("%s: wl=%u", __func__, wl->idx);
else
log_debug("%s: wl=none", __func__);
if (wp != NULL)
@@ -2561,6 +2689,8 @@ format_defaults_client(struct format_tree *ft, struct client *c)
format_add(ft, "client_termname", "%s", c->term_name);
format_add(ft, "client_termfeatures", "%s",
tty_get_features(c->term_features));
+ if (c->term_type != NULL)
+ format_add(ft, "client_termtype", "%s", c->term_type);
format_add_tv(ft, "client_created", &c->creation_time);
format_add_tv(ft, "client_activity", &c->activity_time);
@@ -2579,11 +2709,11 @@ format_defaults_client(struct format_tree *ft, struct client *c)
format_add(ft, "client_utf8", "%d", 1);
else
format_add(ft, "client_utf8", "%d", 0);
-
if (c->flags & CLIENT_READONLY)
format_add(ft, "client_readonly", "%d", 1);
else
format_add(ft, "client_readonly", "%d", 0);
+ format_add(ft, "client_flags", "%s", server_client_get_flags(c));
s = c->session;
if (s != NULL)
@@ -2625,11 +2755,9 @@ format_defaults_winlink(struct format_tree *ft, struct winlink *wl)
u_int ox, oy, sx, sy;
if (ft->w == NULL)
- ft->w = wl->window;
+ format_defaults_window(ft, w);
ft->wl = wl;
- format_defaults_window(ft, w);
-
if (c != NULL) {
flag = tty_window_offset(&c->tty, &ox, &oy, &sx, &sy);
format_add(ft, "window_bigger", "%d", flag);
@@ -2689,7 +2817,7 @@ format_defaults_pane(struct format_tree *ft, struct window_pane *wp)
struct window_mode_entry *wme;
if (ft->w == NULL)
- ft->w = w;
+ format_defaults_window(ft, w);
ft->wp = wp;
format_add(ft, "history_size", "%u", gd->hsize);