Bug Summary

File:src/usr.bin/tmux/format.c
Warning:line 1126, column 12
Although the value stored to 's' is used in the enclosing expression, the value is never actually read from 's'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name format.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.bin/tmux/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.bin/tmux -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/tmux/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.bin/tmux/format.c
1/* $OpenBSD: format.c,v 1.299 2021/10/25 21:21:16 nicm Exp $ */
2
3/*
4 * Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/types.h>
20#include <sys/wait.h>
21
22#include <ctype.h>
23#include <errno(*__errno()).h>
24#include <fnmatch.h>
25#include <libgen.h>
26#include <math.h>
27#include <regex.h>
28#include <stdarg.h>
29#include <stdlib.h>
30#include <string.h>
31#include <time.h>
32#include <unistd.h>
33
34#include "tmux.h"
35
36/*
37 * Build a list of key-value pairs and use them to expand #{key} entries in a
38 * string.
39 */
40
41struct format_expand_state;
42
43static char *format_job_get(struct format_expand_state *, const char *);
44static char *format_expand1(struct format_expand_state *, const char *);
45static int format_replace(struct format_expand_state *, const char *,
46 size_t, char **, size_t *, size_t *);
47static void format_defaults_session(struct format_tree *,
48 struct session *);
49static void format_defaults_client(struct format_tree *, struct client *);
50static void format_defaults_winlink(struct format_tree *,
51 struct winlink *);
52
53/* Entry in format job tree. */
54struct format_job {
55 struct client *client;
56 u_int tag;
57 const char *cmd;
58 const char *expanded;
59
60 time_t last;
61 char *out;
62 int updated;
63
64 struct job *job;
65 int status;
66
67 RB_ENTRY(format_job)struct { struct format_job *rbe_left; struct format_job *rbe_right
; struct format_job *rbe_parent; int rbe_color; }
entry;
68};
69
70/* Format job tree. */
71static int format_job_cmp(struct format_job *, struct format_job *);
72static RB_HEAD(format_job_tree, format_job)struct format_job_tree { struct format_job *rbh_root; } format_jobs = RB_INITIALIZER(){ ((void *)0) };
73RB_GENERATE_STATIC(format_job_tree, format_job, entry, format_job_cmp)__attribute__((__unused__)) static void format_job_tree_RB_INSERT_COLOR
(struct format_job_tree *head, struct format_job *elm) { struct
format_job *parent, *gparent, *tmp; while ((parent = (elm)->
entry.rbe_parent) && (parent)->entry.rbe_color == 1
) { gparent = (parent)->entry.rbe_parent; if (parent == (gparent
)->entry.rbe_left) { tmp = (gparent)->entry.rbe_right; if
(tmp && (tmp)->entry.rbe_color == 1) { (tmp)->
entry.rbe_color = 0; do { (parent)->entry.rbe_color = 0; (
gparent)->entry.rbe_color = 1; } while (0); elm = gparent;
continue; } if ((parent)->entry.rbe_right == elm) { do { (
tmp) = (parent)->entry.rbe_right; if (((parent)->entry.
rbe_right = (tmp)->entry.rbe_left)) { ((tmp)->entry.rbe_left
)->entry.rbe_parent = (parent); } do {} while (0); if (((tmp
)->entry.rbe_parent = (parent)->entry.rbe_parent)) { if
((parent) == ((parent)->entry.rbe_parent)->entry.rbe_left
) ((parent)->entry.rbe_parent)->entry.rbe_left = (tmp);
else ((parent)->entry.rbe_parent)->entry.rbe_right = (
tmp); } else (head)->rbh_root = (tmp); (tmp)->entry.rbe_left
= (parent); (parent)->entry.rbe_parent = (tmp); do {} while
(0); if (((tmp)->entry.rbe_parent)) do {} while (0); } while
(0); tmp = parent; parent = elm; elm = tmp; } do { (parent)->
entry.rbe_color = 0; (gparent)->entry.rbe_color = 1; } while
(0); do { (tmp) = (gparent)->entry.rbe_left; if (((gparent
)->entry.rbe_left = (tmp)->entry.rbe_right)) { ((tmp)->
entry.rbe_right)->entry.rbe_parent = (gparent); } do {} while
(0); if (((tmp)->entry.rbe_parent = (gparent)->entry.rbe_parent
)) { if ((gparent) == ((gparent)->entry.rbe_parent)->entry
.rbe_left) ((gparent)->entry.rbe_parent)->entry.rbe_left
= (tmp); else ((gparent)->entry.rbe_parent)->entry.rbe_right
= (tmp); } else (head)->rbh_root = (tmp); (tmp)->entry
.rbe_right = (gparent); (gparent)->entry.rbe_parent = (tmp
); do {} while (0); if (((tmp)->entry.rbe_parent)) do {} while
(0); } while (0); } else { tmp = (gparent)->entry.rbe_left
; if (tmp && (tmp)->entry.rbe_color == 1) { (tmp)->
entry.rbe_color = 0; do { (parent)->entry.rbe_color = 0; (
gparent)->entry.rbe_color = 1; } while (0); elm = gparent;
continue; } if ((parent)->entry.rbe_left == elm) { do { (
tmp) = (parent)->entry.rbe_left; if (((parent)->entry.rbe_left
= (tmp)->entry.rbe_right)) { ((tmp)->entry.rbe_right)->
entry.rbe_parent = (parent); } do {} while (0); if (((tmp)->
entry.rbe_parent = (parent)->entry.rbe_parent)) { if ((parent
) == ((parent)->entry.rbe_parent)->entry.rbe_left) ((parent
)->entry.rbe_parent)->entry.rbe_left = (tmp); else ((parent
)->entry.rbe_parent)->entry.rbe_right = (tmp); } else (
head)->rbh_root = (tmp); (tmp)->entry.rbe_right = (parent
); (parent)->entry.rbe_parent = (tmp); do {} while (0); if
(((tmp)->entry.rbe_parent)) do {} while (0); } while (0);
tmp = parent; parent = elm; elm = tmp; } do { (parent)->entry
.rbe_color = 0; (gparent)->entry.rbe_color = 1; } while (0
); do { (tmp) = (gparent)->entry.rbe_right; if (((gparent)
->entry.rbe_right = (tmp)->entry.rbe_left)) { ((tmp)->
entry.rbe_left)->entry.rbe_parent = (gparent); } do {} while
(0); if (((tmp)->entry.rbe_parent = (gparent)->entry.rbe_parent
)) { if ((gparent) == ((gparent)->entry.rbe_parent)->entry
.rbe_left) ((gparent)->entry.rbe_parent)->entry.rbe_left
= (tmp); else ((gparent)->entry.rbe_parent)->entry.rbe_right
= (tmp); } else (head)->rbh_root = (tmp); (tmp)->entry
.rbe_left = (gparent); (gparent)->entry.rbe_parent = (tmp)
; do {} while (0); if (((tmp)->entry.rbe_parent)) do {} while
(0); } while (0); } } (head->rbh_root)->entry.rbe_color
= 0; } __attribute__((__unused__)) static void format_job_tree_RB_REMOVE_COLOR
(struct format_job_tree *head, struct format_job *parent, struct
format_job *elm) { struct format_job *tmp; while ((elm == ((
void *)0) || (elm)->entry.rbe_color == 0) && elm !=
(head)->rbh_root) { if ((parent)->entry.rbe_left == elm
) { tmp = (parent)->entry.rbe_right; if ((tmp)->entry.rbe_color
== 1) { do { (tmp)->entry.rbe_color = 0; (parent)->entry
.rbe_color = 1; } while (0); do { (tmp) = (parent)->entry.
rbe_right; if (((parent)->entry.rbe_right = (tmp)->entry
.rbe_left)) { ((tmp)->entry.rbe_left)->entry.rbe_parent
= (parent); } do {} while (0); if (((tmp)->entry.rbe_parent
= (parent)->entry.rbe_parent)) { if ((parent) == ((parent
)->entry.rbe_parent)->entry.rbe_left) ((parent)->entry
.rbe_parent)->entry.rbe_left = (tmp); else ((parent)->entry
.rbe_parent)->entry.rbe_right = (tmp); } else (head)->rbh_root
= (tmp); (tmp)->entry.rbe_left = (parent); (parent)->entry
.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent
)) do {} while (0); } while (0); tmp = (parent)->entry.rbe_right
; } if (((tmp)->entry.rbe_left == ((void *)0) || ((tmp)->
entry.rbe_left)->entry.rbe_color == 0) && ((tmp)->
entry.rbe_right == ((void *)0) || ((tmp)->entry.rbe_right)
->entry.rbe_color == 0)) { (tmp)->entry.rbe_color = 1; elm
= parent; parent = (elm)->entry.rbe_parent; } else { if (
(tmp)->entry.rbe_right == ((void *)0) || ((tmp)->entry.
rbe_right)->entry.rbe_color == 0) { struct format_job *oleft
; if ((oleft = (tmp)->entry.rbe_left)) (oleft)->entry.rbe_color
= 0; (tmp)->entry.rbe_color = 1; do { (oleft) = (tmp)->
entry.rbe_left; if (((tmp)->entry.rbe_left = (oleft)->entry
.rbe_right)) { ((oleft)->entry.rbe_right)->entry.rbe_parent
= (tmp); } do {} while (0); if (((oleft)->entry.rbe_parent
= (tmp)->entry.rbe_parent)) { if ((tmp) == ((tmp)->entry
.rbe_parent)->entry.rbe_left) ((tmp)->entry.rbe_parent)
->entry.rbe_left = (oleft); else ((tmp)->entry.rbe_parent
)->entry.rbe_right = (oleft); } else (head)->rbh_root =
(oleft); (oleft)->entry.rbe_right = (tmp); (tmp)->entry
.rbe_parent = (oleft); do {} while (0); if (((oleft)->entry
.rbe_parent)) do {} while (0); } while (0); tmp = (parent)->
entry.rbe_right; } (tmp)->entry.rbe_color = (parent)->entry
.rbe_color; (parent)->entry.rbe_color = 0; if ((tmp)->entry
.rbe_right) ((tmp)->entry.rbe_right)->entry.rbe_color =
0; do { (tmp) = (parent)->entry.rbe_right; if (((parent)->
entry.rbe_right = (tmp)->entry.rbe_left)) { ((tmp)->entry
.rbe_left)->entry.rbe_parent = (parent); } do {} while (0)
; if (((tmp)->entry.rbe_parent = (parent)->entry.rbe_parent
)) { if ((parent) == ((parent)->entry.rbe_parent)->entry
.rbe_left) ((parent)->entry.rbe_parent)->entry.rbe_left
= (tmp); else ((parent)->entry.rbe_parent)->entry.rbe_right
= (tmp); } else (head)->rbh_root = (tmp); (tmp)->entry
.rbe_left = (parent); (parent)->entry.rbe_parent = (tmp); do
{} while (0); if (((tmp)->entry.rbe_parent)) do {} while (
0); } while (0); elm = (head)->rbh_root; break; } } else {
tmp = (parent)->entry.rbe_left; if ((tmp)->entry.rbe_color
== 1) { do { (tmp)->entry.rbe_color = 0; (parent)->entry
.rbe_color = 1; } while (0); do { (tmp) = (parent)->entry.
rbe_left; if (((parent)->entry.rbe_left = (tmp)->entry.
rbe_right)) { ((tmp)->entry.rbe_right)->entry.rbe_parent
= (parent); } do {} while (0); if (((tmp)->entry.rbe_parent
= (parent)->entry.rbe_parent)) { if ((parent) == ((parent
)->entry.rbe_parent)->entry.rbe_left) ((parent)->entry
.rbe_parent)->entry.rbe_left = (tmp); else ((parent)->entry
.rbe_parent)->entry.rbe_right = (tmp); } else (head)->rbh_root
= (tmp); (tmp)->entry.rbe_right = (parent); (parent)->
entry.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry
.rbe_parent)) do {} while (0); } while (0); tmp = (parent)->
entry.rbe_left; } if (((tmp)->entry.rbe_left == ((void *)0
) || ((tmp)->entry.rbe_left)->entry.rbe_color == 0) &&
((tmp)->entry.rbe_right == ((void *)0) || ((tmp)->entry
.rbe_right)->entry.rbe_color == 0)) { (tmp)->entry.rbe_color
= 1; elm = parent; parent = (elm)->entry.rbe_parent; } else
{ if ((tmp)->entry.rbe_left == ((void *)0) || ((tmp)->
entry.rbe_left)->entry.rbe_color == 0) { struct format_job
*oright; if ((oright = (tmp)->entry.rbe_right)) (oright)->
entry.rbe_color = 0; (tmp)->entry.rbe_color = 1; do { (oright
) = (tmp)->entry.rbe_right; if (((tmp)->entry.rbe_right
= (oright)->entry.rbe_left)) { ((oright)->entry.rbe_left
)->entry.rbe_parent = (tmp); } do {} while (0); if (((oright
)->entry.rbe_parent = (tmp)->entry.rbe_parent)) { if ((
tmp) == ((tmp)->entry.rbe_parent)->entry.rbe_left) ((tmp
)->entry.rbe_parent)->entry.rbe_left = (oright); else (
(tmp)->entry.rbe_parent)->entry.rbe_right = (oright); }
else (head)->rbh_root = (oright); (oright)->entry.rbe_left
= (tmp); (tmp)->entry.rbe_parent = (oright); do {} while (
0); if (((oright)->entry.rbe_parent)) do {} while (0); } while
(0); tmp = (parent)->entry.rbe_left; } (tmp)->entry.rbe_color
= (parent)->entry.rbe_color; (parent)->entry.rbe_color
= 0; if ((tmp)->entry.rbe_left) ((tmp)->entry.rbe_left
)->entry.rbe_color = 0; do { (tmp) = (parent)->entry.rbe_left
; if (((parent)->entry.rbe_left = (tmp)->entry.rbe_right
)) { ((tmp)->entry.rbe_right)->entry.rbe_parent = (parent
); } do {} while (0); if (((tmp)->entry.rbe_parent = (parent
)->entry.rbe_parent)) { if ((parent) == ((parent)->entry
.rbe_parent)->entry.rbe_left) ((parent)->entry.rbe_parent
)->entry.rbe_left = (tmp); else ((parent)->entry.rbe_parent
)->entry.rbe_right = (tmp); } else (head)->rbh_root = (
tmp); (tmp)->entry.rbe_right = (parent); (parent)->entry
.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent
)) do {} while (0); } while (0); elm = (head)->rbh_root; break
; } } } if (elm) (elm)->entry.rbe_color = 0; } __attribute__
((__unused__)) static struct format_job * format_job_tree_RB_REMOVE
(struct format_job_tree *head, struct format_job *elm) { struct
format_job *child, *parent, *old = elm; int color; if ((elm)
->entry.rbe_left == ((void *)0)) child = (elm)->entry.rbe_right
; else if ((elm)->entry.rbe_right == ((void *)0)) child = (
elm)->entry.rbe_left; else { struct format_job *left; elm =
(elm)->entry.rbe_right; while ((left = (elm)->entry.rbe_left
)) elm = left; child = (elm)->entry.rbe_right; parent = (elm
)->entry.rbe_parent; color = (elm)->entry.rbe_color; if
(child) (child)->entry.rbe_parent = parent; if (parent) {
if ((parent)->entry.rbe_left == elm) (parent)->entry.rbe_left
= child; else (parent)->entry.rbe_right = child; do {} while
(0); } else (head)->rbh_root = child; if ((elm)->entry
.rbe_parent == old) parent = elm; (elm)->entry = (old)->
entry; if ((old)->entry.rbe_parent) { if (((old)->entry
.rbe_parent)->entry.rbe_left == old) ((old)->entry.rbe_parent
)->entry.rbe_left = elm; else ((old)->entry.rbe_parent)
->entry.rbe_right = elm; do {} while (0); } else (head)->
rbh_root = elm; ((old)->entry.rbe_left)->entry.rbe_parent
= elm; if ((old)->entry.rbe_right) ((old)->entry.rbe_right
)->entry.rbe_parent = elm; if (parent) { left = parent; do
{ do {} while (0); } while ((left = (left)->entry.rbe_parent
)); } goto color; } parent = (elm)->entry.rbe_parent; color
= (elm)->entry.rbe_color; if (child) (child)->entry.rbe_parent
= parent; if (parent) { if ((parent)->entry.rbe_left == elm
) (parent)->entry.rbe_left = child; else (parent)->entry
.rbe_right = child; do {} while (0); } else (head)->rbh_root
= child; color: if (color == 0) format_job_tree_RB_REMOVE_COLOR
(head, parent, child); return (old); } __attribute__((__unused__
)) static struct format_job * format_job_tree_RB_INSERT(struct
format_job_tree *head, struct format_job *elm) { struct format_job
*tmp; struct format_job *parent = ((void *)0); int comp = 0;
tmp = (head)->rbh_root; while (tmp) { parent = tmp; comp =
(format_job_cmp)(elm, parent); if (comp < 0) tmp = (tmp)->
entry.rbe_left; else if (comp > 0) tmp = (tmp)->entry.rbe_right
; else return (tmp); } do { (elm)->entry.rbe_parent = parent
; (elm)->entry.rbe_left = (elm)->entry.rbe_right = ((void
*)0); (elm)->entry.rbe_color = 1; } while (0); if (parent
!= ((void *)0)) { if (comp < 0) (parent)->entry.rbe_left
= elm; else (parent)->entry.rbe_right = elm; do {} while (
0); } else (head)->rbh_root = elm; format_job_tree_RB_INSERT_COLOR
(head, elm); return (((void *)0)); } __attribute__((__unused__
)) static struct format_job * format_job_tree_RB_FIND(struct format_job_tree
*head, struct format_job *elm) { struct format_job *tmp = (head
)->rbh_root; int comp; while (tmp) { comp = format_job_cmp
(elm, tmp); if (comp < 0) tmp = (tmp)->entry.rbe_left; else
if (comp > 0) tmp = (tmp)->entry.rbe_right; else return
(tmp); } return (((void *)0)); } __attribute__((__unused__))
static struct format_job * format_job_tree_RB_NFIND(struct format_job_tree
*head, struct format_job *elm) { struct format_job *tmp = (head
)->rbh_root; struct format_job *res = ((void *)0); int comp
; while (tmp) { comp = format_job_cmp(elm, tmp); if (comp <
0) { res = tmp; tmp = (tmp)->entry.rbe_left; } else if (comp
> 0) tmp = (tmp)->entry.rbe_right; else return (tmp); }
return (res); } __attribute__((__unused__)) static struct format_job
* format_job_tree_RB_NEXT(struct format_job *elm) { if ((elm
)->entry.rbe_right) { elm = (elm)->entry.rbe_right; while
((elm)->entry.rbe_left) elm = (elm)->entry.rbe_left; }
else { if ((elm)->entry.rbe_parent && (elm == ((elm
)->entry.rbe_parent)->entry.rbe_left)) elm = (elm)->
entry.rbe_parent; else { while ((elm)->entry.rbe_parent &&
(elm == ((elm)->entry.rbe_parent)->entry.rbe_right)) elm
= (elm)->entry.rbe_parent; elm = (elm)->entry.rbe_parent
; } } return (elm); } __attribute__((__unused__)) static struct
format_job * format_job_tree_RB_PREV(struct format_job *elm)
{ if ((elm)->entry.rbe_left) { elm = (elm)->entry.rbe_left
; while ((elm)->entry.rbe_right) elm = (elm)->entry.rbe_right
; } else { if ((elm)->entry.rbe_parent && (elm == (
(elm)->entry.rbe_parent)->entry.rbe_right)) elm = (elm)
->entry.rbe_parent; else { while ((elm)->entry.rbe_parent
&& (elm == ((elm)->entry.rbe_parent)->entry.rbe_left
)) elm = (elm)->entry.rbe_parent; elm = (elm)->entry.rbe_parent
; } } return (elm); } __attribute__((__unused__)) static struct
format_job * format_job_tree_RB_MINMAX(struct format_job_tree
*head, int val) { struct format_job *tmp = (head)->rbh_root
; struct format_job *parent = ((void *)0); while (tmp) { parent
= tmp; if (val < 0) tmp = (tmp)->entry.rbe_left; else tmp
= (tmp)->entry.rbe_right; } return (parent); }
;
74
75/* Format job tree comparison function. */
76static int
77format_job_cmp(struct format_job *fj1, struct format_job *fj2)
78{
79 if (fj1->tag < fj2->tag)
80 return (-1);
81 if (fj1->tag > fj2->tag)
82 return (1);
83 return (strcmp(fj1->cmd, fj2->cmd));
84}
85
86/* Format modifiers. */
87#define FORMAT_TIMESTRING0x1 0x1
88#define FORMAT_BASENAME0x2 0x2
89#define FORMAT_DIRNAME0x4 0x4
90#define FORMAT_QUOTE_SHELL0x8 0x8
91#define FORMAT_LITERAL0x10 0x10
92#define FORMAT_EXPAND0x20 0x20
93#define FORMAT_EXPANDTIME0x40 0x40
94#define FORMAT_SESSIONS0x80 0x80
95#define FORMAT_WINDOWS0x100 0x100
96#define FORMAT_PANES0x200 0x200
97#define FORMAT_PRETTY0x400 0x400
98#define FORMAT_LENGTH0x800 0x800
99#define FORMAT_WIDTH0x1000 0x1000
100#define FORMAT_QUOTE_STYLE0x2000 0x2000
101#define FORMAT_WINDOW_NAME0x4000 0x4000
102#define FORMAT_SESSION_NAME0x8000 0x8000
103#define FORMAT_CHARACTER0x10000 0x10000
104#define FORMAT_COLOUR0x20000 0x20000
105
106/* Limit on recursion. */
107#define FORMAT_LOOP_LIMIT100 100
108
109/* Format expand flags. */
110#define FORMAT_EXPAND_TIME0x1 0x1
111#define FORMAT_EXPAND_NOJOBS0x2 0x2
112
113/* Entry in format tree. */
114struct format_entry {
115 char *key;
116 char *value;
117 time_t time;
118 format_cb cb;
119 RB_ENTRY(format_entry)struct { struct format_entry *rbe_left; struct format_entry *
rbe_right; struct format_entry *rbe_parent; int rbe_color; }
entry;
120};
121
122/* Format type. */
123enum format_type {
124 FORMAT_TYPE_UNKNOWN,
125 FORMAT_TYPE_SESSION,
126 FORMAT_TYPE_WINDOW,
127 FORMAT_TYPE_PANE
128};
129
130struct format_tree {
131 enum format_type type;
132
133 struct client *c;
134 struct session *s;
135 struct winlink *wl;
136 struct window *w;
137 struct window_pane *wp;
138 struct paste_buffer *pb;
139
140 struct cmdq_item *item;
141 struct client *client;
142 int flags;
143 u_int tag;
144
145 struct mouse_event m;
146
147 RB_HEAD(format_entry_tree, format_entry)struct format_entry_tree { struct format_entry *rbh_root; } tree;
148};
149static int format_entry_cmp(struct format_entry *, struct format_entry *);
150RB_GENERATE_STATIC(format_entry_tree, format_entry, entry, format_entry_cmp)__attribute__((__unused__)) static void format_entry_tree_RB_INSERT_COLOR
(struct format_entry_tree *head, struct format_entry *elm) { struct
format_entry *parent, *gparent, *tmp; while ((parent = (elm)
->entry.rbe_parent) && (parent)->entry.rbe_color
== 1) { gparent = (parent)->entry.rbe_parent; if (parent ==
(gparent)->entry.rbe_left) { tmp = (gparent)->entry.rbe_right
; if (tmp && (tmp)->entry.rbe_color == 1) { (tmp)->
entry.rbe_color = 0; do { (parent)->entry.rbe_color = 0; (
gparent)->entry.rbe_color = 1; } while (0); elm = gparent;
continue; } if ((parent)->entry.rbe_right == elm) { do { (
tmp) = (parent)->entry.rbe_right; if (((parent)->entry.
rbe_right = (tmp)->entry.rbe_left)) { ((tmp)->entry.rbe_left
)->entry.rbe_parent = (parent); } do {} while (0); if (((tmp
)->entry.rbe_parent = (parent)->entry.rbe_parent)) { if
((parent) == ((parent)->entry.rbe_parent)->entry.rbe_left
) ((parent)->entry.rbe_parent)->entry.rbe_left = (tmp);
else ((parent)->entry.rbe_parent)->entry.rbe_right = (
tmp); } else (head)->rbh_root = (tmp); (tmp)->entry.rbe_left
= (parent); (parent)->entry.rbe_parent = (tmp); do {} while
(0); if (((tmp)->entry.rbe_parent)) do {} while (0); } while
(0); tmp = parent; parent = elm; elm = tmp; } do { (parent)->
entry.rbe_color = 0; (gparent)->entry.rbe_color = 1; } while
(0); do { (tmp) = (gparent)->entry.rbe_left; if (((gparent
)->entry.rbe_left = (tmp)->entry.rbe_right)) { ((tmp)->
entry.rbe_right)->entry.rbe_parent = (gparent); } do {} while
(0); if (((tmp)->entry.rbe_parent = (gparent)->entry.rbe_parent
)) { if ((gparent) == ((gparent)->entry.rbe_parent)->entry
.rbe_left) ((gparent)->entry.rbe_parent)->entry.rbe_left
= (tmp); else ((gparent)->entry.rbe_parent)->entry.rbe_right
= (tmp); } else (head)->rbh_root = (tmp); (tmp)->entry
.rbe_right = (gparent); (gparent)->entry.rbe_parent = (tmp
); do {} while (0); if (((tmp)->entry.rbe_parent)) do {} while
(0); } while (0); } else { tmp = (gparent)->entry.rbe_left
; if (tmp && (tmp)->entry.rbe_color == 1) { (tmp)->
entry.rbe_color = 0; do { (parent)->entry.rbe_color = 0; (
gparent)->entry.rbe_color = 1; } while (0); elm = gparent;
continue; } if ((parent)->entry.rbe_left == elm) { do { (
tmp) = (parent)->entry.rbe_left; if (((parent)->entry.rbe_left
= (tmp)->entry.rbe_right)) { ((tmp)->entry.rbe_right)->
entry.rbe_parent = (parent); } do {} while (0); if (((tmp)->
entry.rbe_parent = (parent)->entry.rbe_parent)) { if ((parent
) == ((parent)->entry.rbe_parent)->entry.rbe_left) ((parent
)->entry.rbe_parent)->entry.rbe_left = (tmp); else ((parent
)->entry.rbe_parent)->entry.rbe_right = (tmp); } else (
head)->rbh_root = (tmp); (tmp)->entry.rbe_right = (parent
); (parent)->entry.rbe_parent = (tmp); do {} while (0); if
(((tmp)->entry.rbe_parent)) do {} while (0); } while (0);
tmp = parent; parent = elm; elm = tmp; } do { (parent)->entry
.rbe_color = 0; (gparent)->entry.rbe_color = 1; } while (0
); do { (tmp) = (gparent)->entry.rbe_right; if (((gparent)
->entry.rbe_right = (tmp)->entry.rbe_left)) { ((tmp)->
entry.rbe_left)->entry.rbe_parent = (gparent); } do {} while
(0); if (((tmp)->entry.rbe_parent = (gparent)->entry.rbe_parent
)) { if ((gparent) == ((gparent)->entry.rbe_parent)->entry
.rbe_left) ((gparent)->entry.rbe_parent)->entry.rbe_left
= (tmp); else ((gparent)->entry.rbe_parent)->entry.rbe_right
= (tmp); } else (head)->rbh_root = (tmp); (tmp)->entry
.rbe_left = (gparent); (gparent)->entry.rbe_parent = (tmp)
; do {} while (0); if (((tmp)->entry.rbe_parent)) do {} while
(0); } while (0); } } (head->rbh_root)->entry.rbe_color
= 0; } __attribute__((__unused__)) static void format_entry_tree_RB_REMOVE_COLOR
(struct format_entry_tree *head, struct format_entry *parent,
struct format_entry *elm) { struct format_entry *tmp; while (
(elm == ((void *)0) || (elm)->entry.rbe_color == 0) &&
elm != (head)->rbh_root) { if ((parent)->entry.rbe_left
== elm) { tmp = (parent)->entry.rbe_right; if ((tmp)->
entry.rbe_color == 1) { do { (tmp)->entry.rbe_color = 0; (
parent)->entry.rbe_color = 1; } while (0); do { (tmp) = (parent
)->entry.rbe_right; if (((parent)->entry.rbe_right = (tmp
)->entry.rbe_left)) { ((tmp)->entry.rbe_left)->entry
.rbe_parent = (parent); } do {} while (0); if (((tmp)->entry
.rbe_parent = (parent)->entry.rbe_parent)) { if ((parent) ==
((parent)->entry.rbe_parent)->entry.rbe_left) ((parent
)->entry.rbe_parent)->entry.rbe_left = (tmp); else ((parent
)->entry.rbe_parent)->entry.rbe_right = (tmp); } else (
head)->rbh_root = (tmp); (tmp)->entry.rbe_left = (parent
); (parent)->entry.rbe_parent = (tmp); do {} while (0); if
(((tmp)->entry.rbe_parent)) do {} while (0); } while (0);
tmp = (parent)->entry.rbe_right; } if (((tmp)->entry.rbe_left
== ((void *)0) || ((tmp)->entry.rbe_left)->entry.rbe_color
== 0) && ((tmp)->entry.rbe_right == ((void *)0) ||
((tmp)->entry.rbe_right)->entry.rbe_color == 0)) { (tmp
)->entry.rbe_color = 1; elm = parent; parent = (elm)->entry
.rbe_parent; } else { if ((tmp)->entry.rbe_right == ((void
*)0) || ((tmp)->entry.rbe_right)->entry.rbe_color == 0
) { struct format_entry *oleft; if ((oleft = (tmp)->entry.
rbe_left)) (oleft)->entry.rbe_color = 0; (tmp)->entry.rbe_color
= 1; do { (oleft) = (tmp)->entry.rbe_left; if (((tmp)->
entry.rbe_left = (oleft)->entry.rbe_right)) { ((oleft)->
entry.rbe_right)->entry.rbe_parent = (tmp); } do {} while (
0); if (((oleft)->entry.rbe_parent = (tmp)->entry.rbe_parent
)) { if ((tmp) == ((tmp)->entry.rbe_parent)->entry.rbe_left
) ((tmp)->entry.rbe_parent)->entry.rbe_left = (oleft); else
((tmp)->entry.rbe_parent)->entry.rbe_right = (oleft); }
else (head)->rbh_root = (oleft); (oleft)->entry.rbe_right
= (tmp); (tmp)->entry.rbe_parent = (oleft); do {} while (
0); if (((oleft)->entry.rbe_parent)) do {} while (0); } while
(0); tmp = (parent)->entry.rbe_right; } (tmp)->entry.rbe_color
= (parent)->entry.rbe_color; (parent)->entry.rbe_color
= 0; if ((tmp)->entry.rbe_right) ((tmp)->entry.rbe_right
)->entry.rbe_color = 0; do { (tmp) = (parent)->entry.rbe_right
; if (((parent)->entry.rbe_right = (tmp)->entry.rbe_left
)) { ((tmp)->entry.rbe_left)->entry.rbe_parent = (parent
); } do {} while (0); if (((tmp)->entry.rbe_parent = (parent
)->entry.rbe_parent)) { if ((parent) == ((parent)->entry
.rbe_parent)->entry.rbe_left) ((parent)->entry.rbe_parent
)->entry.rbe_left = (tmp); else ((parent)->entry.rbe_parent
)->entry.rbe_right = (tmp); } else (head)->rbh_root = (
tmp); (tmp)->entry.rbe_left = (parent); (parent)->entry
.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent
)) do {} while (0); } while (0); elm = (head)->rbh_root; break
; } } else { tmp = (parent)->entry.rbe_left; if ((tmp)->
entry.rbe_color == 1) { do { (tmp)->entry.rbe_color = 0; (
parent)->entry.rbe_color = 1; } while (0); do { (tmp) = (parent
)->entry.rbe_left; if (((parent)->entry.rbe_left = (tmp
)->entry.rbe_right)) { ((tmp)->entry.rbe_right)->entry
.rbe_parent = (parent); } do {} while (0); if (((tmp)->entry
.rbe_parent = (parent)->entry.rbe_parent)) { if ((parent) ==
((parent)->entry.rbe_parent)->entry.rbe_left) ((parent
)->entry.rbe_parent)->entry.rbe_left = (tmp); else ((parent
)->entry.rbe_parent)->entry.rbe_right = (tmp); } else (
head)->rbh_root = (tmp); (tmp)->entry.rbe_right = (parent
); (parent)->entry.rbe_parent = (tmp); do {} while (0); if
(((tmp)->entry.rbe_parent)) do {} while (0); } while (0);
tmp = (parent)->entry.rbe_left; } if (((tmp)->entry.rbe_left
== ((void *)0) || ((tmp)->entry.rbe_left)->entry.rbe_color
== 0) && ((tmp)->entry.rbe_right == ((void *)0) ||
((tmp)->entry.rbe_right)->entry.rbe_color == 0)) { (tmp
)->entry.rbe_color = 1; elm = parent; parent = (elm)->entry
.rbe_parent; } else { if ((tmp)->entry.rbe_left == ((void *
)0) || ((tmp)->entry.rbe_left)->entry.rbe_color == 0) {
struct format_entry *oright; if ((oright = (tmp)->entry.rbe_right
)) (oright)->entry.rbe_color = 0; (tmp)->entry.rbe_color
= 1; do { (oright) = (tmp)->entry.rbe_right; if (((tmp)->
entry.rbe_right = (oright)->entry.rbe_left)) { ((oright)->
entry.rbe_left)->entry.rbe_parent = (tmp); } do {} while (
0); if (((oright)->entry.rbe_parent = (tmp)->entry.rbe_parent
)) { if ((tmp) == ((tmp)->entry.rbe_parent)->entry.rbe_left
) ((tmp)->entry.rbe_parent)->entry.rbe_left = (oright);
else ((tmp)->entry.rbe_parent)->entry.rbe_right = (oright
); } else (head)->rbh_root = (oright); (oright)->entry.
rbe_left = (tmp); (tmp)->entry.rbe_parent = (oright); do {
} while (0); if (((oright)->entry.rbe_parent)) do {} while
(0); } while (0); tmp = (parent)->entry.rbe_left; } (tmp)
->entry.rbe_color = (parent)->entry.rbe_color; (parent)
->entry.rbe_color = 0; if ((tmp)->entry.rbe_left) ((tmp
)->entry.rbe_left)->entry.rbe_color = 0; do { (tmp) = (
parent)->entry.rbe_left; if (((parent)->entry.rbe_left =
(tmp)->entry.rbe_right)) { ((tmp)->entry.rbe_right)->
entry.rbe_parent = (parent); } do {} while (0); if (((tmp)->
entry.rbe_parent = (parent)->entry.rbe_parent)) { if ((parent
) == ((parent)->entry.rbe_parent)->entry.rbe_left) ((parent
)->entry.rbe_parent)->entry.rbe_left = (tmp); else ((parent
)->entry.rbe_parent)->entry.rbe_right = (tmp); } else (
head)->rbh_root = (tmp); (tmp)->entry.rbe_right = (parent
); (parent)->entry.rbe_parent = (tmp); do {} while (0); if
(((tmp)->entry.rbe_parent)) do {} while (0); } while (0);
elm = (head)->rbh_root; break; } } } if (elm) (elm)->entry
.rbe_color = 0; } __attribute__((__unused__)) static struct format_entry
* format_entry_tree_RB_REMOVE(struct format_entry_tree *head
, struct format_entry *elm) { struct format_entry *child, *parent
, *old = elm; int color; if ((elm)->entry.rbe_left == ((void
*)0)) child = (elm)->entry.rbe_right; else if ((elm)->
entry.rbe_right == ((void *)0)) child = (elm)->entry.rbe_left
; else { struct format_entry *left; elm = (elm)->entry.rbe_right
; while ((left = (elm)->entry.rbe_left)) elm = left; child
= (elm)->entry.rbe_right; parent = (elm)->entry.rbe_parent
; color = (elm)->entry.rbe_color; if (child) (child)->entry
.rbe_parent = parent; if (parent) { if ((parent)->entry.rbe_left
== elm) (parent)->entry.rbe_left = child; else (parent)->
entry.rbe_right = child; do {} while (0); } else (head)->rbh_root
= child; if ((elm)->entry.rbe_parent == old) parent = elm
; (elm)->entry = (old)->entry; if ((old)->entry.rbe_parent
) { if (((old)->entry.rbe_parent)->entry.rbe_left == old
) ((old)->entry.rbe_parent)->entry.rbe_left = elm; else
((old)->entry.rbe_parent)->entry.rbe_right = elm; do {
} while (0); } else (head)->rbh_root = elm; ((old)->entry
.rbe_left)->entry.rbe_parent = elm; if ((old)->entry.rbe_right
) ((old)->entry.rbe_right)->entry.rbe_parent = elm; if (
parent) { left = parent; do { do {} while (0); } while ((left
= (left)->entry.rbe_parent)); } goto color; } parent = (elm
)->entry.rbe_parent; color = (elm)->entry.rbe_color; if
(child) (child)->entry.rbe_parent = parent; if (parent) {
if ((parent)->entry.rbe_left == elm) (parent)->entry.rbe_left
= child; else (parent)->entry.rbe_right = child; do {} while
(0); } else (head)->rbh_root = child; color: if (color ==
0) format_entry_tree_RB_REMOVE_COLOR(head, parent, child); return
(old); } __attribute__((__unused__)) static struct format_entry
* format_entry_tree_RB_INSERT(struct format_entry_tree *head
, struct format_entry *elm) { struct format_entry *tmp; struct
format_entry *parent = ((void *)0); int comp = 0; tmp = (head
)->rbh_root; while (tmp) { parent = tmp; comp = (format_entry_cmp
)(elm, parent); if (comp < 0) tmp = (tmp)->entry.rbe_left
; else if (comp > 0) tmp = (tmp)->entry.rbe_right; else
return (tmp); } do { (elm)->entry.rbe_parent = parent; (elm
)->entry.rbe_left = (elm)->entry.rbe_right = ((void *)0
); (elm)->entry.rbe_color = 1; } while (0); if (parent != (
(void *)0)) { if (comp < 0) (parent)->entry.rbe_left = elm
; else (parent)->entry.rbe_right = elm; do {} while (0); }
else (head)->rbh_root = elm; format_entry_tree_RB_INSERT_COLOR
(head, elm); return (((void *)0)); } __attribute__((__unused__
)) static struct format_entry * format_entry_tree_RB_FIND(struct
format_entry_tree *head, struct format_entry *elm) { struct format_entry
*tmp = (head)->rbh_root; int comp; while (tmp) { comp = format_entry_cmp
(elm, tmp); if (comp < 0) tmp = (tmp)->entry.rbe_left; else
if (comp > 0) tmp = (tmp)->entry.rbe_right; else return
(tmp); } return (((void *)0)); } __attribute__((__unused__))
static struct format_entry * format_entry_tree_RB_NFIND(struct
format_entry_tree *head, struct format_entry *elm) { struct format_entry
*tmp = (head)->rbh_root; struct format_entry *res = ((void
*)0); int comp; while (tmp) { comp = format_entry_cmp(elm, tmp
); if (comp < 0) { res = tmp; tmp = (tmp)->entry.rbe_left
; } else if (comp > 0) tmp = (tmp)->entry.rbe_right; else
return (tmp); } return (res); } __attribute__((__unused__)) static
struct format_entry * format_entry_tree_RB_NEXT(struct format_entry
*elm) { if ((elm)->entry.rbe_right) { elm = (elm)->entry
.rbe_right; while ((elm)->entry.rbe_left) elm = (elm)->
entry.rbe_left; } else { if ((elm)->entry.rbe_parent &&
(elm == ((elm)->entry.rbe_parent)->entry.rbe_left)) elm
= (elm)->entry.rbe_parent; else { while ((elm)->entry.
rbe_parent && (elm == ((elm)->entry.rbe_parent)->
entry.rbe_right)) elm = (elm)->entry.rbe_parent; elm = (elm
)->entry.rbe_parent; } } return (elm); } __attribute__((__unused__
)) static struct format_entry * format_entry_tree_RB_PREV(struct
format_entry *elm) { if ((elm)->entry.rbe_left) { elm = (
elm)->entry.rbe_left; while ((elm)->entry.rbe_right) elm
= (elm)->entry.rbe_right; } else { if ((elm)->entry.rbe_parent
&& (elm == ((elm)->entry.rbe_parent)->entry.rbe_right
)) elm = (elm)->entry.rbe_parent; else { while ((elm)->
entry.rbe_parent && (elm == ((elm)->entry.rbe_parent
)->entry.rbe_left)) elm = (elm)->entry.rbe_parent; elm =
(elm)->entry.rbe_parent; } } return (elm); } __attribute__
((__unused__)) static struct format_entry * format_entry_tree_RB_MINMAX
(struct format_entry_tree *head, int val) { struct format_entry
*tmp = (head)->rbh_root; struct format_entry *parent = ((
void *)0); while (tmp) { parent = tmp; if (val < 0) tmp = (
tmp)->entry.rbe_left; else tmp = (tmp)->entry.rbe_right
; } return (parent); }
;
151
152/* Format expand state. */
153struct format_expand_state {
154 struct format_tree *ft;
155 u_int loop;
156 time_t time;
157 struct tm tm;
158 int flags;
159};
160
161/* Format modifier. */
162struct format_modifier {
163 char modifier[3];
164 u_int size;
165
166 char **argv;
167 int argc;
168};
169
170/* Format entry tree comparison function. */
171static int
172format_entry_cmp(struct format_entry *fe1, struct format_entry *fe2)
173{
174 return (strcmp(fe1->key, fe2->key));
175}
176
177/* Single-character uppercase aliases. */
178static const char *format_upper[] = {
179 NULL((void *)0), /* A */
180 NULL((void *)0), /* B */
181 NULL((void *)0), /* C */
182 "pane_id", /* D */
183 NULL((void *)0), /* E */
184 "window_flags", /* F */
185 NULL((void *)0), /* G */
186 "host", /* H */
187 "window_index", /* I */
188 NULL((void *)0), /* J */
189 NULL((void *)0), /* K */
190 NULL((void *)0), /* L */
191 NULL((void *)0), /* M */
192 NULL((void *)0), /* N */
193 NULL((void *)0), /* O */
194 "pane_index", /* P */
195 NULL((void *)0), /* Q */
196 NULL((void *)0), /* R */
197 "session_name", /* S */
198 "pane_title", /* T */
199 NULL((void *)0), /* U */
200 NULL((void *)0), /* V */
201 "window_name", /* W */
202 NULL((void *)0), /* X */
203 NULL((void *)0), /* Y */
204 NULL((void *)0) /* Z */
205};
206
207/* Single-character lowercase aliases. */
208static const char *format_lower[] = {
209 NULL((void *)0), /* a */
210 NULL((void *)0), /* b */
211 NULL((void *)0), /* c */
212 NULL((void *)0), /* d */
213 NULL((void *)0), /* e */
214 NULL((void *)0), /* f */
215 NULL((void *)0), /* g */
216 "host_short", /* h */
217 NULL((void *)0), /* i */
218 NULL((void *)0), /* j */
219 NULL((void *)0), /* k */
220 NULL((void *)0), /* l */
221 NULL((void *)0), /* m */
222 NULL((void *)0), /* n */
223 NULL((void *)0), /* o */
224 NULL((void *)0), /* p */
225 NULL((void *)0), /* q */
226 NULL((void *)0), /* r */
227 NULL((void *)0), /* s */
228 NULL((void *)0), /* t */
229 NULL((void *)0), /* u */
230 NULL((void *)0), /* v */
231 NULL((void *)0), /* w */
232 NULL((void *)0), /* x */
233 NULL((void *)0), /* y */
234 NULL((void *)0) /* z */
235};
236
237/* Is logging enabled? */
238static inline int
239format_logging(struct format_tree *ft)
240{
241 return (log_get_level() != 0 || (ft->flags & FORMAT_VERBOSE0x8));
242}
243
244/* Log a message if verbose. */
245static void printflike(3, 4)__attribute__ ((format (printf, 3, 4)))
246format_log1(struct format_expand_state *es, const char *from, const char *fmt,
247 ...)
248{
249 struct format_tree *ft = es->ft;
250 va_list ap;
251 char *s;
252 static const char spaces[] = " ";
253
254 if (!format_logging(ft))
255 return;
256
257 va_start(ap, fmt)__builtin_va_start(ap, fmt);
258 xvasprintf(&s, fmt, ap);
259 va_end(ap)__builtin_va_end(ap);
260
261 log_debug("%s: %s", from, s);
262 if (ft->item != NULL((void *)0) && (ft->flags & FORMAT_VERBOSE0x8))
263 cmdq_print(ft->item, "#%.*s%s", es->loop, spaces, s);
264
265 free(s);
266}
267#define format_log(es, fmt, ...)format_log1(es, __func__, fmt, ...) format_log1(es, __func__, fmt, ##__VA_ARGS__)
268
269/* Copy expand state. */
270static void
271format_copy_state(struct format_expand_state *to,
272 struct format_expand_state *from, int flags)
273{
274 to->ft = from->ft;
275 to->loop = from->loop;
276 to->time = from->time;
277 memcpy(&to->tm, &from->tm, sizeof to->tm);
278 to->flags = from->flags|flags;
279}
280
281/* Format job update callback. */
282static void
283format_job_update(struct job *job)
284{
285 struct format_job *fj = job_get_data(job);
286 struct evbuffer *evb = job_get_event(job)->input;
287 char *line = NULL((void *)0), *next;
288 time_t t;
289
290 while ((next = evbuffer_readline(evb)) != NULL((void *)0)) {
291 free(line);
292 line = next;
293 }
294 if (line == NULL((void *)0))
295 return;
296 fj->updated = 1;
297
298 free(fj->out);
299 fj->out = line;
300
301 log_debug("%s: %p %s: %s", __func__, fj, fj->cmd, fj->out);
302
303 t = time(NULL((void *)0));
304 if (fj->status && fj->last != t) {
305 if (fj->client != NULL((void *)0))
306 server_status_client(fj->client);
307 fj->last = t;
308 }
309}
310
311/* Format job complete callback. */
312static void
313format_job_complete(struct job *job)
314{
315 struct format_job *fj = job_get_data(job);
316 struct evbuffer *evb = job_get_event(job)->input;
317 char *line, *buf;
318 size_t len;
319
320 fj->job = NULL((void *)0);
321
322 buf = NULL((void *)0);
323 if ((line = evbuffer_readline(evb)) == NULL((void *)0)) {
324 len = EVBUFFER_LENGTH(evb)(evb)->off;
325 buf = xmalloc(len + 1);
326 if (len != 0)
327 memcpy(buf, EVBUFFER_DATA(evb)(evb)->buffer, len);
328 buf[len] = '\0';
329 } else
330 buf = line;
331
332 log_debug("%s: %p %s: %s", __func__, fj, fj->cmd, buf);
333
334 if (*buf != '\0' || !fj->updated) {
335 free(fj->out);
336 fj->out = buf;
337 } else
338 free(buf);
339
340 if (fj->status) {
341 if (fj->client != NULL((void *)0))
342 server_status_client(fj->client);
343 fj->status = 0;
344 }
345}
346
347/* Find a job. */
348static char *
349format_job_get(struct format_expand_state *es, const char *cmd)
350{
351 struct format_tree *ft = es->ft;
352 struct format_job_tree *jobs;
353 struct format_job fj0, *fj;
354 time_t t;
355 char *expanded;
356 int force;
357 struct format_expand_state next;
358
359 if (ft->client == NULL((void *)0))
360 jobs = &format_jobs;
361 else if (ft->client->jobs != NULL((void *)0))
362 jobs = ft->client->jobs;
363 else {
364 jobs = ft->client->jobs = xmalloc(sizeof *ft->client->jobs);
365 RB_INIT(jobs)do { (jobs)->rbh_root = ((void *)0); } while (0);
366 }
367
368 fj0.tag = ft->tag;
369 fj0.cmd = cmd;
370 if ((fj = RB_FIND(format_job_tree, jobs, &fj0)format_job_tree_RB_FIND(jobs, &fj0)) == NULL((void *)0)) {
371 fj = xcalloc(1, sizeof *fj);
372 fj->client = ft->client;
373 fj->tag = ft->tag;
374 fj->cmd = xstrdup(cmd);
375
376 RB_INSERT(format_job_tree, jobs, fj)format_job_tree_RB_INSERT(jobs, fj);
377 }
378
379 format_copy_state(&next, es, FORMAT_EXPAND_NOJOBS0x2);
380 next.flags &= ~FORMAT_EXPAND_TIME0x1;
381
382 expanded = format_expand1(&next, cmd);
383 if (fj->expanded == NULL((void *)0) || strcmp(expanded, fj->expanded) != 0) {
384 free((void *)fj->expanded);
385 fj->expanded = xstrdup(expanded);
386 force = 1;
387 } else
388 force = (ft->flags & FORMAT_FORCE0x2);
389
390 t = time(NULL((void *)0));
391 if (force && fj->job != NULL((void *)0))
392 job_free(fj->job);
393 if (force || (fj->job == NULL((void *)0) && fj->last != t)) {
394 fj->job = job_run(expanded, 0, NULL((void *)0), NULL((void *)0), NULL((void *)0),
395 server_client_get_cwd(ft->client, NULL((void *)0)), format_job_update,
396 format_job_complete, NULL((void *)0), fj, JOB_NOWAIT0x1, -1, -1);
397 if (fj->job == NULL((void *)0)) {
398 free(fj->out);
399 xasprintf(&fj->out, "<'%s' didn't start>", fj->cmd);
400 }
401 fj->last = t;
402 fj->updated = 0;
403 } else if (fj->job != NULL((void *)0) && (t - fj->last) > 1 && fj->out == NULL((void *)0))
404 xasprintf(&fj->out, "<'%s' not ready>", fj->cmd);
405 free(expanded);
406
407 if (ft->flags & FORMAT_STATUS0x1)
408 fj->status = 1;
409 if (fj->out == NULL((void *)0))
410 return (xstrdup(""));
411 return (format_expand1(&next, fj->out));
412}
413
414/* Remove old jobs. */
415static void
416format_job_tidy(struct format_job_tree *jobs, int force)
417{
418 struct format_job *fj, *fj1;
419 time_t now;
420
421 now = time(NULL((void *)0));
422 RB_FOREACH_SAFE(fj, format_job_tree, jobs, fj1)for ((fj) = format_job_tree_RB_MINMAX(jobs, -1); ((fj) != ((void
*)0)) && ((fj1) = format_job_tree_RB_NEXT(fj), 1); (
fj) = (fj1))
{
423 if (!force && (fj->last > now || now - fj->last < 3600))
424 continue;
425 RB_REMOVE(format_job_tree, jobs, fj)format_job_tree_RB_REMOVE(jobs, fj);
426
427 log_debug("%s: %s", __func__, fj->cmd);
428
429 if (fj->job != NULL((void *)0))
430 job_free(fj->job);
431
432 free((void *)fj->expanded);
433 free((void *)fj->cmd);
434 free(fj->out);
435
436 free(fj);
437 }
438}
439
440/* Tidy old jobs for all clients. */
441void
442format_tidy_jobs(void)
443{
444 struct client *c;
445
446 format_job_tidy(&format_jobs, 0);
447 TAILQ_FOREACH(c, &clients, entry)for((c) = ((&clients)->tqh_first); (c) != ((void *)0);
(c) = ((c)->entry.tqe_next))
{
448 if (c->jobs != NULL((void *)0))
449 format_job_tidy(c->jobs, 0);
450 }
451}
452
453/* Remove old jobs for client. */
454void
455format_lost_client(struct client *c)
456{
457 if (c->jobs != NULL((void *)0))
458 format_job_tidy(c->jobs, 1);
459 free(c->jobs);
460}
461
462/* Wrapper for asprintf. */
463static char * printflike(1, 2)__attribute__ ((format (printf, 1, 2)))
464format_printf(const char *fmt, ...)
465{
466 va_list ap;
467 char *s;
468
469 va_start(ap, fmt)__builtin_va_start(ap, fmt);
470 xvasprintf(&s, fmt, ap);
471 va_end(ap)__builtin_va_end(ap);
472 return (s);
473}
474
475/* Callback for host. */
476static void *
477format_cb_host(__unused__attribute__((__unused__)) struct format_tree *ft)
478{
479 char host[HOST_NAME_MAX255 + 1];
480
481 if (gethostname(host, sizeof host) != 0)
482 return (xstrdup(""));
483 return (xstrdup(host));
484}
485
486/* Callback for host_short. */
487static void *
488format_cb_host_short(__unused__attribute__((__unused__)) struct format_tree *ft)
489{
490 char host[HOST_NAME_MAX255 + 1], *cp;
491
492 if (gethostname(host, sizeof host) != 0)
493 return (xstrdup(""));
494 if ((cp = strchr(host, '.')) != NULL((void *)0))
495 *cp = '\0';
496 return (xstrdup(host));
497}
498
499/* Callback for pid. */
500static void *
501format_cb_pid(__unused__attribute__((__unused__)) struct format_tree *ft)
502{
503 char *value;
504
505 xasprintf(&value, "%ld", (long)getpid());
506 return (value);
507}
508
509/* Callback for session_attached_list. */
510static void *
511format_cb_session_attached_list(struct format_tree *ft)
512{
513 struct session *s = ft->s;
514 struct client *loop;
515 struct evbuffer *buffer;
516 int size;
517 char *value = NULL((void *)0);
518
519 if (s == NULL((void *)0))
520 return (NULL((void *)0));
521
522 buffer = evbuffer_new();
523 if (buffer == NULL((void *)0))
524 fatalx("out of memory");
525
526 TAILQ_FOREACH(loop, &clients, entry)for((loop) = ((&clients)->tqh_first); (loop) != ((void
*)0); (loop) = ((loop)->entry.tqe_next))
{
527 if (loop->session == s) {
528 if (EVBUFFER_LENGTH(buffer)(buffer)->off > 0)
529 evbuffer_add(buffer, ",", 1);
530 evbuffer_add_printf(buffer, "%s", loop->name);
531 }
532 }
533
534 if ((size = EVBUFFER_LENGTH(buffer)(buffer)->off) != 0)
535 xasprintf(&value, "%.*s", size, EVBUFFER_DATA(buffer)(buffer)->buffer);
536 evbuffer_free(buffer);
537 return (value);
538}
539
540/* Callback for session_alerts. */
541static void *
542format_cb_session_alerts(struct format_tree *ft)
543{
544 struct session *s = ft->s;
545 struct winlink *wl;
546 char alerts[1024], tmp[16];
547
548 if (s == NULL((void *)0))
549 return (NULL((void *)0));
550
551 *alerts = '\0';
552 RB_FOREACH(wl, winlinks, &s->windows)for ((wl) = winlinks_RB_MINMAX(&s->windows, -1); (wl) !=
((void *)0); (wl) = winlinks_RB_NEXT(wl))
{
553 if ((wl->flags & WINLINK_ALERTFLAGS(0x1|0x2|0x4)) == 0)
554 continue;
555 xsnprintf(tmp, sizeof tmp, "%u", wl->idx);
556
557 if (*alerts != '\0')
558 strlcat(alerts, ",", sizeof alerts);
559 strlcat(alerts, tmp, sizeof alerts);
560 if (wl->flags & WINLINK_ACTIVITY0x2)
561 strlcat(alerts, "#", sizeof alerts);
562 if (wl->flags & WINLINK_BELL0x1)
563 strlcat(alerts, "!", sizeof alerts);
564 if (wl->flags & WINLINK_SILENCE0x4)
565 strlcat(alerts, "~", sizeof alerts);
566 }
567 return (xstrdup(alerts));
568}
569
570/* Callback for session_stack. */
571static void *
572format_cb_session_stack(struct format_tree *ft)
573{
574 struct session *s = ft->s;
575 struct winlink *wl;
576 char result[1024], tmp[16];
577
578 if (s == NULL((void *)0))
579 return (NULL((void *)0));
580
581 xsnprintf(result, sizeof result, "%u", s->curw->idx);
582 TAILQ_FOREACH(wl, &s->lastw, sentry)for((wl) = ((&s->lastw)->tqh_first); (wl) != ((void
*)0); (wl) = ((wl)->sentry.tqe_next))
{
583 xsnprintf(tmp, sizeof tmp, "%u", wl->idx);
584
585 if (*result != '\0')
586 strlcat(result, ",", sizeof result);
587 strlcat(result, tmp, sizeof result);
588 }
589 return (xstrdup(result));
590}
591
592/* Callback for window_stack_index. */
593static void *
594format_cb_window_stack_index(struct format_tree *ft)
595{
596 struct session *s;
597 struct winlink *wl;
598 u_int idx;
599 char *value = NULL((void *)0);
600
601 if (ft->wl == NULL((void *)0))
602 return (NULL((void *)0));
603 s = ft->wl->session;
604
605 idx = 0;
606 TAILQ_FOREACH(wl, &s->lastw, sentry)for((wl) = ((&s->lastw)->tqh_first); (wl) != ((void
*)0); (wl) = ((wl)->sentry.tqe_next))
{
607 idx++;
608 if (wl == ft->wl)
609 break;
610 }
611 if (wl == NULL((void *)0))
612 return (xstrdup("0"));
613 xasprintf(&value, "%u", idx);
614 return (value);
615}
616
617/* Callback for window_linked_sessions_list. */
618static void *
619format_cb_window_linked_sessions_list(struct format_tree *ft)
620{
621 struct window *w;
622 struct winlink *wl;
623 struct evbuffer *buffer;
624 int size;
625 char *value = NULL((void *)0);
626
627 if (ft->wl == NULL((void *)0))
628 return (NULL((void *)0));
629 w = ft->wl->window;
630
631 buffer = evbuffer_new();
632 if (buffer == NULL((void *)0))
633 fatalx("out of memory");
634
635 TAILQ_FOREACH(wl, &w->winlinks, wentry)for((wl) = ((&w->winlinks)->tqh_first); (wl) != ((void
*)0); (wl) = ((wl)->wentry.tqe_next))
{
636 if (EVBUFFER_LENGTH(buffer)(buffer)->off > 0)
637 evbuffer_add(buffer, ",", 1);
638 evbuffer_add_printf(buffer, "%s", wl->session->name);
639 }
640
641 if ((size = EVBUFFER_LENGTH(buffer)(buffer)->off) != 0)
642 xasprintf(&value, "%.*s", size, EVBUFFER_DATA(buffer)(buffer)->buffer);
643 evbuffer_free(buffer);
644 return (value);
645}
646
647/* Callback for window_active_sessions. */
648static void *
649format_cb_window_active_sessions(struct format_tree *ft)
650{
651 struct window *w;
652 struct winlink *wl;
653 u_int n = 0;
654 char *value;
655
656 if (ft->wl == NULL((void *)0))
657 return (NULL((void *)0));
658 w = ft->wl->window;
659
660 TAILQ_FOREACH(wl, &w->winlinks, wentry)for((wl) = ((&w->winlinks)->tqh_first); (wl) != ((void
*)0); (wl) = ((wl)->wentry.tqe_next))
{
661 if (wl->session->curw == wl)
662 n++;
663 }
664
665 xasprintf(&value, "%u", n);
666 return (value);
667}
668
669/* Callback for window_active_sessions_list. */
670static void *
671format_cb_window_active_sessions_list(struct format_tree *ft)
672{
673 struct window *w;
674 struct winlink *wl;
675 struct evbuffer *buffer;
676 int size;
677 char *value = NULL((void *)0);
678
679 if (ft->wl == NULL((void *)0))
680 return (NULL((void *)0));
681 w = ft->wl->window;
682
683 buffer = evbuffer_new();
684 if (buffer == NULL((void *)0))
685 fatalx("out of memory");
686
687 TAILQ_FOREACH(wl, &w->winlinks, wentry)for((wl) = ((&w->winlinks)->tqh_first); (wl) != ((void
*)0); (wl) = ((wl)->wentry.tqe_next))
{
688 if (wl->session->curw == wl) {
689 if (EVBUFFER_LENGTH(buffer)(buffer)->off > 0)
690 evbuffer_add(buffer, ",", 1);
691 evbuffer_add_printf(buffer, "%s", wl->session->name);
692 }
693 }
694
695 if ((size = EVBUFFER_LENGTH(buffer)(buffer)->off) != 0)
696 xasprintf(&value, "%.*s", size, EVBUFFER_DATA(buffer)(buffer)->buffer);
697 evbuffer_free(buffer);
698 return (value);
699}
700
701/* Callback for window_active_clients. */
702static void *
703format_cb_window_active_clients(struct format_tree *ft)
704{
705 struct window *w;
706 struct client *loop;
707 struct session *client_session;
708 u_int n = 0;
709 char *value;
710
711 if (ft->wl == NULL((void *)0))
712 return (NULL((void *)0));
713 w = ft->wl->window;
714
715 TAILQ_FOREACH(loop, &clients, entry)for((loop) = ((&clients)->tqh_first); (loop) != ((void
*)0); (loop) = ((loop)->entry.tqe_next))
{
716 client_session = loop->session;
717 if (client_session == NULL((void *)0))
718 continue;
719
720 if (w == client_session->curw->window)
721 n++;
722 }
723
724 xasprintf(&value, "%u", n);
725 return (value);
726}
727
728/* Callback for window_active_clients_list. */
729static void *
730format_cb_window_active_clients_list(struct format_tree *ft)
731{
732 struct window *w;
733 struct client *loop;
734 struct session *client_session;
735 struct evbuffer *buffer;
736 int size;
737 char *value = NULL((void *)0);
738
739 if (ft->wl == NULL((void *)0))
740 return (NULL((void *)0));
741 w = ft->wl->window;
742
743 buffer = evbuffer_new();
744 if (buffer == NULL((void *)0))
745 fatalx("out of memory");
746
747 TAILQ_FOREACH(loop, &clients, entry)for((loop) = ((&clients)->tqh_first); (loop) != ((void
*)0); (loop) = ((loop)->entry.tqe_next))
{
748 client_session = loop->session;
749 if (client_session == NULL((void *)0))
750 continue;
751
752 if (w == client_session->curw->window) {
753 if (EVBUFFER_LENGTH(buffer)(buffer)->off > 0)
754 evbuffer_add(buffer, ",", 1);
755 evbuffer_add_printf(buffer, "%s", loop->name);
756 }
757 }
758
759 if ((size = EVBUFFER_LENGTH(buffer)(buffer)->off) != 0)
760 xasprintf(&value, "%.*s", size, EVBUFFER_DATA(buffer)(buffer)->buffer);
761 evbuffer_free(buffer);
762 return (value);
763}
764
765/* Callback for window_layout. */
766static void *
767format_cb_window_layout(struct format_tree *ft)
768{
769 struct window *w = ft->w;
770
771 if (w == NULL((void *)0))
772 return (NULL((void *)0));
773
774 if (w->saved_layout_root != NULL((void *)0))
775 return (layout_dump(w->saved_layout_root));
776 return (layout_dump(w->layout_root));
777}
778
779/* Callback for window_visible_layout. */
780static void *
781format_cb_window_visible_layout(struct format_tree *ft)
782{
783 struct window *w = ft->w;
784
785 if (w == NULL((void *)0))
786 return (NULL((void *)0));
787
788 return (layout_dump(w->layout_root));
789}
790
791/* Callback for pane_start_command. */
792static void *
793format_cb_start_command(struct format_tree *ft)
794{
795 struct window_pane *wp = ft->wp;
796
797 if (wp == NULL((void *)0))
798 return (NULL((void *)0));
799
800 return (cmd_stringify_argv(wp->argc, wp->argv));
801}
802
803/* Callback for pane_current_command. */
804static void *
805format_cb_current_command(struct format_tree *ft)
806{
807 struct window_pane *wp = ft->wp;
808 char *cmd, *value;
809
810 if (wp == NULL((void *)0) || wp->shell == NULL((void *)0))
811 return (NULL((void *)0));
812
813 cmd = get_proc_name(wp->fd, wp->tty);
814 if (cmd == NULL((void *)0) || *cmd == '\0') {
815 free(cmd);
816 cmd = cmd_stringify_argv(wp->argc, wp->argv);
817 if (cmd == NULL((void *)0) || *cmd == '\0') {
818 free(cmd);
819 cmd = xstrdup(wp->shell);
820 }
821 }
822 value = parse_window_name(cmd);
823 free(cmd);
824 return (value);
825}
826
827/* Callback for pane_current_path. */
828static void *
829format_cb_current_path(struct format_tree *ft)
830{
831 struct window_pane *wp = ft->wp;
832 char *cwd;
833
834 if (wp == NULL((void *)0))
835 return (NULL((void *)0));
836
837 cwd = get_proc_cwd(wp->fd);
838 if (cwd == NULL((void *)0))
839 return (NULL((void *)0));
840 return (xstrdup(cwd));
841}
842
843/* Callback for history_bytes. */
844static void *
845format_cb_history_bytes(struct format_tree *ft)
846{
847 struct window_pane *wp = ft->wp;
848 struct grid *gd;
849 struct grid_line *gl;
850 size_t size = 0;
851 u_int i;
852 char *value;
853
854 if (wp == NULL((void *)0))
855 return (NULL((void *)0));
856 gd = wp->base.grid;
857
858 for (i = 0; i < gd->hsize + gd->sy; i++) {
859 gl = grid_get_line(gd, i);
860 size += gl->cellsize * sizeof *gl->celldata;
861 size += gl->extdsize * sizeof *gl->extddata;
862 }
863 size += (gd->hsize + gd->sy) * sizeof *gl;
864
865 xasprintf(&value, "%zu", size);
866 return (value);
867}
868
869/* Callback for history_all_bytes. */
870static void *
871format_cb_history_all_bytes(struct format_tree *ft)
872{
873 struct window_pane *wp = ft->wp;
874 struct grid *gd;
875 struct grid_line *gl;
876 u_int i, lines, cells = 0, extended_cells = 0;
877 char *value;
878
879 if (wp == NULL((void *)0))
880 return (NULL((void *)0));
881 gd = wp->base.grid;
882
883 lines = gd->hsize + gd->sy;
884 for (i = 0; i < lines; i++) {
885 gl = grid_get_line(gd, i);
886 cells += gl->cellsize;
887 extended_cells += gl->extdsize;
888 }
889
890 xasprintf(&value, "%u,%zu,%u,%zu,%u,%zu", lines,
891 lines * sizeof *gl, cells, cells * sizeof *gl->celldata,
892 extended_cells, extended_cells * sizeof *gl->extddata);
893 return (value);
894}
895
896/* Callback for pane_tabs. */
897static void *
898format_cb_pane_tabs(struct format_tree *ft)
899{
900 struct window_pane *wp = ft->wp;
901 struct evbuffer *buffer;
902 u_int i;
903 int size;
904 char *value = NULL((void *)0);
905
906 if (wp == NULL((void *)0))
907 return (NULL((void *)0));
908
909 buffer = evbuffer_new();
910 if (buffer == NULL((void *)0))
911 fatalx("out of memory");
912 for (i = 0; i < wp->base.grid->sx; i++) {
913 if (!bit_test(wp->base.tabs, i)((wp->base.tabs)[((i) >> 3)] & (1 << ((i)&
0x7)))
)
914 continue;
915
916 if (EVBUFFER_LENGTH(buffer)(buffer)->off > 0)
917 evbuffer_add(buffer, ",", 1);
918 evbuffer_add_printf(buffer, "%u", i);
919 }
920 if ((size = EVBUFFER_LENGTH(buffer)(buffer)->off) != 0)
921 xasprintf(&value, "%.*s", size, EVBUFFER_DATA(buffer)(buffer)->buffer);
922 evbuffer_free(buffer);
923 return (value);
924}
925
926/* Callback for pane_fg. */
927static void *
928format_cb_pane_fg(struct format_tree *ft)
929{
930 struct window_pane *wp = ft->wp;
931 struct grid_cell gc;
932
933 if (wp == NULL((void *)0))
934 return (NULL((void *)0));
935
936 tty_default_colours(&gc, wp);
937 return (xstrdup(colour_tostring(gc.fg)));
938}
939
940/* Callback for pane_bg. */
941static void *
942format_cb_pane_bg(struct format_tree *ft)
943{
944 struct window_pane *wp = ft->wp;
945 struct grid_cell gc;
946
947 if (wp == NULL((void *)0))
948 return (NULL((void *)0));
949
950 tty_default_colours(&gc, wp);
951 return (xstrdup(colour_tostring(gc.bg)));
952}
953
954/* Callback for session_group_list. */
955static void *
956format_cb_session_group_list(struct format_tree *ft)
957{
958 struct session *s = ft->s;
959 struct session_group *sg;
960 struct session *loop;
961 struct evbuffer *buffer;
962 int size;
963 char *value = NULL((void *)0);
964
965 if (s == NULL((void *)0))
966 return (NULL((void *)0));
967 sg = session_group_contains(s);
968 if (sg == NULL((void *)0))
969 return (NULL((void *)0));
970
971 buffer = evbuffer_new();
972 if (buffer == NULL((void *)0))
973 fatalx("out of memory");
974
975 TAILQ_FOREACH(loop, &sg->sessions, gentry)for((loop) = ((&sg->sessions)->tqh_first); (loop) !=
((void *)0); (loop) = ((loop)->gentry.tqe_next))
{
976 if (EVBUFFER_LENGTH(buffer)(buffer)->off > 0)
977 evbuffer_add(buffer, ",", 1);
978 evbuffer_add_printf(buffer, "%s", loop->name);
979 }
980
981 if ((size = EVBUFFER_LENGTH(buffer)(buffer)->off) != 0)
982 xasprintf(&value, "%.*s", size, EVBUFFER_DATA(buffer)(buffer)->buffer);
983 evbuffer_free(buffer);
984 return (value);
985}
986
987/* Callback for session_group_attached_list. */
988static void *
989format_cb_session_group_attached_list(struct format_tree *ft)
990{
991 struct session *s = ft->s, *client_session, *session_loop;
992 struct session_group *sg;
993 struct client *loop;
994 struct evbuffer *buffer;
995 int size;
996 char *value = NULL((void *)0);
997
998 if (s == NULL((void *)0))
999 return (NULL((void *)0));
1000 sg = session_group_contains(s);
1001 if (sg == NULL((void *)0))
1002 return (NULL((void *)0));
1003
1004 buffer = evbuffer_new();
1005 if (buffer == NULL((void *)0))
1006 fatalx("out of memory");
1007
1008 TAILQ_FOREACH(loop, &clients, entry)for((loop) = ((&clients)->tqh_first); (loop) != ((void
*)0); (loop) = ((loop)->entry.tqe_next))
{
1009 client_session = loop->session;
1010 if (client_session == NULL((void *)0))
1011 continue;
1012 TAILQ_FOREACH(session_loop, &sg->sessions, gentry)for((session_loop) = ((&sg->sessions)->tqh_first); (
session_loop) != ((void *)0); (session_loop) = ((session_loop
)->gentry.tqe_next))
{
1013 if (session_loop == client_session){
1014 if (EVBUFFER_LENGTH(buffer)(buffer)->off > 0)
1015 evbuffer_add(buffer, ",", 1);
1016 evbuffer_add_printf(buffer, "%s", loop->name);
1017 }
1018 }
1019 }
1020
1021 if ((size = EVBUFFER_LENGTH(buffer)(buffer)->off) != 0)
1022 xasprintf(&value, "%.*s", size, EVBUFFER_DATA(buffer)(buffer)->buffer);
1023 evbuffer_free(buffer);
1024 return (value);
1025}
1026
1027/* Callback for pane_in_mode. */
1028static void *
1029format_cb_pane_in_mode(struct format_tree *ft)
1030{
1031 struct window_pane *wp = ft->wp;
1032 u_int n = 0;
1033 struct window_mode_entry *wme;
1034 char *value;
1035
1036 if (wp == NULL((void *)0))
1037 return (NULL((void *)0));
1038
1039 TAILQ_FOREACH(wme, &wp->modes, entry)for((wme) = ((&wp->modes)->tqh_first); (wme) != ((void
*)0); (wme) = ((wme)->entry.tqe_next))
1040 n++;
1041 xasprintf(&value, "%u", n);
1042 return (value);
1043}
1044
1045/* Callback for pane_at_top. */
1046static void *
1047format_cb_pane_at_top(struct format_tree *ft)
1048{
1049 struct window_pane *wp = ft->wp;
1050 struct window *w;
1051 int status, flag;
1052 char *value;
1053
1054 if (wp == NULL((void *)0))
1055 return (NULL((void *)0));
1056 w = wp->window;
1057
1058 status = options_get_number(w->options, "pane-border-status");
1059 if (status == PANE_STATUS_TOP1)
1060 flag = (wp->yoff == 1);
1061 else
1062 flag = (wp->yoff == 0);
1063 xasprintf(&value, "%d", flag);
1064 return (value);
1065}
1066
1067/* Callback for pane_at_bottom. */
1068static void *
1069format_cb_pane_at_bottom(struct format_tree *ft)
1070{
1071 struct window_pane *wp = ft->wp;
1072 struct window *w;
1073 int status, flag;
1074 char *value;
1075
1076 if (wp == NULL((void *)0))
1077 return (NULL((void *)0));
1078 w = wp->window;
1079
1080 status = options_get_number(w->options, "pane-border-status");
1081 if (status == PANE_STATUS_BOTTOM2)
1082 flag = (wp->yoff + wp->sy == w->sy - 1);
1083 else
1084 flag = (wp->yoff + wp->sy == w->sy);
1085 xasprintf(&value, "%d", flag);
1086 return (value);
1087}
1088
1089/* Callback for cursor_character. */
1090static void *
1091format_cb_cursor_character(struct format_tree *ft)
1092{
1093 struct window_pane *wp = ft->wp;
1094 struct grid_cell gc;
1095 char *value = NULL((void *)0);
1096
1097 if (wp == NULL((void *)0))
1098 return (NULL((void *)0));
1099
1100 grid_view_get_cell(wp->base.grid, wp->base.cx, wp->base.cy, &gc);
1101 if (~gc.flags & GRID_FLAG_PADDING0x4)
1102 xasprintf(&value, "%.*s", (int)gc.data.size, gc.data.data);
1103 return (value);
1104}
1105
1106/* Callback for mouse_word. */
1107static void *
1108format_cb_mouse_word(struct format_tree *ft)
1109{
1110 struct window_pane *wp;
1111 struct grid *gd;
1112 u_int x, y;
1113 char *s;
1114
1115 if (!ft->m.valid)
1116 return (NULL((void *)0));
1117 wp = cmd_mouse_pane(&ft->m, NULL((void *)0), NULL((void *)0));
1118 if (wp == NULL((void *)0))
1119 return (NULL((void *)0));
1120 if (cmd_mouse_at(wp, &ft->m, &x, &y, 0) != 0)
1121 return (NULL((void *)0));
1122
1123 if (!TAILQ_EMPTY(&wp->modes)(((&wp->modes)->tqh_first) == ((void *)0))) {
1124 if (TAILQ_FIRST(&wp->modes)((&wp->modes)->tqh_first)->mode == &window_copy_mode ||
1125 TAILQ_FIRST(&wp->modes)((&wp->modes)->tqh_first)->mode == &window_view_mode)
1126 return (s = window_copy_get_word(wp, x, y));
Although the value stored to 's' is used in the enclosing expression, the value is never actually read from 's'
1127 return (NULL((void *)0));
1128 }
1129 gd = wp->base.grid;
1130 return (format_grid_word(gd, x, gd->hsize + y));
1131}
1132
1133/* Callback for mouse_line. */
1134static void *
1135format_cb_mouse_line(struct format_tree *ft)
1136{
1137 struct window_pane *wp;
1138 struct grid *gd;
1139 u_int x, y;
1140
1141 if (!ft->m.valid)
1142 return (NULL((void *)0));
1143 wp = cmd_mouse_pane(&ft->m, NULL((void *)0), NULL((void *)0));
1144 if (wp == NULL((void *)0))
1145 return (NULL((void *)0));
1146 if (cmd_mouse_at(wp, &ft->m, &x, &y, 0) != 0)
1147 return (NULL((void *)0));
1148
1149 if (!TAILQ_EMPTY(&wp->modes)(((&wp->modes)->tqh_first) == ((void *)0))) {
1150 if (TAILQ_FIRST(&wp->modes)((&wp->modes)->tqh_first)->mode == &window_copy_mode ||
1151 TAILQ_FIRST(&wp->modes)((&wp->modes)->tqh_first)->mode == &window_view_mode)
1152 return (window_copy_get_line(wp, y));
1153 return (NULL((void *)0));
1154 }
1155 gd = wp->base.grid;
1156 return (format_grid_line(gd, gd->hsize + y));
1157}
1158
1159/* Callback for alternate_on. */
1160static void *
1161format_cb_alternate_on(struct format_tree *ft)
1162{
1163 if (ft->wp != NULL((void *)0)) {
1164 if (ft->wp->base.saved_grid != NULL((void *)0))
1165 return (xstrdup("1"));
1166 return (xstrdup("0"));
1167 }
1168 return (NULL((void *)0));
1169}
1170
1171/* Callback for alternate_saved_x. */
1172static void *
1173format_cb_alternate_saved_x(struct format_tree *ft)
1174{
1175 if (ft->wp != NULL((void *)0))
1176 return (format_printf("%u", ft->wp->base.saved_cx));
1177 return (NULL((void *)0));
1178}
1179
1180/* Callback for alternate_saved_y. */
1181static void *
1182format_cb_alternate_saved_y(struct format_tree *ft)
1183{
1184 if (ft->wp != NULL((void *)0))
1185 return (format_printf("%u", ft->wp->base.saved_cy));
1186 return (NULL((void *)0));
1187}
1188
1189/* Callback for buffer_name. */
1190static void *
1191format_cb_buffer_name(struct format_tree *ft)
1192{
1193 if (ft->pb != NULL((void *)0))
1194 return (xstrdup(paste_buffer_name(ft->pb)));
1195 return (NULL((void *)0));
1196}
1197
1198/* Callback for buffer_sample. */
1199static void *
1200format_cb_buffer_sample(struct format_tree *ft)
1201{
1202 if (ft->pb != NULL((void *)0))
1203 return (paste_make_sample(ft->pb));
1204 return (NULL((void *)0));
1205}
1206
1207/* Callback for buffer_size. */
1208static void *
1209format_cb_buffer_size(struct format_tree *ft)
1210{
1211 size_t size;
1212
1213 if (ft->pb != NULL((void *)0)) {
1214 paste_buffer_data(ft->pb, &size);
1215 return (format_printf("%zu", size));
1216 }
1217 return (NULL((void *)0));
1218}
1219
1220/* Callback for client_cell_height. */
1221static void *
1222format_cb_client_cell_height(struct format_tree *ft)
1223{
1224 if (ft->c != NULL((void *)0) && (ft->c->tty.flags & TTY_STARTED0x10))
1225 return (format_printf("%u", ft->c->tty.ypixel));
1226 return (NULL((void *)0));
1227}
1228
1229/* Callback for client_cell_width. */
1230static void *
1231format_cb_client_cell_width(struct format_tree *ft)
1232{
1233 if (ft->c != NULL((void *)0) && (ft->c->tty.flags & TTY_STARTED0x10))
1234 return (format_printf("%u", ft->c->tty.xpixel));
1235 return (NULL((void *)0));
1236}
1237
1238/* Callback for client_control_mode. */
1239static void *
1240format_cb_client_control_mode(struct format_tree *ft)
1241{
1242 if (ft->c != NULL((void *)0)) {
1243 if (ft->c->flags & CLIENT_CONTROL0x2000)
1244 return (xstrdup("1"));
1245 return (xstrdup("0"));
1246 }
1247 return (NULL((void *)0));
1248}
1249
1250/* Callback for client_discarded. */
1251static void *
1252format_cb_client_discarded(struct format_tree *ft)
1253{
1254 if (ft->c != NULL((void *)0))
1255 return (format_printf("%zu", ft->c->discarded));
1256 return (NULL((void *)0));
1257}
1258
1259/* Callback for client_flags. */
1260static void *
1261format_cb_client_flags(struct format_tree *ft)
1262{
1263 if (ft->c != NULL((void *)0))
1264 return (xstrdup(server_client_get_flags(ft->c)));
1265 return (NULL((void *)0));
1266}
1267
1268/* Callback for client_height. */
1269static void *
1270format_cb_client_height(struct format_tree *ft)
1271{
1272 if (ft->c != NULL((void *)0) && (ft->c->tty.flags & TTY_STARTED0x10))
1273 return (format_printf("%u", ft->c->tty.sy));
1274 return (NULL((void *)0));
1275}
1276
1277/* Callback for client_key_table. */
1278static void *
1279format_cb_client_key_table(struct format_tree *ft)
1280{
1281 if (ft->c != NULL((void *)0))
1282 return (xstrdup(ft->c->keytable->name));
1283 return (NULL((void *)0));
1284}
1285
1286/* Callback for client_last_session. */
1287static void *
1288format_cb_client_last_session(struct format_tree *ft)
1289{
1290 if (ft->c != NULL((void *)0) &&
1291 ft->c->last_session != NULL((void *)0) &&
1292 session_alive(ft->c->last_session))
1293 return (xstrdup(ft->c->last_session->name));
1294 return (NULL((void *)0));
1295}
1296
1297/* Callback for client_name. */
1298static void *
1299format_cb_client_name(struct format_tree *ft)
1300{
1301 if (ft->c != NULL((void *)0))
1302 return (xstrdup(ft->c->name));
1303 return (NULL((void *)0));
1304}
1305
1306/* Callback for client_pid. */
1307static void *
1308format_cb_client_pid(struct format_tree *ft)
1309{
1310 if (ft->c != NULL((void *)0))
1311 return (format_printf("%ld", (long)ft->c->pid));
1312 return (NULL((void *)0));
1313}
1314
1315/* Callback for client_prefix. */
1316static void *
1317format_cb_client_prefix(struct format_tree *ft)
1318{
1319 const char *name;
1320
1321 if (ft->c != NULL((void *)0)) {
1322 name = server_client_get_key_table(ft->c);
1323 if (strcmp(ft->c->keytable->name, name) == 0)
1324 return (xstrdup("0"));
1325 return (xstrdup("1"));
1326 }
1327 return (NULL((void *)0));
1328}
1329
1330/* Callback for client_readonly. */
1331static void *
1332format_cb_client_readonly(struct format_tree *ft)
1333{
1334 if (ft->c != NULL((void *)0)) {
1335 if (ft->c->flags & CLIENT_READONLY0x800)
1336 return (xstrdup("1"));
1337 return (xstrdup("0"));
1338 }
1339 return (NULL((void *)0));
1340}
1341
1342/* Callback for client_session. */
1343static void *
1344format_cb_client_session(struct format_tree *ft)
1345{
1346 if (ft->c != NULL((void *)0) && ft->c->session != NULL((void *)0))
1347 return (xstrdup(ft->c->session->name));
1348 return (NULL((void *)0));
1349}
1350
1351/* Callback for client_termfeatures. */
1352static void *
1353format_cb_client_termfeatures(struct format_tree *ft)
1354{
1355 if (ft->c != NULL((void *)0))
1356 return (xstrdup(tty_get_features(ft->c->term_features)));
1357 return (NULL((void *)0));
1358}
1359
1360/* Callback for client_termname. */
1361static void *
1362format_cb_client_termname(struct format_tree *ft)
1363{
1364 if (ft->c != NULL((void *)0))
1365 return (xstrdup(ft->c->term_name));
1366 return (NULL((void *)0));
1367}
1368
1369/* Callback for client_termtype. */
1370static void *
1371format_cb_client_termtype(struct format_tree *ft)
1372{
1373 if (ft->c != NULL((void *)0)) {
1374 if (ft->c->term_type == NULL((void *)0))
1375 return (xstrdup(""));
1376 return (xstrdup(ft->c->term_type));
1377 }
1378 return (NULL((void *)0));
1379}
1380
1381/* Callback for client_tty. */
1382static void *
1383format_cb_client_tty(struct format_tree *ft)
1384{
1385 if (ft->c != NULL((void *)0))
1386 return (xstrdup(ft->c->ttyname));
1387 return (NULL((void *)0));
1388}
1389
1390/* Callback for client_utf8. */
1391static void *
1392format_cb_client_utf8(struct format_tree *ft)
1393{
1394 if (ft->c != NULL((void *)0)) {
1395 if (ft->c->flags & CLIENT_UTF80x10000)
1396 return (xstrdup("1"));
1397 return (xstrdup("0"));
1398 }
1399 return (NULL((void *)0));
1400}
1401
1402/* Callback for client_width. */
1403static void *
1404format_cb_client_width(struct format_tree *ft)
1405{
1406 if (ft->c != NULL((void *)0))
1407 return (format_printf("%u", ft->c->tty.sx));
1408 return (NULL((void *)0));
1409}
1410
1411/* Callback for client_written. */
1412static void *
1413format_cb_client_written(struct format_tree *ft)
1414{
1415 if (ft->c != NULL((void *)0))
1416 return (format_printf("%zu", ft->c->written));
1417 return (NULL((void *)0));
1418}
1419
1420/* Callback for config_files. */
1421static void *
1422format_cb_config_files(__unused__attribute__((__unused__)) struct format_tree *ft)
1423{
1424 char *s = NULL((void *)0);
1425 size_t slen = 0;
1426 u_int i;
1427 size_t n;
1428
1429 for (i = 0; i < cfg_nfiles; i++) {
1430 n = strlen(cfg_files[i]) + 1;
1431 s = xrealloc(s, slen + n + 1);
1432 slen += xsnprintf(s + slen, n + 1, "%s,", cfg_files[i]);
1433 }
1434 if (s == NULL((void *)0))
1435 return (xstrdup(""));
1436 s[slen - 1] = '\0';
1437 return (s);
1438}
1439
1440/* Callback for cursor_flag. */
1441static void *
1442format_cb_cursor_flag(struct format_tree *ft)
1443{
1444 if (ft->wp != NULL((void *)0)) {
1445 if (ft->wp->base.mode & MODE_CURSOR0x1)
1446 return (xstrdup("1"));
1447 return (xstrdup("0"));
1448 }
1449 return (NULL((void *)0));
1450}
1451
1452/* Callback for cursor_x. */
1453static void *
1454format_cb_cursor_x(struct format_tree *ft)
1455{
1456 if (ft->wp != NULL((void *)0))
1457 return (format_printf("%u", ft->wp->base.cx));
1458 return (NULL((void *)0));
1459}
1460
1461/* Callback for cursor_y. */
1462static void *
1463format_cb_cursor_y(struct format_tree *ft)
1464{
1465 if (ft->wp != NULL((void *)0))
1466 return (format_printf("%u", ft->wp->base.cy));
1467 return (NULL((void *)0));
1468}
1469
1470/* Callback for history_limit. */
1471static void *
1472format_cb_history_limit(struct format_tree *ft)
1473{
1474 if (ft->wp != NULL((void *)0))
1475 return (format_printf("%u", ft->wp->base.grid->hlimit));
1476 return (NULL((void *)0));
1477}
1478
1479/* Callback for history_size. */
1480static void *
1481format_cb_history_size(struct format_tree *ft)
1482{
1483 if (ft->wp != NULL((void *)0))
1484 return (format_printf("%u", ft->wp->base.grid->hsize));
1485 return (NULL((void *)0));
1486}
1487
1488/* Callback for insert_flag. */
1489static void *
1490format_cb_insert_flag(struct format_tree *ft)
1491{
1492 if (ft->wp != NULL((void *)0)) {
1493 if (ft->wp->base.mode & MODE_INSERT0x2)
1494 return (xstrdup("1"));
1495 return (xstrdup("0"));
1496 }
1497 return (NULL((void *)0));
1498}
1499
1500/* Callback for keypad_cursor_flag. */
1501static void *
1502format_cb_keypad_cursor_flag(struct format_tree *ft)
1503{
1504 if (ft->wp != NULL((void *)0)) {
1505 if (ft->wp->base.mode & MODE_KCURSOR0x4)
1506 return (xstrdup("1"));
1507 return (xstrdup("0"));
1508 }
1509 return (NULL((void *)0));
1510}
1511
1512/* Callback for keypad_flag. */
1513static void *
1514format_cb_keypad_flag(struct format_tree *ft)
1515{
1516 if (ft->wp != NULL((void *)0)) {
1517 if (ft->wp->base.mode & MODE_KKEYPAD0x8)
1518 return (xstrdup("1"));
1519 return (xstrdup("0"));
1520 }
1521 return (NULL((void *)0));
1522}
1523
1524/* Callback for mouse_all_flag. */
1525static void *
1526format_cb_mouse_all_flag(struct format_tree *ft)
1527{
1528 if (ft->wp != NULL((void *)0)) {
1529 if (ft->wp->base.mode & MODE_MOUSE_ALL0x1000)
1530 return (xstrdup("1"));
1531 return (xstrdup("0"));
1532 }
1533 return (NULL((void *)0));
1534}
1535
1536/* Callback for mouse_any_flag. */
1537static void *
1538format_cb_mouse_any_flag(struct format_tree *ft)
1539{
1540 if (ft->wp != NULL((void *)0)) {
1541 if (ft->wp->base.mode & ALL_MOUSE_MODES(0x20|0x40|0x1000))
1542 return (xstrdup("1"));
1543 return (xstrdup("0"));
1544 }
1545 return (NULL((void *)0));
1546}
1547
1548/* Callback for mouse_button_flag. */
1549static void *
1550format_cb_mouse_button_flag(struct format_tree *ft)
1551{
1552 if (ft->wp != NULL((void *)0)) {
1553 if (ft->wp->base.mode & MODE_MOUSE_BUTTON0x40)
1554 return (xstrdup("1"));
1555 return (xstrdup("0"));
1556 }
1557 return (NULL((void *)0));
1558}
1559
1560/* Callback for mouse_pane. */
1561static void *
1562format_cb_mouse_pane(struct format_tree *ft)
1563{
1564 struct window_pane *wp;
1565
1566 if (ft->m.valid) {
1567 wp = cmd_mouse_pane(&ft->m, NULL((void *)0), NULL((void *)0));
1568 if (wp != NULL((void *)0))
1569 return (format_printf("%%%u", wp->id));
1570 return (NULL((void *)0));
1571 }
1572 return (NULL((void *)0));
1573}
1574
1575/* Callback for mouse_sgr_flag. */
1576static void *
1577format_cb_mouse_sgr_flag(struct format_tree *ft)
1578{
1579 if (ft->wp != NULL((void *)0)) {
1580 if (ft->wp->base.mode & MODE_MOUSE_SGR0x200)
1581 return (xstrdup("1"));
1582 return (xstrdup("0"));
1583 }
1584 return (NULL((void *)0));
1585}
1586
1587/* Callback for mouse_standard_flag. */
1588static void *
1589format_cb_mouse_standard_flag(struct format_tree *ft)
1590{
1591 if (ft->wp != NULL((void *)0)) {
1592 if (ft->wp->base.mode & MODE_MOUSE_STANDARD0x20)
1593 return (xstrdup("1"));
1594 return (xstrdup("0"));
1595 }
1596 return (NULL((void *)0));
1597}
1598
1599/* Callback for mouse_utf8_flag. */
1600static void *
1601format_cb_mouse_utf8_flag(struct format_tree *ft)
1602{
1603 if (ft->wp != NULL((void *)0)) {
1604 if (ft->wp->base.mode & MODE_MOUSE_UTF80x100)
1605 return (xstrdup("1"));
1606 return (xstrdup("0"));
1607 }
1608 return (NULL((void *)0));
1609}
1610
1611/* Callback for mouse_x. */
1612static void *
1613format_cb_mouse_x(struct format_tree *ft)
1614{
1615 struct window_pane *wp;
1616 u_int x, y;
1617
1618 if (!ft->m.valid)
1619 return (NULL((void *)0));
1620 wp = cmd_mouse_pane(&ft->m, NULL((void *)0), NULL((void *)0));
1621 if (wp != NULL((void *)0) && cmd_mouse_at(wp, &ft->m, &x, &y, 0) == 0)
1622 return (format_printf("%u", x));
1623 if (ft->c != NULL((void *)0) && (ft->c->tty.flags & TTY_STARTED0x10)) {
1624 if (ft->m.statusat == 0 && ft->m.y < ft->m.statuslines)
1625 return (format_printf("%u", ft->m.x));
1626 if (ft->m.statusat > 0 && ft->m.y >= (u_int)ft->m.statusat)
1627 return (format_printf("%u", ft->m.x));
1628 }
1629 return (NULL((void *)0));
1630}
1631
1632/* Callback for mouse_y. */
1633static void *
1634format_cb_mouse_y(struct format_tree *ft)
1635{
1636 struct window_pane *wp;
1637 u_int x, y;
1638
1639 if (!ft->m.valid)
1640 return (NULL((void *)0));
1641 wp = cmd_mouse_pane(&ft->m, NULL((void *)0), NULL((void *)0));
1642 if (wp != NULL((void *)0) && cmd_mouse_at(wp, &ft->m, &x, &y, 0) == 0)
1643 return (format_printf("%u", y));
1644 if (ft->c != NULL((void *)0) && (ft->c->tty.flags & TTY_STARTED0x10)) {
1645 if (ft->m.statusat == 0 && ft->m.y < ft->m.statuslines)
1646 return (format_printf("%u", ft->m.y));
1647 if (ft->m.statusat > 0 && ft->m.y >= (u_int)ft->m.statusat)
1648 return (format_printf("%u", ft->m.y - ft->m.statusat));
1649 }
1650 return (NULL((void *)0));
1651}
1652
1653/* Callback for origin_flag. */
1654static void *
1655format_cb_origin_flag(struct format_tree *ft)
1656{
1657 if (ft->wp != NULL((void *)0)) {
1658 if (ft->wp->base.mode & MODE_ORIGIN0x2000)
1659 return (xstrdup("1"));
1660 return (xstrdup("0"));
1661 }
1662 return (NULL((void *)0));
1663}
1664
1665/* Callback for pane_active. */
1666static void *
1667format_cb_pane_active(struct format_tree *ft)
1668{
1669 if (ft->wp != NULL((void *)0)) {
1670 if (ft->wp == ft->wp->window->active)
1671 return (xstrdup("1"));
1672 return (xstrdup("0"));
1673 }
1674 return (NULL((void *)0));
1675}
1676
1677/* Callback for pane_at_left. */
1678static void *
1679format_cb_pane_at_left(struct format_tree *ft)
1680{
1681 if (ft->wp != NULL((void *)0)) {
1682 if (ft->wp->xoff == 0)
1683 return (xstrdup("1"));
1684 return (xstrdup("0"));
1685 }
1686 return (NULL((void *)0));
1687}
1688
1689/* Callback for pane_at_right. */
1690static void *
1691format_cb_pane_at_right(struct format_tree *ft)
1692{
1693 if (ft->wp != NULL((void *)0)) {
1694 if (ft->wp->xoff + ft->wp->sx == ft->wp->window->sx)
1695 return (xstrdup("1"));
1696 return (xstrdup("0"));
1697 }
1698 return (NULL((void *)0));
1699}
1700
1701/* Callback for pane_bottom. */
1702static void *
1703format_cb_pane_bottom(struct format_tree *ft)
1704{
1705 if (ft->wp != NULL((void *)0))
1706 return (format_printf("%u", ft->wp->yoff + ft->wp->sy - 1));
1707 return (NULL((void *)0));
1708}
1709
1710/* Callback for pane_dead. */
1711static void *
1712format_cb_pane_dead(struct format_tree *ft)
1713{
1714 if (ft->wp != NULL((void *)0)) {
1715 if (ft->wp->fd == -1)
1716 return (xstrdup("1"));
1717 return (xstrdup("0"));
1718 }
1719 return (NULL((void *)0));
1720}
1721
1722/* Callback for pane_dead_status. */
1723static void *
1724format_cb_pane_dead_status(struct format_tree *ft)
1725{
1726 struct window_pane *wp = ft->wp;
1727
1728 if (wp != NULL((void *)0)) {
1729 if ((wp->flags & PANE_STATUSREADY0x200) && WIFEXITED(wp->status)(((wp->status) & 0177) == 0))
1730 return (format_printf("%d", WEXITSTATUS(wp->status)(int)(((unsigned)(wp->status) >> 8) & 0xff)));
1731 return (NULL((void *)0));
1732 }
1733 return (NULL((void *)0));
1734}
1735
1736/* Callback for pane_format. */
1737static void *
1738format_cb_pane_format(struct format_tree *ft)
1739{
1740 if (ft->type == FORMAT_TYPE_PANE)
1741 return (xstrdup("1"));
1742 return (xstrdup("0"));
1743}
1744
1745/* Callback for pane_height. */
1746static void *
1747format_cb_pane_height(struct format_tree *ft)
1748{
1749 if (ft->wp != NULL((void *)0))
1750 return (format_printf("%u", ft->wp->sy));
1751 return (NULL((void *)0));
1752}
1753
1754/* Callback for pane_id. */
1755static void *
1756format_cb_pane_id(struct format_tree *ft)
1757{
1758 if (ft->wp != NULL((void *)0))
1759 return (format_printf("%%%u", ft->wp->id));
1760 return (NULL((void *)0));
1761}
1762
1763/* Callback for pane_index. */
1764static void *
1765format_cb_pane_index(struct format_tree *ft)
1766{
1767 u_int idx;
1768
1769 if (ft->wp != NULL((void *)0) && window_pane_index(ft->wp, &idx) == 0)
1770 return (format_printf("%u", idx));
1771 return (NULL((void *)0));
1772}
1773
1774/* Callback for pane_input_off. */
1775static void *
1776format_cb_pane_input_off(struct format_tree *ft)
1777{
1778 if (ft->wp != NULL((void *)0)) {
1779 if (ft->wp->flags & PANE_INPUTOFF0x40)
1780 return (xstrdup("1"));
1781 return (xstrdup("0"));
1782 }
1783 return (NULL((void *)0));
1784}
1785
1786/* Callback for pane_last. */
1787static void *
1788format_cb_pane_last(struct format_tree *ft)
1789{
1790 if (ft->wp != NULL((void *)0)) {
1791 if (ft->wp == ft->wp->window->last)
1792 return (xstrdup("1"));
1793 return (xstrdup("0"));
1794 }
1795 return (NULL((void *)0));
1796}
1797
1798/* Callback for pane_left. */
1799static void *
1800format_cb_pane_left(struct format_tree *ft)
1801{
1802 if (ft->wp != NULL((void *)0))
1803 return (format_printf("%u", ft->wp->xoff));
1804 return (NULL((void *)0));
1805}
1806
1807/* Callback for pane_marked. */
1808static void *
1809format_cb_pane_marked(struct format_tree *ft)
1810{
1811 if (ft->wp != NULL((void *)0)) {
1812 if (server_check_marked() && marked_pane.wp == ft->wp)
1813 return (xstrdup("1"));
1814 return (xstrdup("0"));
1815 }
1816 return (NULL((void *)0));
1817}
1818
1819/* Callback for pane_marked_set. */
1820static void *
1821format_cb_pane_marked_set(struct format_tree *ft)
1822{
1823 if (ft->wp != NULL((void *)0)) {
1824 if (server_check_marked())
1825 return (xstrdup("1"));
1826 return (xstrdup("0"));
1827 }
1828 return (NULL((void *)0));
1829}
1830
1831/* Callback for pane_mode. */
1832static void *
1833format_cb_pane_mode(struct format_tree *ft)
1834{
1835 struct window_mode_entry *wme;
1836
1837 if (ft->wp != NULL((void *)0)) {
1838 wme = TAILQ_FIRST(&ft->wp->modes)((&ft->wp->modes)->tqh_first);
1839 if (wme != NULL((void *)0))
1840 return (xstrdup(wme->mode->name));
1841 return (NULL((void *)0));
1842 }
1843 return (NULL((void *)0));
1844}
1845
1846/* Callback for pane_path. */
1847static void *
1848format_cb_pane_path(struct format_tree *ft)
1849{
1850 if (ft->wp != NULL((void *)0)) {
1851 if (ft->wp->base.path == NULL((void *)0))
1852 return (xstrdup(""));
1853 return (xstrdup(ft->wp->base.path));
1854 }
1855 return (NULL((void *)0));
1856}
1857
1858/* Callback for pane_pid. */
1859static void *
1860format_cb_pane_pid(struct format_tree *ft)
1861{
1862 if (ft->wp != NULL((void *)0))
1863 return (format_printf("%ld", (long)ft->wp->pid));
1864 return (NULL((void *)0));
1865}
1866
1867/* Callback for pane_pipe. */
1868static void *
1869format_cb_pane_pipe(struct format_tree *ft)
1870{
1871 if (ft->wp != NULL((void *)0)) {
1872 if (ft->wp->pipe_fd != -1)
1873 return (xstrdup("1"));
1874 return (xstrdup("0"));
1875 }
1876 return (NULL((void *)0));
1877}
1878
1879/* Callback for pane_right. */
1880static void *
1881format_cb_pane_right(struct format_tree *ft)
1882{
1883 if (ft->wp != NULL((void *)0))
1884 return (format_printf("%u", ft->wp->xoff + ft->wp->sx - 1));
1885 return (NULL((void *)0));
1886}
1887
1888/* Callback for pane_search_string. */
1889static void *
1890format_cb_pane_search_string(struct format_tree *ft)
1891{
1892 if (ft->wp != NULL((void *)0)) {
1893 if (ft->wp->searchstr == NULL((void *)0))
1894 return (xstrdup(""));
1895 return (xstrdup(ft->wp->searchstr));
1896 }
1897 return (NULL((void *)0));
1898}
1899
1900/* Callback for pane_synchronized. */
1901static void *
1902format_cb_pane_synchronized(struct format_tree *ft)
1903{
1904 if (ft->wp != NULL((void *)0)) {
1905 if (options_get_number(ft->wp->options, "synchronize-panes"))
1906 return (xstrdup("1"));
1907 return (xstrdup("0"));
1908 }
1909 return (NULL((void *)0));
1910}
1911
1912/* Callback for pane_title. */
1913static void *
1914format_cb_pane_title(struct format_tree *ft)
1915{
1916 if (ft->wp != NULL((void *)0))
1917 return (xstrdup(ft->wp->base.title));
1918 return (NULL((void *)0));
1919}
1920
1921/* Callback for pane_top. */
1922static void *
1923format_cb_pane_top(struct format_tree *ft)
1924{
1925 if (ft->wp != NULL((void *)0))
1926 return (format_printf("%u", ft->wp->yoff));
1927 return (NULL((void *)0));
1928}
1929
1930/* Callback for pane_tty. */
1931static void *
1932format_cb_pane_tty(struct format_tree *ft)
1933{
1934 if (ft->wp != NULL((void *)0))
1935 return (xstrdup(ft->wp->tty));
1936 return (NULL((void *)0));
1937}
1938
1939/* Callback for pane_width. */
1940static void *
1941format_cb_pane_width(struct format_tree *ft)
1942{
1943 if (ft->wp != NULL((void *)0))
1944 return (format_printf("%u", ft->wp->sx));
1945 return (NULL((void *)0));
1946}
1947
1948/* Callback for scroll_region_lower. */
1949static void *
1950format_cb_scroll_region_lower(struct format_tree *ft)
1951{
1952 if (ft->wp != NULL((void *)0))
1953 return (format_printf("%u", ft->wp->base.rlower));
1954 return (NULL((void *)0));
1955}
1956
1957/* Callback for scroll_region_upper. */
1958static void *
1959format_cb_scroll_region_upper(struct format_tree *ft)
1960{
1961 if (ft->wp != NULL((void *)0))
1962 return (format_printf("%u", ft->wp->base.rupper));
1963 return (NULL((void *)0));
1964}
1965
1966/* Callback for session_attached. */
1967static void *
1968format_cb_session_attached(struct format_tree *ft)
1969{
1970 if (ft->s != NULL((void *)0))
1971 return (format_printf("%u", ft->s->attached));
1972 return (NULL((void *)0));
1973}
1974
1975/* Callback for session_format. */
1976static void *
1977format_cb_session_format(struct format_tree *ft)
1978{
1979 if (ft->type == FORMAT_TYPE_SESSION)
1980 return (xstrdup("1"));
1981 return (xstrdup("0"));
1982}
1983
1984/* Callback for session_group. */
1985static void *
1986format_cb_session_group(struct format_tree *ft)
1987{
1988 struct session_group *sg;
1989
1990 if (ft->s != NULL((void *)0) && (sg = session_group_contains(ft->s)) != NULL((void *)0))
1991 return (xstrdup(sg->name));
1992 return (NULL((void *)0));
1993}
1994
1995/* Callback for session_group_attached. */
1996static void *
1997format_cb_session_group_attached(struct format_tree *ft)
1998{
1999 struct session_group *sg;
2000
2001 if (ft->s != NULL((void *)0) && (sg = session_group_contains(ft->s)) != NULL((void *)0))
2002 return (format_printf("%u", session_group_attached_count (sg)));
2003 return (NULL((void *)0));
2004}
2005
2006/* Callback for session_group_many_attached. */
2007static void *
2008format_cb_session_group_many_attached(struct format_tree *ft)
2009{
2010 struct session_group *sg;
2011
2012 if (ft->s != NULL((void *)0) && (sg = session_group_contains(ft->s)) != NULL((void *)0)) {
2013 if (session_group_attached_count (sg) > 1)
2014 return (xstrdup("1"));
2015 return (xstrdup("0"));
2016 }
2017 return (NULL((void *)0));
2018}
2019
2020/* Callback for session_group_size. */
2021static void *
2022format_cb_session_group_size(struct format_tree *ft)
2023{
2024 struct session_group *sg;
2025
2026 if (ft->s != NULL((void *)0) && (sg = session_group_contains(ft->s)) != NULL((void *)0))
2027 return (format_printf("%u", session_group_count (sg)));
2028 return (NULL((void *)0));
2029}
2030
2031/* Callback for session_grouped. */
2032static void *
2033format_cb_session_grouped(struct format_tree *ft)
2034{
2035 if (ft->s != NULL((void *)0)) {
2036 if (session_group_contains(ft->s) != NULL((void *)0))
2037 return (xstrdup("1"));
2038 return (xstrdup("0"));
2039 }
2040 return (NULL((void *)0));
2041}
2042
2043/* Callback for session_id. */
2044static void *
2045format_cb_session_id(struct format_tree *ft)
2046{
2047 if (ft->s != NULL((void *)0))
2048 return (format_printf("$%u", ft->s->id));
2049 return (NULL((void *)0));
2050}
2051
2052/* Callback for session_many_attached. */
2053static void *
2054format_cb_session_many_attached(struct format_tree *ft)
2055{
2056 if (ft->s != NULL((void *)0)) {
2057 if (ft->s->attached > 1)
2058 return (xstrdup("1"));
2059 return (xstrdup("0"));
2060 }
2061 return (NULL((void *)0));
2062}
2063
2064/* Callback for session_marked. */
2065static void *
2066format_cb_session_marked(struct format_tree *ft)
2067{
2068 if (ft->s != NULL((void *)0)) {
2069 if (server_check_marked() && marked_pane.s == ft->s)
2070 return (xstrdup("1"));
2071 return (xstrdup("0"));
2072 }
2073 return (NULL((void *)0));
2074}
2075
2076/* Callback for session_name. */
2077static void *
2078format_cb_session_name(struct format_tree *ft)
2079{
2080 if (ft->s != NULL((void *)0))
2081 return (xstrdup(ft->s->name));
2082 return (NULL((void *)0));
2083}
2084
2085/* Callback for session_path. */
2086static void *
2087format_cb_session_path(struct format_tree *ft)
2088{
2089 if (ft->s != NULL((void *)0))
2090 return (xstrdup(ft->s->cwd));
2091 return (NULL((void *)0));
2092}
2093
2094/* Callback for session_windows. */
2095static void *
2096format_cb_session_windows(struct format_tree *ft)
2097{
2098 if (ft->s != NULL((void *)0))
2099 return (format_printf("%u", winlink_count(&ft->s->windows)));
2100 return (NULL((void *)0));
2101}
2102
2103/* Callback for socket_path. */
2104static void *
2105format_cb_socket_path(__unused__attribute__((__unused__)) struct format_tree *ft)
2106{
2107 return (xstrdup(socket_path));
2108}
2109
2110/* Callback for version. */
2111static void *
2112format_cb_version(__unused__attribute__((__unused__)) struct format_tree *ft)
2113{
2114 return (xstrdup(getversion()));
2115}
2116
2117/* Callback for active_window_index. */
2118static void *
2119format_cb_active_window_index(struct format_tree *ft)
2120{
2121 if (ft->s != NULL((void *)0))
2122 return (format_printf("%u", ft->s->curw->idx));
2123 return (NULL((void *)0));
2124}
2125
2126/* Callback for last_window_index. */
2127static void *
2128format_cb_last_window_index(struct format_tree *ft)
2129{
2130 struct winlink *wl;
2131
2132 if (ft->s != NULL((void *)0)) {
2133 wl = RB_MAX(winlinks, &ft->s->windows)winlinks_RB_MINMAX(&ft->s->windows, 1);
2134 return (format_printf("%u", wl->idx));
2135 }
2136 return (NULL((void *)0));
2137}
2138
2139/* Callback for window_active. */
2140static void *
2141format_cb_window_active(struct format_tree *ft)
2142{
2143 if (ft->wl != NULL((void *)0)) {
2144 if (ft->wl == ft->wl->session->curw)
2145 return (xstrdup("1"));
2146 return (xstrdup("0"));
2147 }
2148 return (NULL((void *)0));
2149}
2150
2151/* Callback for window_activity_flag. */
2152static void *
2153format_cb_window_activity_flag(struct format_tree *ft)
2154{
2155 if (ft->wl != NULL((void *)0)) {
2156 if (ft->wl->flags & WINLINK_ACTIVITY0x2)
2157 return (xstrdup("1"));
2158 return (xstrdup("0"));
2159 }
2160 return (NULL((void *)0));
2161}
2162
2163/* Callback for window_bell_flag. */
2164static void *
2165format_cb_window_bell_flag(struct format_tree *ft)
2166{
2167 if (ft->wl != NULL((void *)0)) {
2168 if (ft->wl->flags & WINLINK_BELL0x1)
2169 return (xstrdup("1"));
2170 return (xstrdup("0"));
2171 }
2172 return (NULL((void *)0));
2173}
2174
2175/* Callback for window_bigger. */
2176static void *
2177format_cb_window_bigger(struct format_tree *ft)
2178{
2179 u_int ox, oy, sx, sy;
2180
2181 if (ft->c != NULL((void *)0)) {
2182 if (tty_window_offset(&ft->c->tty, &ox, &oy, &sx, &sy))
2183 return (xstrdup("1"));
2184 return (xstrdup("0"));
2185 }
2186 return (NULL((void *)0));
2187}
2188
2189/* Callback for window_cell_height. */
2190static void *
2191format_cb_window_cell_height(struct format_tree *ft)
2192{
2193 if (ft->w != NULL((void *)0))
2194 return (format_printf("%u", ft->w->ypixel));
2195 return (NULL((void *)0));
2196}
2197
2198/* Callback for window_cell_width. */
2199static void *
2200format_cb_window_cell_width(struct format_tree *ft)
2201{
2202 if (ft->w != NULL((void *)0))
2203 return (format_printf("%u", ft->w->xpixel));
2204 return (NULL((void *)0));
2205}
2206
2207/* Callback for window_end_flag. */
2208static void *
2209format_cb_window_end_flag(struct format_tree *ft)
2210{
2211 if (ft->wl != NULL((void *)0)) {
2212 if (ft->wl == RB_MAX(winlinks, &ft->wl->session->windows)winlinks_RB_MINMAX(&ft->wl->session->windows, 1))
2213 return (xstrdup("1"));
2214 return (xstrdup("0"));
2215 }
2216 return (NULL((void *)0));
2217}
2218
2219/* Callback for window_flags. */
2220static void *
2221format_cb_window_flags(struct format_tree *ft)
2222{
2223 if (ft->wl != NULL((void *)0))
2224 return (xstrdup(window_printable_flags(ft->wl, 1)));
2225 return (NULL((void *)0));
2226}
2227
2228/* Callback for window_format. */
2229static void *
2230format_cb_window_format(struct format_tree *ft)
2231{
2232 if (ft->type == FORMAT_TYPE_WINDOW)
2233 return (xstrdup("1"));
2234 return (xstrdup("0"));
2235}
2236
2237/* Callback for window_height. */
2238static void *
2239format_cb_window_height(struct format_tree *ft)
2240{
2241 if (ft->w != NULL((void *)0))
2242 return (format_printf("%u", ft->w->sy));
2243 return (NULL((void *)0));
2244}
2245
2246/* Callback for window_id. */
2247static void *
2248format_cb_window_id(struct format_tree *ft)
2249{
2250 if (ft->w != NULL((void *)0))
2251 return (format_printf("@%u", ft->w->id));
2252 return (NULL((void *)0));
2253}
2254
2255/* Callback for window_index. */
2256static void *
2257format_cb_window_index(struct format_tree *ft)
2258{
2259 if (ft->wl != NULL((void *)0))
2260 return (format_printf("%d", ft->wl->idx));
2261 return (NULL((void *)0));
2262}
2263
2264/* Callback for window_last_flag. */
2265static void *
2266format_cb_window_last_flag(struct format_tree *ft)
2267{
2268 if (ft->wl != NULL((void *)0)) {
2269 if (ft->wl == TAILQ_FIRST(&ft->wl->session->lastw)((&ft->wl->session->lastw)->tqh_first))
2270 return (xstrdup("1"));
2271 return (xstrdup("0"));
2272 }
2273 return (NULL((void *)0));
2274}
2275
2276/* Callback for window_linked. */
2277static void *
2278format_cb_window_linked(struct format_tree *ft)
2279{
2280 if (ft->wl != NULL((void *)0)) {
2281 if (session_is_linked(ft->wl->session, ft->wl->window))
2282 return (xstrdup("1"));
2283 return (xstrdup("0"));
2284 }
2285 return (NULL((void *)0));
2286}
2287
2288/* Callback for window_linked_sessions. */
2289static void *
2290format_cb_window_linked_sessions(struct format_tree *ft)
2291{
2292 if (ft->wl != NULL((void *)0))
2293 return (format_printf("%u", ft->wl->window->references));
2294 return (NULL((void *)0));
2295}
2296
2297/* Callback for window_marked_flag. */
2298static void *
2299format_cb_window_marked_flag(struct format_tree *ft)
2300{
2301 if (ft->wl != NULL((void *)0)) {
2302 if (server_check_marked() && marked_pane.wl == ft->wl)
2303 return (xstrdup("1"));
2304 return (xstrdup("0"));
2305 }
2306 return (NULL((void *)0));
2307}
2308
2309/* Callback for window_name. */
2310static void *
2311format_cb_window_name(struct format_tree *ft)
2312{
2313 if (ft->w != NULL((void *)0))
2314 return (format_printf("%s", ft->w->name));
2315 return (NULL((void *)0));
2316}
2317
2318/* Callback for window_offset_x. */
2319static void *
2320format_cb_window_offset_x(struct format_tree *ft)
2321{
2322 u_int ox, oy, sx, sy;
2323
2324 if (ft->c != NULL((void *)0)) {
2325 if (tty_window_offset(&ft->c->tty, &ox, &oy, &sx, &sy))
2326 return (format_printf("%u", ox));
2327 return (NULL((void *)0));
2328 }
2329 return (NULL((void *)0));
2330}
2331
2332/* Callback for window_offset_y. */
2333static void *
2334format_cb_window_offset_y(struct format_tree *ft)
2335{
2336 u_int ox, oy, sx, sy;
2337
2338 if (ft->c != NULL((void *)0)) {
2339 if (tty_window_offset(&ft->c->tty, &ox, &oy, &sx, &sy))
2340 return (format_printf("%u", oy));
2341 return (NULL((void *)0));
2342 }
2343 return (NULL((void *)0));
2344}
2345
2346/* Callback for window_panes. */
2347static void *
2348format_cb_window_panes(struct format_tree *ft)
2349{
2350 if (ft->w != NULL((void *)0))
2351 return (format_printf("%u", window_count_panes(ft->w)));
2352 return (NULL((void *)0));
2353}
2354
2355/* Callback for window_raw_flags. */
2356static void *
2357format_cb_window_raw_flags(struct format_tree *ft)
2358{
2359 if (ft->wl != NULL((void *)0))
2360 return (xstrdup(window_printable_flags(ft->wl, 0)));
2361 return (NULL((void *)0));
2362}
2363
2364/* Callback for window_silence_flag. */
2365static void *
2366format_cb_window_silence_flag(struct format_tree *ft)
2367{
2368 if (ft->wl != NULL((void *)0)) {
2369 if (ft->wl->flags & WINLINK_SILENCE0x4)
2370 return (xstrdup("1"));
2371 return (xstrdup("0"));
2372 }
2373 return (NULL((void *)0));
2374}
2375
2376/* Callback for window_start_flag. */
2377static void *
2378format_cb_window_start_flag(struct format_tree *ft)
2379{
2380 if (ft->wl != NULL((void *)0)) {
2381 if (ft->wl == RB_MIN(winlinks, &ft->wl->session->windows)winlinks_RB_MINMAX(&ft->wl->session->windows, -1
)
)
2382 return (xstrdup("1"));
2383 return (xstrdup("0"));
2384 }
2385 return (NULL((void *)0));
2386}
2387
2388/* Callback for window_width. */
2389static void *
2390format_cb_window_width(struct format_tree *ft)
2391{
2392 if (ft->w != NULL((void *)0))
2393 return (format_printf("%u", ft->w->sx));
2394 return (NULL((void *)0));
2395}
2396
2397/* Callback for window_zoomed_flag. */
2398static void *
2399format_cb_window_zoomed_flag(struct format_tree *ft)
2400{
2401 if (ft->w != NULL((void *)0)) {
2402 if (ft->w->flags & WINDOW_ZOOMED0x8)
2403 return (xstrdup("1"));
2404 return (xstrdup("0"));
2405 }
2406 return (NULL((void *)0));
2407}
2408
2409/* Callback for wrap_flag. */
2410static void *
2411format_cb_wrap_flag(struct format_tree *ft)
2412{
2413 if (ft->wp != NULL((void *)0)) {
2414 if (ft->wp->base.mode & MODE_WRAP0x10)
2415 return (xstrdup("1"));
2416 return (xstrdup("0"));
2417 }
2418 return (NULL((void *)0));
2419}
2420
2421/* Callback for buffer_created. */
2422static void *
2423format_cb_buffer_created(struct format_tree *ft)
2424{
2425 static struct timeval tv;
2426
2427 if (ft->pb != NULL((void *)0)) {
2428 timerclear(&tv)(&tv)->tv_sec = (&tv)->tv_usec = 0;
2429 tv.tv_sec = paste_buffer_created(ft->pb);
2430 return (&tv);
2431 }
2432 return (NULL((void *)0));
2433}
2434
2435/* Callback for client_activity. */
2436static void *
2437format_cb_client_activity(struct format_tree *ft)
2438{
2439 if (ft->c != NULL((void *)0))
2440 return (&ft->c->activity_time);
2441 return (NULL((void *)0));
2442}
2443
2444/* Callback for client_created. */
2445static void *
2446format_cb_client_created(struct format_tree *ft)
2447{
2448 if (ft->c != NULL((void *)0))
2449 return (&ft->c->creation_time);
2450 return (NULL((void *)0));
2451}
2452
2453/* Callback for session_activity. */
2454static void *
2455format_cb_session_activity(struct format_tree *ft)
2456{
2457 if (ft->s != NULL((void *)0))
2458 return (&ft->s->activity_time);
2459 return (NULL((void *)0));
2460}
2461
2462/* Callback for session_created. */
2463static void *
2464format_cb_session_created(struct format_tree *ft)
2465{
2466 if (ft->s != NULL((void *)0))
2467 return (&ft->s->creation_time);
2468 return (NULL((void *)0));
2469}
2470
2471/* Callback for session_last_attached. */
2472static void *
2473format_cb_session_last_attached(struct format_tree *ft)
2474{
2475 if (ft->s != NULL((void *)0))
2476 return (&ft->s->last_attached_time);
2477 return (NULL((void *)0));
2478}
2479
2480/* Callback for start_time. */
2481static void *
2482format_cb_start_time(__unused__attribute__((__unused__)) struct format_tree *ft)
2483{
2484 return (&start_time);
2485}
2486
2487/* Callback for window_activity. */
2488static void *
2489format_cb_window_activity(struct format_tree *ft)
2490{
2491 if (ft->w != NULL((void *)0))
2492 return (&ft->w->activity_time);
2493 return (NULL((void *)0));
2494}
2495
2496/* Callback for buffer_mode_format, */
2497static void *
2498format_cb_buffer_mode_format(__unused__attribute__((__unused__)) struct format_tree *ft)
2499{
2500 return (xstrdup(window_buffer_mode.default_format));
2501}
2502
2503/* Callback for client_mode_format, */
2504static void *
2505format_cb_client_mode_format(__unused__attribute__((__unused__)) struct format_tree *ft)
2506{
2507 return (xstrdup(window_client_mode.default_format));
2508}
2509
2510/* Callback for tree_mode_format, */
2511static void *
2512format_cb_tree_mode_format(__unused__attribute__((__unused__)) struct format_tree *ft)
2513{
2514 return (xstrdup(window_tree_mode.default_format));
2515}
2516
2517/* Format table type. */
2518enum format_table_type {
2519 FORMAT_TABLE_STRING,
2520 FORMAT_TABLE_TIME
2521};
2522
2523/* Format table entry. */
2524struct format_table_entry {
2525 const char *key;
2526 enum format_table_type type;
2527 format_cb cb;
2528};
2529
2530/*
2531 * Format table. Default format variables (that are almost always in the tree
2532 * and where the value is expanded by a callback in this file) are listed here.
2533 * Only variables which are added by the caller go into the tree.
2534 */
2535static const struct format_table_entry format_table[] = {
2536 { "active_window_index", FORMAT_TABLE_STRING,
2537 format_cb_active_window_index
2538 },
2539 { "alternate_on", FORMAT_TABLE_STRING,
2540 format_cb_alternate_on
2541 },
2542 { "alternate_saved_x", FORMAT_TABLE_STRING,
2543 format_cb_alternate_saved_x
2544 },
2545 { "alternate_saved_y", FORMAT_TABLE_STRING,
2546 format_cb_alternate_saved_y
2547 },
2548 { "buffer_created", FORMAT_TABLE_TIME,
2549 format_cb_buffer_created
2550 },
2551 { "buffer_mode_format", FORMAT_TABLE_STRING,
2552 format_cb_buffer_mode_format
2553 },
2554 { "buffer_name", FORMAT_TABLE_STRING,
2555 format_cb_buffer_name
2556 },
2557 { "buffer_sample", FORMAT_TABLE_STRING,
2558 format_cb_buffer_sample
2559 },
2560 { "buffer_size", FORMAT_TABLE_STRING,
2561 format_cb_buffer_size
2562 },
2563 { "client_activity", FORMAT_TABLE_TIME,
2564 format_cb_client_activity
2565 },
2566 { "client_cell_height", FORMAT_TABLE_STRING,
2567 format_cb_client_cell_height
2568 },
2569 { "client_cell_width", FORMAT_TABLE_STRING,
2570 format_cb_client_cell_width
2571 },
2572 { "client_control_mode", FORMAT_TABLE_STRING,
2573 format_cb_client_control_mode
2574 },
2575 { "client_created", FORMAT_TABLE_TIME,
2576 format_cb_client_created
2577 },
2578 { "client_discarded", FORMAT_TABLE_STRING,
2579 format_cb_client_discarded
2580 },
2581 { "client_flags", FORMAT_TABLE_STRING,
2582 format_cb_client_flags
2583 },
2584 { "client_height", FORMAT_TABLE_STRING,
2585 format_cb_client_height
2586 },
2587 { "client_key_table", FORMAT_TABLE_STRING,
2588 format_cb_client_key_table
2589 },
2590 { "client_last_session", FORMAT_TABLE_STRING,
2591 format_cb_client_last_session
2592 },
2593 { "client_mode_format", FORMAT_TABLE_STRING,
2594 format_cb_client_mode_format
2595 },
2596 { "client_name", FORMAT_TABLE_STRING,
2597 format_cb_client_name
2598 },
2599 { "client_pid", FORMAT_TABLE_STRING,
2600 format_cb_client_pid
2601 },
2602 { "client_prefix", FORMAT_TABLE_STRING,
2603 format_cb_client_prefix
2604 },
2605 { "client_readonly", FORMAT_TABLE_STRING,
2606 format_cb_client_readonly
2607 },
2608 { "client_session", FORMAT_TABLE_STRING,
2609 format_cb_client_session
2610 },
2611 { "client_termfeatures", FORMAT_TABLE_STRING,
2612 format_cb_client_termfeatures
2613 },
2614 { "client_termname", FORMAT_TABLE_STRING,
2615 format_cb_client_termname
2616 },
2617 { "client_termtype", FORMAT_TABLE_STRING,
2618 format_cb_client_termtype
2619 },
2620 { "client_tty", FORMAT_TABLE_STRING,
2621 format_cb_client_tty
2622 },
2623 { "client_utf8", FORMAT_TABLE_STRING,
2624 format_cb_client_utf8
2625 },
2626 { "client_width", FORMAT_TABLE_STRING,
2627 format_cb_client_width
2628 },
2629 { "client_written", FORMAT_TABLE_STRING,
2630 format_cb_client_written
2631 },
2632 { "config_files", FORMAT_TABLE_STRING,
2633 format_cb_config_files
2634 },
2635 { "cursor_character", FORMAT_TABLE_STRING,
2636 format_cb_cursor_character
2637 },
2638 { "cursor_flag", FORMAT_TABLE_STRING,
2639 format_cb_cursor_flag
2640 },
2641 { "cursor_x", FORMAT_TABLE_STRING,
2642 format_cb_cursor_x
2643 },
2644 { "cursor_y", FORMAT_TABLE_STRING,
2645 format_cb_cursor_y
2646 },
2647 { "history_all_bytes", FORMAT_TABLE_STRING,
2648 format_cb_history_all_bytes
2649 },
2650 { "history_bytes", FORMAT_TABLE_STRING,
2651 format_cb_history_bytes
2652 },
2653 { "history_limit", FORMAT_TABLE_STRING,
2654 format_cb_history_limit
2655 },
2656 { "history_size", FORMAT_TABLE_STRING,
2657 format_cb_history_size
2658 },
2659 { "host", FORMAT_TABLE_STRING,
2660 format_cb_host
2661 },
2662 { "host_short", FORMAT_TABLE_STRING,
2663 format_cb_host_short
2664 },
2665 { "insert_flag", FORMAT_TABLE_STRING,
2666 format_cb_insert_flag
2667 },
2668 { "keypad_cursor_flag", FORMAT_TABLE_STRING,
2669 format_cb_keypad_cursor_flag
2670 },
2671 { "keypad_flag", FORMAT_TABLE_STRING,
2672 format_cb_keypad_flag
2673 },
2674 { "last_window_index", FORMAT_TABLE_STRING,
2675 format_cb_last_window_index
2676 },
2677 { "mouse_all_flag", FORMAT_TABLE_STRING,
2678 format_cb_mouse_all_flag
2679 },
2680 { "mouse_any_flag", FORMAT_TABLE_STRING,
2681 format_cb_mouse_any_flag
2682 },
2683 { "mouse_button_flag", FORMAT_TABLE_STRING,
2684 format_cb_mouse_button_flag
2685 },
2686 { "mouse_line", FORMAT_TABLE_STRING,
2687 format_cb_mouse_line
2688 },
2689 { "mouse_pane", FORMAT_TABLE_STRING,
2690 format_cb_mouse_pane
2691 },
2692 { "mouse_sgr_flag", FORMAT_TABLE_STRING,
2693 format_cb_mouse_sgr_flag
2694 },
2695 { "mouse_standard_flag", FORMAT_TABLE_STRING,
2696 format_cb_mouse_standard_flag
2697 },
2698 { "mouse_utf8_flag", FORMAT_TABLE_STRING,
2699 format_cb_mouse_utf8_flag
2700 },
2701 { "mouse_word", FORMAT_TABLE_STRING,
2702 format_cb_mouse_word
2703 },
2704 { "mouse_x", FORMAT_TABLE_STRING,
2705 format_cb_mouse_x
2706 },
2707 { "mouse_y", FORMAT_TABLE_STRING,
2708 format_cb_mouse_y
2709 },
2710 { "origin_flag", FORMAT_TABLE_STRING,
2711 format_cb_origin_flag
2712 },
2713 { "pane_active", FORMAT_TABLE_STRING,
2714 format_cb_pane_active
2715 },
2716 { "pane_at_bottom", FORMAT_TABLE_STRING,
2717 format_cb_pane_at_bottom
2718 },
2719 { "pane_at_left", FORMAT_TABLE_STRING,
2720 format_cb_pane_at_left
2721 },
2722 { "pane_at_right", FORMAT_TABLE_STRING,
2723 format_cb_pane_at_right
2724 },
2725 { "pane_at_top", FORMAT_TABLE_STRING,
2726 format_cb_pane_at_top
2727 },
2728 { "pane_bg", FORMAT_TABLE_STRING,
2729 format_cb_pane_bg
2730 },
2731 { "pane_bottom", FORMAT_TABLE_STRING,
2732 format_cb_pane_bottom
2733 },
2734 { "pane_current_command", FORMAT_TABLE_STRING,
2735 format_cb_current_command
2736 },
2737 { "pane_current_path", FORMAT_TABLE_STRING,
2738 format_cb_current_path
2739 },
2740 { "pane_dead", FORMAT_TABLE_STRING,
2741 format_cb_pane_dead
2742 },
2743 { "pane_dead_status", FORMAT_TABLE_STRING,
2744 format_cb_pane_dead_status
2745 },
2746 { "pane_fg", FORMAT_TABLE_STRING,
2747 format_cb_pane_fg
2748 },
2749 { "pane_format", FORMAT_TABLE_STRING,
2750 format_cb_pane_format
2751 },
2752 { "pane_height", FORMAT_TABLE_STRING,
2753 format_cb_pane_height
2754 },
2755 { "pane_id", FORMAT_TABLE_STRING,
2756 format_cb_pane_id
2757 },
2758 { "pane_in_mode", FORMAT_TABLE_STRING,
2759 format_cb_pane_in_mode
2760 },
2761 { "pane_index", FORMAT_TABLE_STRING,
2762 format_cb_pane_index
2763 },
2764 { "pane_input_off", FORMAT_TABLE_STRING,
2765 format_cb_pane_input_off
2766 },
2767 { "pane_last", FORMAT_TABLE_STRING,
2768 format_cb_pane_last
2769 },
2770 { "pane_left", FORMAT_TABLE_STRING,
2771 format_cb_pane_left
2772 },
2773 { "pane_marked", FORMAT_TABLE_STRING,
2774 format_cb_pane_marked
2775 },
2776 { "pane_marked_set", FORMAT_TABLE_STRING,
2777 format_cb_pane_marked_set
2778 },
2779 { "pane_mode", FORMAT_TABLE_STRING,
2780 format_cb_pane_mode
2781 },
2782 { "pane_path", FORMAT_TABLE_STRING,
2783 format_cb_pane_path
2784 },
2785 { "pane_pid", FORMAT_TABLE_STRING,
2786 format_cb_pane_pid
2787 },
2788 { "pane_pipe", FORMAT_TABLE_STRING,
2789 format_cb_pane_pipe
2790 },
2791 { "pane_right", FORMAT_TABLE_STRING,
2792 format_cb_pane_right
2793 },
2794 { "pane_search_string", FORMAT_TABLE_STRING,
2795 format_cb_pane_search_string
2796 },
2797 { "pane_start_command", FORMAT_TABLE_STRING,
2798 format_cb_start_command
2799 },
2800 { "pane_synchronized", FORMAT_TABLE_STRING,
2801 format_cb_pane_synchronized
2802 },
2803 { "pane_tabs", FORMAT_TABLE_STRING,
2804 format_cb_pane_tabs
2805 },
2806 { "pane_title", FORMAT_TABLE_STRING,
2807 format_cb_pane_title
2808 },
2809 { "pane_top", FORMAT_TABLE_STRING,
2810 format_cb_pane_top
2811 },
2812 { "pane_tty", FORMAT_TABLE_STRING,
2813 format_cb_pane_tty
2814 },
2815 { "pane_width", FORMAT_TABLE_STRING,
2816 format_cb_pane_width
2817 },
2818 { "pid", FORMAT_TABLE_STRING,
2819 format_cb_pid
2820 },
2821 { "scroll_region_lower", FORMAT_TABLE_STRING,
2822 format_cb_scroll_region_lower
2823 },
2824 { "scroll_region_upper", FORMAT_TABLE_STRING,
2825 format_cb_scroll_region_upper
2826 },
2827 { "session_activity", FORMAT_TABLE_TIME,
2828 format_cb_session_activity
2829 },
2830 { "session_alerts", FORMAT_TABLE_STRING,
2831 format_cb_session_alerts
2832 },
2833 { "session_attached", FORMAT_TABLE_STRING,
2834 format_cb_session_attached
2835 },
2836 { "session_attached_list", FORMAT_TABLE_STRING,
2837 format_cb_session_attached_list
2838 },
2839 { "session_created", FORMAT_TABLE_TIME,
2840 format_cb_session_created
2841 },
2842 { "session_format", FORMAT_TABLE_STRING,
2843 format_cb_session_format
2844 },
2845 { "session_group", FORMAT_TABLE_STRING,
2846 format_cb_session_group
2847 },
2848 { "session_group_attached", FORMAT_TABLE_STRING,
2849 format_cb_session_group_attached
2850 },
2851 { "session_group_attached_list", FORMAT_TABLE_STRING,
2852 format_cb_session_group_attached_list
2853 },
2854 { "session_group_list", FORMAT_TABLE_STRING,
2855 format_cb_session_group_list
2856 },
2857 { "session_group_many_attached", FORMAT_TABLE_STRING,
2858 format_cb_session_group_many_attached
2859 },
2860 { "session_group_size", FORMAT_TABLE_STRING,
2861 format_cb_session_group_size
2862 },
2863 { "session_grouped", FORMAT_TABLE_STRING,
2864 format_cb_session_grouped
2865 },
2866 { "session_id", FORMAT_TABLE_STRING,
2867 format_cb_session_id
2868 },
2869 { "session_last_attached", FORMAT_TABLE_TIME,
2870 format_cb_session_last_attached
2871 },
2872 { "session_many_attached", FORMAT_TABLE_STRING,
2873 format_cb_session_many_attached
2874 },
2875 { "session_marked", FORMAT_TABLE_STRING,
2876 format_cb_session_marked,
2877 },
2878 { "session_name", FORMAT_TABLE_STRING,
2879 format_cb_session_name
2880 },
2881 { "session_path", FORMAT_TABLE_STRING,
2882 format_cb_session_path
2883 },
2884 { "session_stack", FORMAT_TABLE_STRING,
2885 format_cb_session_stack
2886 },
2887 { "session_windows", FORMAT_TABLE_STRING,
2888 format_cb_session_windows
2889 },
2890 { "socket_path", FORMAT_TABLE_STRING,
2891 format_cb_socket_path
2892 },
2893 { "start_time", FORMAT_TABLE_TIME,
2894 format_cb_start_time
2895 },
2896 { "tree_mode_format", FORMAT_TABLE_STRING,
2897 format_cb_tree_mode_format
2898 },
2899 { "version", FORMAT_TABLE_STRING,
2900 format_cb_version
2901 },
2902 { "window_active", FORMAT_TABLE_STRING,
2903 format_cb_window_active
2904 },
2905 { "window_active_clients", FORMAT_TABLE_STRING,
2906 format_cb_window_active_clients
2907 },
2908 { "window_active_clients_list", FORMAT_TABLE_STRING,
2909 format_cb_window_active_clients_list
2910 },
2911 { "window_active_sessions", FORMAT_TABLE_STRING,
2912 format_cb_window_active_sessions
2913 },
2914 { "window_active_sessions_list", FORMAT_TABLE_STRING,
2915 format_cb_window_active_sessions_list
2916 },
2917 { "window_activity", FORMAT_TABLE_TIME,
2918 format_cb_window_activity
2919 },
2920 { "window_activity_flag", FORMAT_TABLE_STRING,
2921 format_cb_window_activity_flag
2922 },
2923 { "window_bell_flag", FORMAT_TABLE_STRING,
2924 format_cb_window_bell_flag
2925 },
2926 { "window_bigger", FORMAT_TABLE_STRING,
2927 format_cb_window_bigger
2928 },
2929 { "window_cell_height", FORMAT_TABLE_STRING,
2930 format_cb_window_cell_height
2931 },
2932 { "window_cell_width", FORMAT_TABLE_STRING,
2933 format_cb_window_cell_width
2934 },
2935 { "window_end_flag", FORMAT_TABLE_STRING,
2936 format_cb_window_end_flag
2937 },
2938 { "window_flags", FORMAT_TABLE_STRING,
2939 format_cb_window_flags
2940 },
2941 { "window_format", FORMAT_TABLE_STRING,
2942 format_cb_window_format
2943 },
2944 { "window_height", FORMAT_TABLE_STRING,
2945 format_cb_window_height
2946 },
2947 { "window_id", FORMAT_TABLE_STRING,
2948 format_cb_window_id
2949 },
2950 { "window_index", FORMAT_TABLE_STRING,
2951 format_cb_window_index
2952 },
2953 { "window_last_flag", FORMAT_TABLE_STRING,
2954 format_cb_window_last_flag
2955 },
2956 { "window_layout", FORMAT_TABLE_STRING,
2957 format_cb_window_layout
2958 },
2959 { "window_linked", FORMAT_TABLE_STRING,
2960 format_cb_window_linked
2961 },
2962 { "window_linked_sessions", FORMAT_TABLE_STRING,
2963 format_cb_window_linked_sessions
2964 },
2965 { "window_linked_sessions_list", FORMAT_TABLE_STRING,
2966 format_cb_window_linked_sessions_list
2967 },
2968 { "window_marked_flag", FORMAT_TABLE_STRING,
2969 format_cb_window_marked_flag
2970 },
2971 { "window_name", FORMAT_TABLE_STRING,
2972 format_cb_window_name
2973 },
2974 { "window_offset_x", FORMAT_TABLE_STRING,
2975 format_cb_window_offset_x
2976 },
2977 { "window_offset_y", FORMAT_TABLE_STRING,
2978 format_cb_window_offset_y
2979 },
2980 { "window_panes", FORMAT_TABLE_STRING,
2981 format_cb_window_panes
2982 },
2983 { "window_raw_flags", FORMAT_TABLE_STRING,
2984 format_cb_window_raw_flags
2985 },
2986 { "window_silence_flag", FORMAT_TABLE_STRING,
2987 format_cb_window_silence_flag
2988 },
2989 { "window_stack_index", FORMAT_TABLE_STRING,
2990 format_cb_window_stack_index
2991 },
2992 { "window_start_flag", FORMAT_TABLE_STRING,
2993 format_cb_window_start_flag
2994 },
2995 { "window_visible_layout", FORMAT_TABLE_STRING,
2996 format_cb_window_visible_layout
2997 },
2998 { "window_width", FORMAT_TABLE_STRING,
2999 format_cb_window_width
3000 },
3001 { "window_zoomed_flag", FORMAT_TABLE_STRING,
3002 format_cb_window_zoomed_flag
3003 },
3004 { "wrap_flag", FORMAT_TABLE_STRING,
3005 format_cb_wrap_flag
3006 }
3007};
3008
3009/* Compare format table entries. */
3010static int
3011format_table_compare(const void *key0, const void *entry0)
3012{
3013 const char *key = key0;
3014 const struct format_table_entry *entry = entry0;
3015
3016 return (strcmp(key, entry->key));
3017}
3018
3019/* Get a format callback. */
3020static struct format_table_entry *
3021format_table_get(const char *key)
3022{
3023 return (bsearch(key, format_table, nitems(format_table)(sizeof((format_table)) / sizeof((format_table)[0])),
3024 sizeof *format_table, format_table_compare));
3025}
3026
3027/* Merge one format tree into another. */
3028void
3029format_merge(struct format_tree *ft, struct format_tree *from)
3030{
3031 struct format_entry *fe;
3032
3033 RB_FOREACH(fe, format_entry_tree, &from->tree)for ((fe) = format_entry_tree_RB_MINMAX(&from->tree, -
1); (fe) != ((void *)0); (fe) = format_entry_tree_RB_NEXT(fe)
)
{
3034 if (fe->value != NULL((void *)0))
3035 format_add(ft, fe->key, "%s", fe->value);
3036 }
3037}
3038
3039/* Get format pane. */
3040struct window_pane *
3041format_get_pane(struct format_tree *ft)
3042{
3043 return (ft->wp);
3044}
3045
3046/* Add item bits to tree. */
3047static void
3048format_create_add_item(struct format_tree *ft, struct cmdq_item *item)
3049{
3050 struct key_event *event = cmdq_get_event(item);
3051 struct mouse_event *m = &event->m;
3052
3053 cmdq_merge_formats(item, ft);
3054 memcpy(&ft->m, m, sizeof ft->m);
3055}
3056
3057/* Create a new tree. */
3058struct format_tree *
3059format_create(struct client *c, struct cmdq_item *item, int tag, int flags)
3060{
3061 struct format_tree *ft;
3062
3063 ft = xcalloc(1, sizeof *ft);
3064 RB_INIT(&ft->tree)do { (&ft->tree)->rbh_root = ((void *)0); } while (
0)
;
3065
3066 if (c != NULL((void *)0)) {
3067 ft->client = c;
3068 ft->client->references++;
3069 }
3070 ft->item = item;
3071
3072 ft->tag = tag;
3073 ft->flags = flags;
3074
3075 if (item != NULL((void *)0))
3076 format_create_add_item(ft, item);
3077
3078 return (ft);
3079}
3080
3081/* Free a tree. */
3082void
3083format_free(struct format_tree *ft)
3084{
3085 struct format_entry *fe, *fe1;
3086
3087 RB_FOREACH_SAFE(fe, format_entry_tree, &ft->tree, fe1)for ((fe) = format_entry_tree_RB_MINMAX(&ft->tree, -1)
; ((fe) != ((void *)0)) && ((fe1) = format_entry_tree_RB_NEXT
(fe), 1); (fe) = (fe1))
{
3088 RB_REMOVE(format_entry_tree, &ft->tree, fe)format_entry_tree_RB_REMOVE(&ft->tree, fe);
3089 free(fe->value);
3090 free(fe->key);
3091 free(fe);
3092 }
3093
3094 if (ft->client != NULL((void *)0))
3095 server_client_unref(ft->client);
3096 free(ft);
3097}
3098
3099/* Log each format. */
3100static void
3101format_log_debug_cb(const char *key, const char *value, void *arg)
3102{
3103 const char *prefix = arg;
3104
3105 log_debug("%s: %s=%s", prefix, key, value);
3106}
3107
3108/* Log a format tree. */
3109void
3110format_log_debug(struct format_tree *ft, const char *prefix)
3111{
3112 format_each(ft, format_log_debug_cb, (void *)prefix);
3113}
3114
3115/* Walk each format. */
3116void
3117format_each(struct format_tree *ft, void (*cb)(const char *, const char *,
3118 void *), void *arg)
3119{
3120 const struct format_table_entry *fte;
3121 struct format_entry *fe;
3122 u_int i;
3123 char s[64];
3124 void *value;
3125 struct timeval *tv;
3126
3127 for (i = 0; i < nitems(format_table)(sizeof((format_table)) / sizeof((format_table)[0])); i++) {
3128 fte = &format_table[i];
3129
3130 value = fte->cb(ft);
3131 if (value == NULL((void *)0))
3132 continue;
3133 if (fte->type == FORMAT_TABLE_TIME) {
3134 tv = value;
3135 xsnprintf(s, sizeof s, "%lld", (long long)tv->tv_sec);
3136 cb(fte->key, s, arg);
3137 } else {
3138 cb(fte->key, value, arg);
3139 free(value);
3140 }
3141 }
3142 RB_FOREACH(fe, format_entry_tree, &ft->tree)for ((fe) = format_entry_tree_RB_MINMAX(&ft->tree, -1)
; (fe) != ((void *)0); (fe) = format_entry_tree_RB_NEXT(fe))
{
3143 if (fe->time != 0) {
3144 xsnprintf(s, sizeof s, "%lld", (long long)fe->time);
3145 cb(fe->key, s, arg);
3146 } else {
3147 if (fe->value == NULL((void *)0) && fe->cb != NULL((void *)0)) {
3148 fe->value = fe->cb(ft);
3149 if (fe->value == NULL((void *)0))
3150 fe->value = xstrdup("");
3151 }
3152 cb(fe->key, fe->value, arg);
3153 }
3154 }
3155}
3156
3157/* Add a key-value pair. */
3158void
3159format_add(struct format_tree *ft, const char *key, const char *fmt, ...)
3160{
3161 struct format_entry *fe;
3162 struct format_entry *fe_now;
3163 va_list ap;
3164
3165 fe = xmalloc(sizeof *fe);
3166 fe->key = xstrdup(key);
3167
3168 fe_now = RB_INSERT(format_entry_tree, &ft->tree, fe)format_entry_tree_RB_INSERT(&ft->tree, fe);
3169 if (fe_now != NULL((void *)0)) {
3170 free(fe->key);
3171 free(fe);
3172 free(fe_now->value);
3173 fe = fe_now;
3174 }
3175
3176 fe->cb = NULL((void *)0);
3177 fe->time = 0;
3178
3179 va_start(ap, fmt)__builtin_va_start(ap, fmt);
3180 xvasprintf(&fe->value, fmt, ap);
3181 va_end(ap)__builtin_va_end(ap);
3182}
3183
3184/* Add a key and time. */
3185void
3186format_add_tv(struct format_tree *ft, const char *key, struct timeval *tv)
3187{
3188 struct format_entry *fe, *fe_now;
3189
3190 fe = xmalloc(sizeof *fe);
3191 fe->key = xstrdup(key);
3192
3193 fe_now = RB_INSERT(format_entry_tree, &ft->tree, fe)format_entry_tree_RB_INSERT(&ft->tree, fe);
3194 if (fe_now != NULL((void *)0)) {
3195 free(fe->key);
3196 free(fe);
3197 free(fe_now->value);
3198 fe = fe_now;
3199 }
3200
3201 fe->cb = NULL((void *)0);
3202 fe->time = tv->tv_sec;
3203
3204 fe->value = NULL((void *)0);
3205}
3206
3207/* Add a key and function. */
3208void
3209format_add_cb(struct format_tree *ft, const char *key, format_cb cb)
3210{
3211 struct format_entry *fe;
3212 struct format_entry *fe_now;
3213
3214 fe = xmalloc(sizeof *fe);
3215 fe->key = xstrdup(key);
3216
3217 fe_now = RB_INSERT(format_entry_tree, &ft->tree, fe)format_entry_tree_RB_INSERT(&ft->tree, fe);
3218 if (fe_now != NULL((void *)0)) {
3219 free(fe->key);
3220 free(fe);
3221 free(fe_now->value);
3222 fe = fe_now;
3223 }
3224
3225 fe->cb = cb;
3226 fe->time = 0;
3227
3228 fe->value = NULL((void *)0);
3229}
3230
3231/* Quote shell special characters in string. */
3232static char *
3233format_quote_shell(const char *s)
3234{
3235 const char *cp;
3236 char *out, *at;
3237
3238 at = out = xmalloc(strlen(s) * 2 + 1);
3239 for (cp = s; *cp != '\0'; cp++) {
3240 if (strchr("|&;<>()$`\\\"'*?[# =%", *cp) != NULL((void *)0))
3241 *at++ = '\\';
3242 *at++ = *cp;
3243 }
3244 *at = '\0';
3245 return (out);
3246}
3247
3248/* Quote #s in string. */
3249static char *
3250format_quote_style(const char *s)
3251{
3252 const char *cp;
3253 char *out, *at;
3254
3255 at = out = xmalloc(strlen(s) * 2 + 1);
3256 for (cp = s; *cp != '\0'; cp++) {
3257 if (*cp == '#')
3258 *at++ = '#';
3259 *at++ = *cp;
3260 }
3261 *at = '\0';
3262 return (out);
3263}
3264
3265/* Make a prettier time. */
3266static char *
3267format_pretty_time(time_t t)
3268{
3269 struct tm now_tm, tm;
3270 time_t now, age;
3271 char s[6];
3272
3273 time(&now);
3274 if (now < t)
3275 now = t;
3276 age = now - t;
3277
3278 localtime_r(&now, &now_tm);
3279 localtime_r(&t, &tm);
3280
3281 /* Last 24 hours. */
3282 if (age < 24 * 3600) {
3283 strftime(s, sizeof s, "%H:%M", &tm);
3284 return (xstrdup(s));
3285 }
3286
3287 /* This month or last 28 days. */
3288 if ((tm.tm_year == now_tm.tm_year && tm.tm_mon == now_tm.tm_mon) ||
3289 age < 28 * 24 * 3600) {
3290 strftime(s, sizeof s, "%a%d", &tm);
3291 return (xstrdup(s));
3292 }
3293
3294 /* Last 12 months. */
3295 if ((tm.tm_year == now_tm.tm_year && tm.tm_mon < now_tm.tm_mon) ||
3296 (tm.tm_year == now_tm.tm_year - 1 && tm.tm_mon > now_tm.tm_mon)) {
3297 strftime(s, sizeof s, "%d%b", &tm);
3298 return (xstrdup(s));
3299 }
3300
3301 /* Older than that. */
3302 strftime(s, sizeof s, "%h%y", &tm);
3303 return (xstrdup(s));
3304}
3305
3306/* Find a format entry. */
3307static char *
3308format_find(struct format_tree *ft, const char *key, int modifiers,
3309 const char *time_format)
3310{
3311 struct format_table_entry *fte;
3312 void *value;
3313 struct format_entry *fe, fe_find;
3314 struct environ_entry *envent;
3315 struct options_entry *o;
3316 int idx;
3317 char *found = NULL((void *)0), *saved, s[512];
3318 const char *errstr;
3319 time_t t = 0;
3320 struct tm tm;
3321
3322 o = options_parse_get(global_options, key, &idx, 0);
3323 if (o == NULL((void *)0) && ft->wp != NULL((void *)0))
3324 o = options_parse_get(ft->wp->options, key, &idx, 0);
3325 if (o == NULL((void *)0) && ft->w != NULL((void *)0))
3326 o = options_parse_get(ft->w->options, key, &idx, 0);
3327 if (o == NULL((void *)0))
3328 o = options_parse_get(global_w_options, key, &idx, 0);
3329 if (o == NULL((void *)0) && ft->s != NULL((void *)0))
3330 o = options_parse_get(ft->s->options, key, &idx, 0);
3331 if (o == NULL((void *)0))
3332 o = options_parse_get(global_s_options, key, &idx, 0);
3333 if (o != NULL((void *)0)) {
3334 found = options_to_string(o, idx, 1);
3335 goto found;
3336 }
3337
3338 fte = format_table_get(key);
3339 if (fte != NULL((void *)0)) {
3340 value = fte->cb(ft);
3341 if (fte->type == FORMAT_TABLE_TIME && value != NULL((void *)0))
3342 t = ((struct timeval *)value)->tv_sec;
3343 else
3344 found = value;
3345 goto found;
3346 }
3347 fe_find.key = (char *)key;
3348 fe = RB_FIND(format_entry_tree, &ft->tree, &fe_find)format_entry_tree_RB_FIND(&ft->tree, &fe_find);
3349 if (fe != NULL((void *)0)) {
3350 if (fe->time != 0) {
3351 t = fe->time;
3352 goto found;
3353 }
3354 if (fe->value == NULL((void *)0) && fe->cb != NULL((void *)0)) {
3355 fe->value = fe->cb(ft);
3356 if (fe->value == NULL((void *)0))
3357 fe->value = xstrdup("");
3358 }
3359 found = xstrdup(fe->value);
3360 goto found;
3361 }
3362
3363 if (~modifiers & FORMAT_TIMESTRING0x1) {
3364 envent = NULL((void *)0);
3365 if (ft->s != NULL((void *)0))
3366 envent = environ_find(ft->s->environ, key);
3367 if (envent == NULL((void *)0))
3368 envent = environ_find(global_environ, key);
3369 if (envent != NULL((void *)0) && envent->value != NULL((void *)0)) {
3370 found = xstrdup(envent->value);
3371 goto found;
3372 }
3373 }
3374
3375 return (NULL((void *)0));
3376
3377found:
3378 if (modifiers & FORMAT_TIMESTRING0x1) {
3379 if (t == 0 && found != NULL((void *)0)) {
3380 t = strtonum(found, 0, INT64_MAX0x7fffffffffffffffLL, &errstr);
3381 if (errstr != NULL((void *)0))
3382 t = 0;
3383 free(found);
3384 }
3385 if (t == 0)
3386 return (NULL((void *)0));
3387 if (modifiers & FORMAT_PRETTY0x400)
3388 found = format_pretty_time(t);
3389 else {
3390 if (time_format != NULL((void *)0)) {
3391 localtime_r(&t, &tm);
3392 strftime(s, sizeof s, time_format, &tm);
3393 } else {
3394 ctime_r(&t, s);
3395 s[strcspn(s, "\n")] = '\0';
3396 }
3397 found = xstrdup(s);
3398 }
3399 return (found);
3400 }
3401
3402 if (t != 0)
3403 xasprintf(&found, "%lld", (long long)t);
3404 else if (found == NULL((void *)0))
3405 return (NULL((void *)0));
3406 if (modifiers & FORMAT_BASENAME0x2) {
3407 saved = found;
3408 found = xstrdup(basename(saved));
3409 free(saved);
3410 }
3411 if (modifiers & FORMAT_DIRNAME0x4) {
3412 saved = found;
3413 found = xstrdup(dirname(saved));
3414 free(saved);
3415 }
3416 if (modifiers & FORMAT_QUOTE_SHELL0x8) {
3417 saved = found;
3418 found = xstrdup(format_quote_shell(saved));
3419 free(saved);
3420 }
3421 if (modifiers & FORMAT_QUOTE_STYLE0x2000) {
3422 saved = found;
3423 found = xstrdup(format_quote_style(saved));
3424 free(saved);
3425 }
3426 return (found);
3427}
3428
3429/* Remove escaped characters from string. */
3430static char *
3431format_strip(const char *s)
3432{
3433 char *out, *cp;
3434 int brackets = 0;
3435
3436 cp = out = xmalloc(strlen(s) + 1);
3437 for (; *s != '\0'; s++) {
3438 if (*s == '#' && s[1] == '{')
3439 brackets++;
3440 if (*s == '#' && strchr(",#{}:", s[1]) != NULL((void *)0)) {
3441 if (brackets != 0)
3442 *cp++ = *s;
3443 continue;
3444 }
3445 if (*s == '}')
3446 brackets--;
3447 *cp++ = *s;
3448 }
3449 *cp = '\0';
3450 return (out);
3451}
3452
3453/* Skip until end. */
3454const char *
3455format_skip(const char *s, const char *end)
3456{
3457 int brackets = 0;
3458
3459 for (; *s != '\0'; s++) {
3460 if (*s == '#' && s[1] == '{')
3461 brackets++;
3462 if (*s == '#' && strchr(",#{}:", s[1]) != NULL((void *)0)) {
3463 s++;
3464 continue;
3465 }
3466 if (*s == '}')
3467 brackets--;
3468 if (strchr(end, *s) != NULL((void *)0) && brackets == 0)
3469 break;
3470 }
3471 if (*s == '\0')
3472 return (NULL((void *)0));
3473 return (s);
3474}
3475
3476/* Return left and right alternatives separated by commas. */
3477static int
3478format_choose(struct format_expand_state *es, const char *s, char **left,
3479 char **right, int expand)
3480{
3481 const char *cp;
3482 char *left0, *right0;
3483
3484 cp = format_skip(s, ",");
3485 if (cp == NULL((void *)0))
3486 return (-1);
3487 left0 = xstrndup(s, cp - s);
3488 right0 = xstrdup(cp + 1);
3489
3490 if (expand) {
3491 *left = format_expand1(es, left0);
3492 free(left0);
3493 *right = format_expand1(es, right0);
3494 free(right0);
3495 } else {
3496 *left = left0;
3497 *right = right0;
3498 }
3499 return (0);
3500}
3501
3502/* Is this true? */
3503int
3504format_true(const char *s)
3505{
3506 if (s != NULL((void *)0) && *s != '\0' && (s[0] != '0' || s[1] != '\0'))
3507 return (1);
3508 return (0);
3509}
3510
3511/* Check if modifier end. */
3512static int
3513format_is_end(char c)
3514{
3515 return (c == ';' || c == ':');
3516}
3517
3518/* Add to modifier list. */
3519static void
3520format_add_modifier(struct format_modifier **list, u_int *count,
3521 const char *c, size_t n, char **argv, int argc)
3522{
3523 struct format_modifier *fm;
3524
3525 *list = xreallocarray(*list, (*count) + 1, sizeof **list);
3526 fm = &(*list)[(*count)++];
3527
3528 memcpy(fm->modifier, c, n);
3529 fm->modifier[n] = '\0';
3530 fm->size = n;
3531
3532 fm->argv = argv;
3533 fm->argc = argc;
3534}
3535
3536/* Free modifier list. */
3537static void
3538format_free_modifiers(struct format_modifier *list, u_int count)
3539{
3540 u_int i;
3541
3542 for (i = 0; i < count; i++)
3543 cmd_free_argv(list[i].argc, list[i].argv);
3544 free(list);
3545}
3546
3547/* Build modifier list. */
3548static struct format_modifier *
3549format_build_modifiers(struct format_expand_state *es, const char **s,
3550 u_int *count)
3551{
3552 const char *cp = *s, *end;
3553 struct format_modifier *list = NULL((void *)0);
3554 char c, last[] = "X;:", **argv, *value;
3555 int argc;
3556
3557 /*
3558 * Modifiers are a ; separated list of the forms:
3559 * l,m,C,a,b,c,d,n,t,w,q,E,T,S,W,P,<,>
3560 * =a
3561 * =/a
3562 * =/a/
3563 * s/a/b/
3564 * s/a/b
3565 * ||,&&,!=,==,<=,>=
3566 */
3567
3568 *count = 0;
3569
3570 while (*cp != '\0' && *cp != ':') {
3571 /* Skip any separator character. */
3572 if (*cp == ';')
3573 cp++;
3574
3575 /* Check single character modifiers with no arguments. */
3576 if (strchr("labcdnwETSWP<>", cp[0]) != NULL((void *)0) &&
3577 format_is_end(cp[1])) {
3578 format_add_modifier(&list, count, cp, 1, NULL((void *)0), 0);
3579 cp++;
3580 continue;
3581 }
3582
3583 /* Then try double character with no arguments. */
3584 if ((memcmp("||", cp, 2) == 0 ||
3585 memcmp("&&", cp, 2) == 0 ||
3586 memcmp("!=", cp, 2) == 0 ||
3587 memcmp("==", cp, 2) == 0 ||
3588 memcmp("<=", cp, 2) == 0 ||
3589 memcmp(">=", cp, 2) == 0) &&
3590 format_is_end(cp[2])) {
3591 format_add_modifier(&list, count, cp, 2, NULL((void *)0), 0);
3592 cp += 2;
3593 continue;
3594 }
3595
3596 /* Now try single character with arguments. */
3597 if (strchr("mCNst=peq", cp[0]) == NULL((void *)0))
3598 break;
3599 c = cp[0];
3600
3601 /* No arguments provided. */
3602 if (format_is_end(cp[1])) {
3603 format_add_modifier(&list, count, cp, 1, NULL((void *)0), 0);
3604 cp++;
3605 continue;
3606 }
3607 argv = NULL((void *)0);
3608 argc = 0;
3609
3610 /* Single argument with no wrapper character. */
3611 if (!ispunct(cp[1]) || cp[1] == '-') {
3612 end = format_skip(cp + 1, ":;");
3613 if (end == NULL((void *)0))
3614 break;
3615
3616 argv = xcalloc(1, sizeof *argv);
3617 value = xstrndup(cp + 1, end - (cp + 1));
3618 argv[0] = format_expand1(es, value);
3619 free(value);
3620 argc = 1;
3621
3622 format_add_modifier(&list, count, &c, 1, argv, argc);
3623 cp = end;
3624 continue;
3625 }
3626
3627 /* Multiple arguments with a wrapper character. */
3628 last[0] = cp[1];
3629 cp++;
3630 do {
3631 if (cp[0] == last[0] && format_is_end(cp[1])) {
3632 cp++;
3633 break;
3634 }
3635 end = format_skip(cp + 1, last);
3636 if (end == NULL((void *)0))
3637 break;
3638 cp++;
3639
3640 argv = xreallocarray(argv, argc + 1, sizeof *argv);
3641 value = xstrndup(cp, end - cp);
3642 argv[argc++] = format_expand1(es, value);
3643 free(value);
3644
3645 cp = end;
3646 } while (!format_is_end(cp[0]));
3647 format_add_modifier(&list, count, &c, 1, argv, argc);
3648 }
3649 if (*cp != ':') {
3650 format_free_modifiers(list, *count);
3651 *count = 0;
3652 return (NULL((void *)0));
3653 }
3654 *s = cp + 1;
3655 return (list);
3656}
3657
3658/* Match against an fnmatch(3) pattern or regular expression. */
3659static char *
3660format_match(struct format_modifier *fm, const char *pattern, const char *text)
3661{
3662 const char *s = "";
3663 regex_t r;
3664 int flags = 0;
3665
3666 if (fm->argc >= 1)
3667 s = fm->argv[0];
3668 if (strchr(s, 'r') == NULL((void *)0)) {
3669 if (strchr(s, 'i') != NULL((void *)0))
3670 flags |= FNM_CASEFOLD0x10;
3671 if (fnmatch(pattern, text, flags) != 0)
3672 return (xstrdup("0"));
3673 } else {
3674 flags = REG_EXTENDED0001|REG_NOSUB0004;
3675 if (strchr(s, 'i') != NULL((void *)0))
3676 flags |= REG_ICASE0002;
3677 if (regcomp(&r, pattern, flags) != 0)
3678 return (xstrdup("0"));
3679 if (regexec(&r, text, 0, NULL((void *)0), 0) != 0) {
3680 regfree(&r);
3681 return (xstrdup("0"));
3682 }
3683 regfree(&r);
3684 }
3685 return (xstrdup("1"));
3686}
3687
3688/* Perform substitution in string. */
3689static char *
3690format_sub(struct format_modifier *fm, const char *text, const char *pattern,
3691 const char *with)
3692{
3693 char *value;
3694 int flags = REG_EXTENDED0001;
3695
3696 if (fm->argc >= 3 && strchr(fm->argv[2], 'i') != NULL((void *)0))
3697 flags |= REG_ICASE0002;
3698 value = regsub(pattern, with, text, flags);
3699 if (value == NULL((void *)0))
3700 return (xstrdup(text));
3701 return (value);
3702}
3703
3704/* Search inside pane. */
3705static char *
3706format_search(struct format_modifier *fm, struct window_pane *wp, const char *s)
3707{
3708 int ignore = 0, regex = 0;
3709 char *value;
3710
3711 if (fm->argc >= 1) {
3712 if (strchr(fm->argv[0], 'i') != NULL((void *)0))
3713 ignore = 1;
3714 if (strchr(fm->argv[0], 'r') != NULL((void *)0))
3715 regex = 1;
3716 }
3717 xasprintf(&value, "%u", window_pane_search(wp, s, regex, ignore));
3718 return (value);
3719}
3720
3721/* Does session name exist? */
3722static char *
3723format_session_name(struct format_expand_state *es, const char *fmt)
3724{
3725 char *name;
3726 struct session *s;
3727
3728 name = format_expand1(es, fmt);
3729 RB_FOREACH(s, sessions, &sessions)for ((s) = sessions_RB_MINMAX(&sessions, -1); (s) != ((void
*)0); (s) = sessions_RB_NEXT(s))
{
3730 if (strcmp(s->name, name) == 0) {
3731 free(name);
3732 return (xstrdup("1"));
3733 }
3734 }
3735 free(name);
3736 return (xstrdup("0"));
3737}
3738
3739/* Loop over sessions. */
3740static char *
3741format_loop_sessions(struct format_expand_state *es, const char *fmt)
3742{
3743 struct format_tree *ft = es->ft;
3744 struct client *c = ft->client;
3745 struct cmdq_item *item = ft->item;
3746 struct format_tree *nft;
3747 struct format_expand_state next;
3748 char *expanded, *value;
3749 size_t valuelen;
3750 struct session *s;
3751
3752 value = xcalloc(1, 1);
3753 valuelen = 1;
3754
3755 RB_FOREACH(s, sessions, &sessions)for ((s) = sessions_RB_MINMAX(&sessions, -1); (s) != ((void
*)0); (s) = sessions_RB_NEXT(s))
{
3756 format_log(es, "session loop: $%u", s->id)format_log1(es, __func__, "session loop: $%u", s->id);
3757 nft = format_create(c, item, FORMAT_NONE0, ft->flags);
3758 format_defaults(nft, ft->c, s, NULL((void *)0), NULL((void *)0));
3759 format_copy_state(&next, es, 0);
3760 next.ft = nft;
3761 expanded = format_expand1(&next, fmt);
3762 format_free(next.ft);
3763
3764 valuelen += strlen(expanded);
3765 value = xrealloc(value, valuelen);
3766
3767 strlcat(value, expanded, valuelen);
3768 free(expanded);
3769 }
3770
3771 return (value);
3772}
3773
3774/* Does window name exist? */
3775static char *
3776format_window_name(struct format_expand_state *es, const char *fmt)
3777{
3778 struct format_tree *ft = es->ft;
3779 char *name;
3780 struct winlink *wl;
3781
3782 if (ft->s == NULL((void *)0)) {
3783 format_log(es, "window name but no session")format_log1(es, __func__, "window name but no session");
3784 return (NULL((void *)0));
3785 }
3786
3787 name = format_expand1(es, fmt);
3788 RB_FOREACH(wl, winlinks, &ft->s->windows)for ((wl) = winlinks_RB_MINMAX(&ft->s->windows, -1)
; (wl) != ((void *)0); (wl) = winlinks_RB_NEXT(wl))
{
3789 if (strcmp(wl->window->name, name) == 0) {
3790 free(name);
3791 return (xstrdup("1"));
3792 }
3793 }
3794 free(name);
3795 return (xstrdup("0"));
3796}
3797
3798/* Loop over windows. */
3799static char *
3800format_loop_windows(struct format_expand_state *es, const char *fmt)
3801{
3802 struct format_tree *ft = es->ft;
3803 struct client *c = ft->client;
3804 struct cmdq_item *item = ft->item;
3805 struct format_tree *nft;
3806 struct format_expand_state next;
3807 char *all, *active, *use, *expanded, *value;
3808 size_t valuelen;
3809 struct winlink *wl;
3810 struct window *w;
3811
3812 if (ft->s == NULL((void *)0)) {
3813 format_log(es, "window loop but no session")format_log1(es, __func__, "window loop but no session");
3814 return (NULL((void *)0));
3815 }
3816
3817 if (format_choose(es, fmt, &all, &active, 0) != 0) {
3818 all = xstrdup(fmt);
3819 active = NULL((void *)0);
3820 }
3821
3822 value = xcalloc(1, 1);
3823 valuelen = 1;
3824
3825 RB_FOREACH(wl, winlinks, &ft->s->windows)for ((wl) = winlinks_RB_MINMAX(&ft->s->windows, -1)
; (wl) != ((void *)0); (wl) = winlinks_RB_NEXT(wl))
{
3826 w = wl->window;
3827 format_log(es, "window loop: %u @%u", wl->idx, w->id)format_log1(es, __func__, "window loop: %u @%u", wl->idx, w
->id)
;
3828 if (active != NULL((void *)0) && wl == ft->s->curw)
3829 use = active;
3830 else
3831 use = all;
3832 nft = format_create(c, item, FORMAT_WINDOW0x40000000U|w->id, ft->flags);
3833 format_defaults(nft, ft->c, ft->s, wl, NULL((void *)0));
3834 format_copy_state(&next, es, 0);
3835 next.ft = nft;
3836 expanded = format_expand1(&next, use);
3837 format_free(nft);
3838
3839 valuelen += strlen(expanded);
3840 value = xrealloc(value, valuelen);
3841
3842 strlcat(value, expanded, valuelen);
3843 free(expanded);
3844 }
3845
3846 free(active);
3847 free(all);
3848
3849 return (value);
3850}
3851
3852/* Loop over panes. */
3853static char *
3854format_loop_panes(struct format_expand_state *es, const char *fmt)
3855{
3856 struct format_tree *ft = es->ft;
3857 struct client *c = ft->client;
3858 struct cmdq_item *item = ft->item;
3859 struct format_tree *nft;
3860 struct format_expand_state next;
3861 char *all, *active, *use, *expanded, *value;
3862 size_t valuelen;
3863 struct window_pane *wp;
3864
3865 if (ft->w == NULL((void *)0)) {
3866 format_log(es, "pane loop but no window")format_log1(es, __func__, "pane loop but no window");
3867 return (NULL((void *)0));
3868 }
3869
3870 if (format_choose(es, fmt, &all, &active, 0) != 0) {
3871 all = xstrdup(fmt);
3872 active = NULL((void *)0);
3873 }
3874
3875 value = xcalloc(1, 1);
3876 valuelen = 1;
3877
3878 TAILQ_FOREACH(wp, &ft->w->panes, entry)for((wp) = ((&ft->w->panes)->tqh_first); (wp) !=
((void *)0); (wp) = ((wp)->entry.tqe_next))
{
3879 format_log(es, "pane loop: %%%u", wp->id)format_log1(es, __func__, "pane loop: %%%u", wp->id);
3880 if (active != NULL((void *)0) && wp == ft->w->active)
3881 use = active;
3882 else
3883 use = all;
3884 nft = format_create(c, item, FORMAT_PANE0x80000000U|wp->id, ft->flags);
3885 format_defaults(nft, ft->c, ft->s, ft->wl, wp);
3886 format_copy_state(&next, es, 0);
3887 next.ft = nft;
3888 expanded = format_expand1(&next, use);
3889 format_free(nft);
3890
3891 valuelen += strlen(expanded);
3892 value = xrealloc(value, valuelen);
3893
3894 strlcat(value, expanded, valuelen);
3895 free(expanded);
3896 }
3897
3898 free(active);
3899 free(all);
3900
3901 return (value);
3902}
3903
3904static char *
3905format_replace_expression(struct format_modifier *mexp,
3906 struct format_expand_state *es, const char *copy)
3907{
3908 int argc = mexp->argc;
3909 const char *errstr;
3910 char *endch, *value, *left = NULL((void *)0), *right = NULL((void *)0);
3911 int use_fp = 0;
3912 u_int prec = 0;
3913 double mleft, mright, result;
3914 enum { ADD,
3915 SUBTRACT,
3916 MULTIPLY,
3917 DIVIDE,
3918 MODULUS,
3919 EQUAL,
3920 NOT_EQUAL,
3921 GREATER_THAN,
3922 GREATER_THAN_EQUAL,
3923 LESS_THAN,
3924 LESS_THAN_EQUAL } operator;
3925
3926 if (strcmp(mexp->argv[0], "+") == 0)
3927 operator = ADD;
3928 else if (strcmp(mexp->argv[0], "-") == 0)
3929 operator = SUBTRACT;
3930 else if (strcmp(mexp->argv[0], "*") == 0)
3931 operator = MULTIPLY;
3932 else if (strcmp(mexp->argv[0], "/") == 0)
3933 operator = DIVIDE;
3934 else if (strcmp(mexp->argv[0], "%") == 0 ||
3935 strcmp(mexp->argv[0], "m") == 0)
3936 operator = MODULUS;
3937 else if (strcmp(mexp->argv[0], "==") == 0)
3938 operator = EQUAL;
3939 else if (strcmp(mexp->argv[0], "!=") == 0)
3940 operator = NOT_EQUAL;
3941 else if (strcmp(mexp->argv[0], ">") == 0)
3942 operator = GREATER_THAN;
3943 else if (strcmp(mexp->argv[0], "<") == 0)
3944 operator = LESS_THAN;
3945 else if (strcmp(mexp->argv[0], ">=") == 0)
3946 operator = GREATER_THAN_EQUAL;
3947 else if (strcmp(mexp->argv[0], "<=") == 0)
3948 operator = LESS_THAN_EQUAL;
3949 else {
3950 format_log(es, "expression has no valid operator: '%s'",format_log1(es, __func__, "expression has no valid operator: '%s'"
, mexp->argv[0])
3951 mexp->argv[0])format_log1(es, __func__, "expression has no valid operator: '%s'"
, mexp->argv[0])
;
3952 goto fail;
3953 }
3954
3955 /* The second argument may be flags. */
3956 if (argc >= 2 && strchr(mexp->argv[1], 'f') != NULL((void *)0)) {
3957 use_fp = 1;
3958 prec = 2;
3959 }
3960
3961 /* The third argument may be precision. */
3962 if (argc >= 3) {
3963 prec = strtonum(mexp->argv[2], INT_MIN(-2147483647 -1), INT_MAX2147483647, &errstr);
3964 if (errstr != NULL((void *)0)) {
3965 format_log(es, "expression precision %s: %s", errstr,format_log1(es, __func__, "expression precision %s: %s", errstr
, mexp->argv[2])
3966 mexp->argv[2])format_log1(es, __func__, "expression precision %s: %s", errstr
, mexp->argv[2])
;
3967 goto fail;
3968 }
3969 }
3970
3971 if (format_choose(es, copy, &left, &right, 1) != 0) {
3972 format_log(es, "expression syntax error")format_log1(es, __func__, "expression syntax error");
3973 goto fail;
3974 }
3975
3976 mleft = strtod(left, &endch);
3977 if (*endch != '\0') {
3978 format_log(es, "expression left side is invalid: %s", left)format_log1(es, __func__, "expression left side is invalid: %s"
, left)
;
3979 goto fail;
3980 }
3981
3982 mright = strtod(right, &endch);
3983 if (*endch != '\0') {
3984 format_log(es, "expression right side is invalid: %s", right)format_log1(es, __func__, "expression right side is invalid: %s"
, right)
;
3985 goto fail;
3986 }
3987
3988 if (!use_fp) {
3989 mleft = (long long)mleft;
3990 mright = (long long)mright;
3991 }
3992 format_log(es, "expression left side is: %.*f", prec, mleft)format_log1(es, __func__, "expression left side is: %.*f", prec
, mleft)
;
3993 format_log(es, "expression right side is: %.*f", prec, mright)format_log1(es, __func__, "expression right side is: %.*f", prec
, mright)
;
3994
3995 switch (operator) {
3996 case ADD:
3997 result = mleft + mright;
3998 break;
3999 case SUBTRACT:
4000 result = mleft - mright;
4001 break;
4002 case MULTIPLY:
4003 result = mleft * mright;
4004 break;
4005 case DIVIDE:
4006 result = mleft / mright;
4007 break;
4008 case MODULUS:
4009 result = fmod(mleft, mright);
4010 break;
4011 case EQUAL:
4012 result = fabs(mleft - mright) < 1e-9;
4013 break;
4014 case NOT_EQUAL:
4015 result = fabs(mleft - mright) > 1e-9;
4016 break;
4017 case GREATER_THAN:
4018 result = (mleft > mright);
4019 break;
4020 case GREATER_THAN_EQUAL:
4021 result = (mleft >= mright);
4022 break;
4023 case LESS_THAN:
4024 result = (mleft < mright);
4025 break;
4026 case LESS_THAN_EQUAL:
4027 result = (mleft <= mright);
4028 break;
4029 }
4030 if (use_fp)
4031 xasprintf(&value, "%.*f", prec, result);
4032 else
4033 xasprintf(&value, "%.*f", prec, (double)(long long)result);
4034 format_log(es, "expression result is %s", value)format_log1(es, __func__, "expression result is %s", value);
4035
4036 free(right);
4037 free(left);
4038 return (value);
4039
4040fail:
4041 free(right);
4042 free(left);
4043 return (NULL((void *)0));
4044}
4045
4046/* Replace a key. */
4047static int
4048format_replace(struct format_expand_state *es, const char *key, size_t keylen,
4049 char **buf, size_t *len, size_t *off)
4050{
4051 struct format_tree *ft = es->ft;
4052 struct window_pane *wp = ft->wp;
4053 const char *errstr, *copy, *cp, *marker = NULL((void *)0);
4054 const char *time_format = NULL((void *)0);
4055 char *copy0, *condition, *found, *new;
4056 char *value, *left, *right;
4057 size_t valuelen;
4058 int modifiers = 0, limit = 0, width = 0;
4059 int j, c;
4060 struct format_modifier *list, *cmp = NULL((void *)0), *search = NULL((void *)0);
4061 struct format_modifier **sub = NULL((void *)0), *mexp = NULL((void *)0), *fm;
4062 u_int i, count, nsub = 0;
4063 struct format_expand_state next;
4064
4065 /* Make a copy of the key. */
4066 copy = copy0 = xstrndup(key, keylen);
4067
4068 /* Process modifier list. */
4069 list = format_build_modifiers(es, &copy, &count);
4070 for (i = 0; i < count; i++) {
4071 fm = &list[i];
4072 if (format_logging(ft)) {
4073 format_log(es, "modifier %u is %s", i, fm->modifier)format_log1(es, __func__, "modifier %u is %s", i, fm->modifier
)
;
4074 for (j = 0; j < fm->argc; j++) {
4075 format_log(es, "modifier %u argument %d: %s", i,format_log1(es, __func__, "modifier %u argument %d: %s", i, j
, fm->argv[j])
4076 j, fm->argv[j])format_log1(es, __func__, "modifier %u argument %d: %s", i, j
, fm->argv[j])
;
4077 }
4078 }
4079 if (fm->size == 1) {
4080 switch (fm->modifier[0]) {
4081 case 'm':
4082 case '<':
4083 case '>':
4084 cmp = fm;
4085 break;
4086 case 'C':
4087 search = fm;
4088 break;
4089 case 's':
4090 if (fm->argc < 2)
4091 break;
4092 sub = xreallocarray(sub, nsub + 1, sizeof *sub);
4093 sub[nsub++] = fm;
4094 break;
4095 case '=':
4096 if (fm->argc < 1)
4097 break;
4098 limit = strtonum(fm->argv[0], INT_MIN(-2147483647 -1), INT_MAX2147483647,
4099 &errstr);
4100 if (errstr != NULL((void *)0))
4101 limit = 0;
4102 if (fm->argc >= 2 && fm->argv[1] != NULL((void *)0))
4103 marker = fm->argv[1];
4104 break;
4105 case 'p':
4106 if (fm->argc < 1)
4107 break;
4108 width = strtonum(fm->argv[0], INT_MIN(-2147483647 -1), INT_MAX2147483647,
4109 &errstr);
4110 if (errstr != NULL((void *)0))
4111 width = 0;
4112 break;
4113 case 'w':
4114 modifiers |= FORMAT_WIDTH0x1000;
4115 break;
4116 case 'e':
4117 if (fm->argc < 1 || fm->argc > 3)
4118 break;
4119 mexp = fm;
4120 break;
4121 case 'l':
4122 modifiers |= FORMAT_LITERAL0x10;
4123 break;
4124 case 'a':
4125 modifiers |= FORMAT_CHARACTER0x10000;
4126 break;
4127 case 'b':
4128 modifiers |= FORMAT_BASENAME0x2;
4129 break;
4130 case 'c':
4131 modifiers |= FORMAT_COLOUR0x20000;
4132 break;
4133 case 'd':
4134 modifiers |= FORMAT_DIRNAME0x4;
4135 break;
4136 case 'n':
4137 modifiers |= FORMAT_LENGTH0x800;
4138 break;
4139 case 't':
4140 modifiers |= FORMAT_TIMESTRING0x1;
4141 if (fm->argc < 1)
4142 break;
4143 if (strchr(fm->argv[0], 'p') != NULL((void *)0))
4144 modifiers |= FORMAT_PRETTY0x400;
4145 else if (fm->argc >= 2 &&
4146 strchr(fm->argv[0], 'f') != NULL((void *)0))
4147 time_format = format_strip(fm->argv[1]);
4148 break;
4149 case 'q':
4150 if (fm->argc < 1)
4151 modifiers |= FORMAT_QUOTE_SHELL0x8;
4152 else if (strchr(fm->argv[0], 'e') != NULL((void *)0) ||
4153 strchr(fm->argv[0], 'h') != NULL((void *)0))
4154 modifiers |= FORMAT_QUOTE_STYLE0x2000;
4155 break;
4156 case 'E':
4157 modifiers |= FORMAT_EXPAND0x20;
4158 break;
4159 case 'T':
4160 modifiers |= FORMAT_EXPANDTIME0x40;
4161 break;
4162 case 'N':
4163 if (fm->argc < 1 ||
4164 strchr(fm->argv[0], 'w') != NULL((void *)0))
4165 modifiers |= FORMAT_WINDOW_NAME0x4000;
4166 else if (strchr(fm->argv[0], 's') != NULL((void *)0))
4167 modifiers |= FORMAT_SESSION_NAME0x8000;
4168 break;
4169 case 'S':
4170 modifiers |= FORMAT_SESSIONS0x80;
4171 break;
4172 case 'W':
4173 modifiers |= FORMAT_WINDOWS0x100;
4174 break;
4175 case 'P':
4176 modifiers |= FORMAT_PANES0x200;
4177 break;
4178 }
4179 } else if (fm->size == 2) {
4180 if (strcmp(fm->modifier, "||") == 0 ||
4181 strcmp(fm->modifier, "&&") == 0 ||
4182 strcmp(fm->modifier, "==") == 0 ||
4183 strcmp(fm->modifier, "!=") == 0 ||
4184 strcmp(fm->modifier, ">=") == 0 ||
4185 strcmp(fm->modifier, "<=") == 0)
4186 cmp = fm;
4187 }
4188 }
4189
4190 /* Is this a literal string? */
4191 if (modifiers & FORMAT_LITERAL0x10) {
4192 value = xstrdup(copy);
4193 goto done;
4194 }
4195
4196 /* Is this a character? */
4197 if (modifiers & FORMAT_CHARACTER0x10000) {
4198 new = format_expand1(es, copy);
4199 c = strtonum(new, 32, 126, &errstr);
4200 if (errstr != NULL((void *)0))
4201 value = xstrdup("");
4202 else
4203 xasprintf(&value, "%c", c);
4204 free(new);
4205 goto done;
4206 }
4207
4208 /* Is this a colour? */
4209 if (modifiers & FORMAT_COLOUR0x20000) {
4210 new = format_expand1(es, copy);
4211 c = colour_fromstring(new);
4212 if (c == -1 || (c = colour_force_rgb(c)) == -1)
4213 value = xstrdup("");
4214 else
4215 xasprintf(&value, "%06x", c & 0xffffff);
4216 free(new);
4217 goto done;
4218 }
4219
4220 /* Is this a loop, comparison or condition? */
4221 if (modifiers & FORMAT_SESSIONS0x80) {
4222 value = format_loop_sessions(es, copy);
4223 if (value == NULL((void *)0))
4224 goto fail;
4225 } else if (modifiers & FORMAT_WINDOWS0x100) {
4226 value = format_loop_windows(es, copy);
4227 if (value == NULL((void *)0))
4228 goto fail;
4229 } else if (modifiers & FORMAT_PANES0x200) {
4230 value = format_loop_panes(es, copy);
4231 if (value == NULL((void *)0))
4232 goto fail;
4233 } else if (modifiers & FORMAT_WINDOW_NAME0x4000) {
4234 value = format_window_name(es, copy);
4235 if (value == NULL((void *)0))
4236 goto fail;
4237 } else if (modifiers & FORMAT_SESSION_NAME0x8000) {
4238 value = format_session_name(es, copy);
4239 if (value == NULL((void *)0))
4240 goto fail;
4241 } else if (search != NULL((void *)0)) {
4242 /* Search in pane. */
4243 new = format_expand1(es, copy);
4244 if (wp == NULL((void *)0)) {
4245 format_log(es, "search '%s' but no pane", new)format_log1(es, __func__, "search '%s' but no pane", new);
4246 value = xstrdup("0");
4247 } else {
4248 format_log(es, "search '%s' pane %%%u", new, wp->id)format_log1(es, __func__, "search '%s' pane %%%u", new, wp->
id)
;
4249 value = format_search(search, wp, new);
4250 }
4251 free(new);
4252 } else if (cmp != NULL((void *)0)) {
4253 /* Comparison of left and right. */
4254 if (format_choose(es, copy, &left, &right, 1) != 0) {
4255 format_log(es, "compare %s syntax error: %s",format_log1(es, __func__, "compare %s syntax error: %s", cmp->
modifier, copy)
4256 cmp->modifier, copy)format_log1(es, __func__, "compare %s syntax error: %s", cmp->
modifier, copy)
;
4257 goto fail;
4258 }
4259 format_log(es, "compare %s left is: %s", cmp->modifier, left)format_log1(es, __func__, "compare %s left is: %s", cmp->modifier
, left)
;
4260 format_log(es, "compare %s right is: %s", cmp->modifier, right)format_log1(es, __func__, "compare %s right is: %s", cmp->
modifier, right)
;
4261
4262 if (strcmp(cmp->modifier, "||") == 0) {
4263 if (format_true(left) || format_true(right))
4264 value = xstrdup("1");
4265 else
4266 value = xstrdup("0");
4267 } else if (strcmp(cmp->modifier, "&&") == 0) {
4268 if (format_true(left) && format_true(right))
4269 value = xstrdup("1");
4270 else
4271 value = xstrdup("0");
4272 } else if (strcmp(cmp->modifier, "==") == 0) {
4273 if (strcmp(left, right) == 0)
4274 value = xstrdup("1");
4275 else
4276 value = xstrdup("0");
4277 } else if (strcmp(cmp->modifier, "!=") == 0) {
4278 if (strcmp(left, right) != 0)
4279 value = xstrdup("1");
4280 else
4281 value = xstrdup("0");
4282 } else if (strcmp(cmp->modifier, "<") == 0) {
4283 if (strcmp(left, right) < 0)
4284 value = xstrdup("1");
4285 else
4286 value = xstrdup("0");
4287 } else if (strcmp(cmp->modifier, ">") == 0) {
4288 if (strcmp(left, right) > 0)
4289 value = xstrdup("1");
4290 else
4291 value = xstrdup("0");
4292 } else if (strcmp(cmp->modifier, "<=") == 0) {
4293 if (strcmp(left, right) <= 0)
4294 value = xstrdup("1");
4295 else
4296 value = xstrdup("0");
4297 } else if (strcmp(cmp->modifier, ">=") == 0) {
4298 if (strcmp(left, right) >= 0)
4299 value = xstrdup("1");
4300 else
4301 value = xstrdup("0");
4302 } else if (strcmp(cmp->modifier, "m") == 0)
4303 value = format_match(cmp, left, right);
4304
4305 free(right);
4306 free(left);
4307 } else if (*copy == '?') {
4308 /* Conditional: check first and choose second or third. */
4309 cp = format_skip(copy + 1, ",");
4310 if (cp == NULL((void *)0)) {
4311 format_log(es, "condition syntax error: %s", copy + 1)format_log1(es, __func__, "condition syntax error: %s", copy +
1)
;
4312 goto fail;
4313 }
4314 condition = xstrndup(copy + 1, cp - (copy + 1));
4315 format_log(es, "condition is: %s", condition)format_log1(es, __func__, "condition is: %s", condition);
4316
4317 found = format_find(ft, condition, modifiers, time_format);
4318 if (found == NULL((void *)0)) {
4319 /*
4320 * If the condition not found, try to expand it. If
4321 * the expansion doesn't have any effect, then assume
4322 * false.
4323 */
4324 found = format_expand1(es, condition);
4325 if (strcmp(found, condition) == 0) {
4326 free(found);
4327 found = xstrdup("");
4328 format_log(es,format_log1(es, __func__, "condition '%s' not found; assuming false"
, condition)
4329 "condition '%s' not found; assuming false",format_log1(es, __func__, "condition '%s' not found; assuming false"
, condition)
4330 condition)format_log1(es, __func__, "condition '%s' not found; assuming false"
, condition)
;
4331 }
4332 } else {
4333 format_log(es, "condition '%s' found: %s", condition,format_log1(es, __func__, "condition '%s' found: %s", condition
, found)
4334 found)format_log1(es, __func__, "condition '%s' found: %s", condition
, found)
;
4335 }
4336
4337 if (format_choose(es, cp + 1, &left, &right, 0) != 0) {
4338 format_log(es, "condition '%s' syntax error: %s",format_log1(es, __func__, "condition '%s' syntax error: %s", condition
, cp + 1)
4339 condition, cp + 1)format_log1(es, __func__, "condition '%s' syntax error: %s", condition
, cp + 1)
;
4340 free(found);
4341 goto fail;
4342 }
4343 if (format_true(found)) {
4344 format_log(es, "condition '%s' is true", condition)format_log1(es, __func__, "condition '%s' is true", condition
)
;
4345 value = format_expand1(es, left);
4346 } else {
4347 format_log(es, "condition '%s' is false", condition)format_log1(es, __func__, "condition '%s' is false", condition
)
;
4348 value = format_expand1(es, right);
4349 }
4350 free(right);
4351 free(left);
4352
4353 free(condition);
4354 free(found);
4355 } else if (mexp != NULL((void *)0)) {
4356 value = format_replace_expression(mexp, es, copy);
4357 if (value == NULL((void *)0))
4358 value = xstrdup("");
4359 } else {
4360 if (strstr(copy, "#{") != 0) {
4361 format_log(es, "expanding inner format '%s'", copy)format_log1(es, __func__, "expanding inner format '%s'", copy
)
;
4362 value = format_expand1(es, copy);
4363 } else {
4364 value = format_find(ft, copy, modifiers, time_format);
4365 if (value == NULL((void *)0)) {
4366 format_log(es, "format '%s' not found", copy)format_log1(es, __func__, "format '%s' not found", copy);
4367 value = xstrdup("");
4368 } else {
4369 format_log(es, "format '%s' found: %s", copy,format_log1(es, __func__, "format '%s' found: %s", copy, value
)
4370 value)format_log1(es, __func__, "format '%s' found: %s", copy, value
)
;
4371 }
4372 }
4373 }
4374
4375done:
4376 /* Expand again if required. */
4377 if (modifiers & FORMAT_EXPAND0x20) {
4378 new = format_expand1(es, value);
4379 free(value);
4380 value = new;
4381 } else if (modifiers & FORMAT_EXPANDTIME0x40) {
4382 format_copy_state(&next, es, FORMAT_EXPAND_TIME0x1);
4383 new = format_expand1(&next, value);
4384 free(value);
4385 value = new;
4386 }
4387
4388 /* Perform substitution if any. */
4389 for (i = 0; i < nsub; i++) {
4390 left = format_expand1(es, sub[i]->argv[0]);
4391 right = format_expand1(es, sub[i]->argv[1]);
4392 new = format_sub(sub[i], value, left, right);
4393 format_log(es, "substitute '%s' to '%s': %s", left, right, new)format_log1(es, __func__, "substitute '%s' to '%s': %s", left
, right, new)
;
4394 free(value);
4395 value = new;
4396 free(right);
4397 free(left);
4398 }
4399
4400 /* Truncate the value if needed. */
4401 if (limit > 0) {
4402 new = format_trim_left(value, limit);
4403 if (marker != NULL((void *)0) && strcmp(new, value) != 0) {
4404 free(value);
4405 xasprintf(&value, "%s%s", new, marker);
4406 } else {
4407 free(value);
4408 value = new;
4409 }
4410 format_log(es, "applied length limit %d: %s", limit, value)format_log1(es, __func__, "applied length limit %d: %s", limit
, value)
;
4411 } else if (limit < 0) {
4412 new = format_trim_right(value, -limit);
4413 if (marker != NULL((void *)0) && strcmp(new, value) != 0) {
4414 free(value);
4415 xasprintf(&value, "%s%s", marker, new);
4416 } else {
4417 free(value);
4418 value = new;
4419 }
4420 format_log(es, "applied length limit %d: %s", limit, value)format_log1(es, __func__, "applied length limit %d: %s", limit
, value)
;
4421 }
4422
4423 /* Pad the value if needed. */
4424 if (width > 0) {
4425 new = utf8_padcstr(value, width);
4426 free(value);
4427 value = new;
4428 format_log(es, "applied padding width %d: %s", width, value)format_log1(es, __func__, "applied padding width %d: %s", width
, value)
;
4429 } else if (width < 0) {
4430 new = utf8_rpadcstr(value, -width);
4431 free(value);
4432 value = new;
4433 format_log(es, "applied padding width %d: %s", width, value)format_log1(es, __func__, "applied padding width %d: %s", width
, value)
;
4434 }
4435
4436 /* Replace with the length or width if needed. */
4437 if (modifiers & FORMAT_LENGTH0x800) {
4438 xasprintf(&new, "%zu", strlen(value));
4439 free(value);
4440 value = new;
4441 format_log(es, "replacing with length: %s", new)format_log1(es, __func__, "replacing with length: %s", new);
4442 }
4443 if (modifiers & FORMAT_WIDTH0x1000) {
4444 xasprintf(&new, "%u", format_width(value));
4445 free(value);
4446 value = new;
4447 format_log(es, "replacing with width: %s", new)format_log1(es, __func__, "replacing with width: %s", new);
4448 }
4449
4450 /* Expand the buffer and copy in the value. */
4451 valuelen = strlen(value);
4452 while (*len - *off < valuelen + 1) {
4453 *buf = xreallocarray(*buf, 2, *len);
4454 *len *= 2;
4455 }
4456 memcpy(*buf + *off, value, valuelen);
4457 *off += valuelen;
4458
4459 format_log(es, "replaced '%s' with '%s'", copy0, value)format_log1(es, __func__, "replaced '%s' with '%s'", copy0, value
)
;
4460 free(value);
4461
4462 free(sub);
4463 format_free_modifiers(list, count);
4464 free(copy0);
4465 return (0);
4466
4467fail:
4468 format_log(es, "failed %s", copy0)format_log1(es, __func__, "failed %s", copy0);
4469
4470 free(sub);
4471 format_free_modifiers(list, count);
4472 free(copy0);
4473 return (-1);
4474}
4475
4476/* Expand keys in a template. */
4477static char *
4478format_expand1(struct format_expand_state *es, const char *fmt)
4479{
4480 struct format_tree *ft = es->ft;
4481 char *buf, *out, *name;
4482 const char *ptr, *s;
4483 size_t off, len, n, outlen;
4484 int ch, brackets;
4485 char expanded[8192];
4486
4487 if (fmt == NULL((void *)0) || *fmt == '\0')
4488 return (xstrdup(""));
4489
4490 if (es->loop == FORMAT_LOOP_LIMIT100) {
4491 format_log(es, "reached loop limit (%u)", FORMAT_LOOP_LIMIT)format_log1(es, __func__, "reached loop limit (%u)", 100);
4492 return (xstrdup(""));
4493 }
4494 es->loop++;
4495
4496 format_log(es, "expanding format: %s", fmt)format_log1(es, __func__, "expanding format: %s", fmt);
4497
4498 if ((es->flags & FORMAT_EXPAND_TIME0x1) && strchr(fmt, '%') != NULL((void *)0)) {
4499 if (es->time == 0) {
4500 es->time = time(NULL((void *)0));
4501 localtime_r(&es->time, &es->tm);
4502 }
4503 if (strftime(expanded, sizeof expanded, fmt, &es->tm) == 0) {
4504 format_log(es, "format is too long")format_log1(es, __func__, "format is too long");
4505 return (xstrdup(""));
4506 }
4507 if (format_logging(ft) && strcmp(expanded, fmt) != 0)
4508 format_log(es, "after time expanded: %s", expanded)format_log1(es, __func__, "after time expanded: %s", expanded
)
;
4509 fmt = expanded;
4510 }
4511
4512 len = 64;
4513 buf = xmalloc(len);
4514 off = 0;
4515
4516 while (*fmt != '\0') {
4517 if (*fmt != '#') {
4518 while (len - off < 2) {
4519 buf = xreallocarray(buf, 2, len);
4520 len *= 2;
4521 }
4522 buf[off++] = *fmt++;
4523 continue;
4524 }
4525 fmt++;
4526
4527 ch = (u_char)*fmt++;
4528 switch (ch) {
4529 case '(':
4530 brackets = 1;
4531 for (ptr = fmt; *ptr != '\0'; ptr++) {
4532 if (*ptr == '(')
4533 brackets++;
4534 if (*ptr == ')' && --brackets == 0)
4535 break;
4536 }
4537 if (*ptr != ')' || brackets != 0)
4538 break;
4539 n = ptr - fmt;
4540
4541 name = xstrndup(fmt, n);
4542 format_log(es, "found #(): %s", name)format_log1(es, __func__, "found #(): %s", name);
4543
4544 if ((ft->flags & FORMAT_NOJOBS0x4) ||
4545 (es->flags & FORMAT_EXPAND_NOJOBS0x2)) {
4546 out = xstrdup("");
4547 format_log(es, "#() is disabled")format_log1(es, __func__, "#() is disabled");
4548 } else {
4549 out = format_job_get(es, name);
4550 format_log(es, "#() result: %s", out)format_log1(es, __func__, "#() result: %s", out);
4551 }
4552 free(name);
4553
4554 outlen = strlen(out);
4555 while (len - off < outlen + 1) {
4556 buf = xreallocarray(buf, 2, len);
4557 len *= 2;
4558 }
4559 memcpy(buf + off, out, outlen);
4560 off += outlen;
4561
4562 free(out);
4563
4564 fmt += n + 1;
4565 continue;
4566 case '{':
4567 ptr = format_skip((char *)fmt - 2, "}");
4568 if (ptr == NULL((void *)0))
4569 break;
4570 n = ptr - fmt;
4571
4572 format_log(es, "found #{}: %.*s", (int)n, fmt)format_log1(es, __func__, "found #{}: %.*s", (int)n, fmt);
4573 if (format_replace(es, fmt, n, &buf, &len, &off) != 0)
4574 break;
4575 fmt += n + 1;
4576 continue;
4577 case '#':
4578 /*
4579 * If ##[ (with two or more #s), then it is a style and
4580 * can be left for format_draw to handle.
4581 */
4582 ptr = fmt;
4583 n = 2;
4584 while (*ptr == '#') {
4585 ptr++;
4586 n++;
4587 }
4588 if (*ptr == '[') {
4589 format_log(es, "found #*%zu[", n)format_log1(es, __func__, "found #*%zu[", n);
4590 while (len - off < n + 2) {
4591 buf = xreallocarray(buf, 2, len);
4592 len *= 2;
4593 }
4594 memcpy(buf + off, fmt - 2, n + 1);
4595 off += n + 1;
4596 fmt = ptr + 1;
4597 continue;
4598 }
4599 /* FALLTHROUGH */
4600 case '}':
4601 case ',':
4602 format_log(es, "found #%c", ch)format_log1(es, __func__, "found #%c", ch);
4603 while (len - off < 2) {
4604 buf = xreallocarray(buf, 2, len);
4605 len *= 2;
4606 }
4607 buf[off++] = ch;
4608 continue;
4609 default:
4610 s = NULL((void *)0);
4611 if (ch >= 'A' && ch <= 'Z')
4612 s = format_upper[ch - 'A'];
4613 else if (ch >= 'a' && ch <= 'z')
4614 s = format_lower[ch - 'a'];
4615 if (s == NULL((void *)0)) {
4616 while (len - off < 3) {
4617 buf = xreallocarray(buf, 2, len);
4618 len *= 2;
4619 }
4620 buf[off++] = '#';
4621 buf[off++] = ch;
4622 continue;
4623 }
4624 n = strlen(s);
4625 format_log(es, "found #%c: %s", ch, s)format_log1(es, __func__, "found #%c: %s", ch, s);
4626 if (format_replace(es, s, n, &buf, &len, &off) != 0)
4627 break;
4628 continue;
4629 }
4630
4631 break;
4632 }
4633 buf[off] = '\0';
4634
4635 format_log(es, "result is: %s", buf)format_log1(es, __func__, "result is: %s", buf);
4636 es->loop--;
4637
4638 return (buf);
4639}
4640
4641/* Expand keys in a template, passing through strftime first. */
4642char *
4643format_expand_time(struct format_tree *ft, const char *fmt)
4644{
4645 struct format_expand_state es;
4646
4647 memset(&es, 0, sizeof es);
4648 es.ft = ft;
4649 es.flags = FORMAT_EXPAND_TIME0x1;
4650 return (format_expand1(&es, fmt));
4651}
4652
4653/* Expand keys in a template. */
4654char *
4655format_expand(struct format_tree *ft, const char *fmt)
4656{
4657 struct format_expand_state es;
4658
4659 memset(&es, 0, sizeof es);
4660 es.ft = ft;
4661 es.flags = 0;
4662 return (format_expand1(&es, fmt));
4663}
4664
4665/* Expand a single string. */
4666char *
4667format_single(struct cmdq_item *item, const char *fmt, struct client *c,
4668 struct session *s, struct winlink *wl, struct window_pane *wp)
4669{
4670 struct format_tree *ft;
4671 char *expanded;
4672
4673 ft = format_create_defaults(item, c, s, wl, wp);
4674 expanded = format_expand(ft, fmt);
4675 format_free(ft);
4676 return (expanded);
4677}
4678
4679/* Expand a single string using state. */
4680char *
4681format_single_from_state(struct cmdq_item *item, const char *fmt,
4682 struct client *c, struct cmd_find_state *fs)
4683{
4684 return (format_single(item, fmt, c, fs->s, fs->wl, fs->wp));
4685}
4686
4687/* Expand a single string using target. */
4688char *
4689format_single_from_target(struct cmdq_item *item, const char *fmt)
4690{
4691 struct client *tc = cmdq_get_target_client(item);
4692
4693 return (format_single_from_state(item, fmt, tc, cmdq_get_target(item)));
4694}
4695
4696/* Create and add defaults. */
4697struct format_tree *
4698format_create_defaults(struct cmdq_item *item, struct client *c,
4699 struct session *s, struct winlink *wl, struct window_pane *wp)
4700{
4701 struct format_tree *ft;
4702
4703 if (item != NULL((void *)0))
4704 ft = format_create(cmdq_get_client(item), item, FORMAT_NONE0, 0);
4705 else
4706 ft = format_create(NULL((void *)0), item, FORMAT_NONE0, 0);
4707 format_defaults(ft, c, s, wl, wp);
4708 return (ft);
4709}
4710
4711/* Create and add defaults using state. */
4712struct format_tree *
4713format_create_from_state(struct cmdq_item *item, struct client *c,
4714 struct cmd_find_state *fs)
4715{
4716 return (format_create_defaults(item, c, fs->s, fs->wl, fs->wp));
4717}
4718
4719/* Create and add defaults using target. */
4720struct format_tree *
4721format_create_from_target(struct cmdq_item *item)
4722{
4723 struct client *tc = cmdq_get_target_client(item);
4724
4725 return (format_create_from_state(item, tc, cmdq_get_target(item)));
4726}
4727
4728/* Set defaults for any of arguments that are not NULL. */
4729void
4730format_defaults(struct format_tree *ft, struct client *c, struct session *s,
4731 struct winlink *wl, struct window_pane *wp)
4732{
4733 struct paste_buffer *pb;
4734
4735 if (c != NULL((void *)0) && c->name != NULL((void *)0))
4736 log_debug("%s: c=%s", __func__, c->name);
4737 else
4738 log_debug("%s: c=none", __func__);
4739 if (s != NULL((void *)0))
4740 log_debug("%s: s=$%u", __func__, s->id);
4741 else
4742 log_debug("%s: s=none", __func__);
4743 if (wl != NULL((void *)0))
4744 log_debug("%s: wl=%u", __func__, wl->idx);
4745 else
4746 log_debug("%s: wl=none", __func__);
4747 if (wp != NULL((void *)0))
4748 log_debug("%s: wp=%%%u", __func__, wp->id);
4749 else
4750 log_debug("%s: wp=none", __func__);
4751
4752 if (c != NULL((void *)0) && s != NULL((void *)0) && c->session != s)
4753 log_debug("%s: session does not match", __func__);
4754
4755 if (wp != NULL((void *)0))
4756 ft->type = FORMAT_TYPE_PANE;
4757 else if (wl != NULL((void *)0))
4758 ft->type = FORMAT_TYPE_WINDOW;
4759 else if (s != NULL((void *)0))
4760 ft->type = FORMAT_TYPE_SESSION;
4761 else
4762 ft->type = FORMAT_TYPE_UNKNOWN;
4763
4764 if (s == NULL((void *)0) && c != NULL((void *)0))
4765 s = c->session;
4766 if (wl == NULL((void *)0) && s != NULL((void *)0))
4767 wl = s->curw;
4768 if (wp == NULL((void *)0) && wl != NULL((void *)0))
4769 wp = wl->window->active;
4770
4771 if (c != NULL((void *)0))
4772 format_defaults_client(ft, c);
4773 if (s != NULL((void *)0))
4774 format_defaults_session(ft, s);
4775 if (wl != NULL((void *)0))
4776 format_defaults_winlink(ft, wl);
4777 if (wp != NULL((void *)0))
4778 format_defaults_pane(ft, wp);
4779
4780 pb = paste_get_top(NULL((void *)0));
4781 if (pb != NULL((void *)0))
4782 format_defaults_paste_buffer(ft, pb);
4783}
4784
4785/* Set default format keys for a session. */
4786static void
4787format_defaults_session(struct format_tree *ft, struct session *s)
4788{
4789 ft->s = s;
4790}
4791
4792/* Set default format keys for a client. */
4793static void
4794format_defaults_client(struct format_tree *ft, struct client *c)
4795{
4796 if (ft->s == NULL((void *)0))
4797 ft->s = c->session;
4798 ft->c = c;
4799}
4800
4801/* Set default format keys for a window. */
4802void
4803format_defaults_window(struct format_tree *ft, struct window *w)
4804{
4805 ft->w = w;
4806}
4807
4808/* Set default format keys for a winlink. */
4809static void
4810format_defaults_winlink(struct format_tree *ft, struct winlink *wl)
4811{
4812 if (ft->w == NULL((void *)0))
4813 format_defaults_window(ft, wl->window);
4814 ft->wl = wl;
4815}
4816
4817/* Set default format keys for a window pane. */
4818void
4819format_defaults_pane(struct format_tree *ft, struct window_pane *wp)
4820{
4821 struct window_mode_entry *wme;
4822
4823 if (ft->w == NULL((void *)0))
4824 format_defaults_window(ft, wp->window);
4825 ft->wp = wp;
4826
4827 wme = TAILQ_FIRST(&wp->modes)((&wp->modes)->tqh_first);
4828 if (wme != NULL((void *)0) && wme->mode->formats != NULL((void *)0))
4829 wme->mode->formats(wme, ft);
4830}
4831
4832/* Set default format keys for paste buffer. */
4833void
4834format_defaults_paste_buffer(struct format_tree *ft, struct paste_buffer *pb)
4835{
4836 ft->pb = pb;
4837}
4838
4839/* Return word at given coordinates. Caller frees. */
4840char *
4841format_grid_word(struct grid *gd, u_int x, u_int y)
4842{
4843 const struct grid_line *gl;
4844 struct grid_cell gc;
4845 const char *ws;
4846 struct utf8_data *ud = NULL((void *)0);
4847 u_int end;
4848 size_t size = 0;
4849 int found = 0;
4850 char *s = NULL((void *)0);
4851
4852 ws = options_get_string(global_s_options, "word-separators");
4853
4854 for (;;) {
4855 grid_get_cell(gd, x, y, &gc);
4856 if (gc.flags & GRID_FLAG_PADDING0x4)
4857 break;
4858 if (utf8_cstrhas(ws, &gc.data) ||
4859 (gc.data.size == 1 && *gc.data.data == ' ')) {
4860 found = 1;
4861 break;
4862 }
4863
4864 if (x == 0) {
4865 if (y == 0)
4866 break;
4867 gl = grid_peek_line(gd, y - 1);
4868 if (~gl->flags & GRID_LINE_WRAPPED0x1)
4869 break;
4870 y--;
4871 x = grid_line_length(gd, y);
4872 if (x == 0)
4873 break;
4874 }
4875 x--;
4876 }
4877 for (;;) {
4878 if (found) {
4879 end = grid_line_length(gd, y);
4880 if (end == 0 || x == end - 1) {
4881 if (y == gd->hsize + gd->sy - 1)
4882 break;
4883 gl = grid_peek_line(gd, y);
4884 if (~gl->flags & GRID_LINE_WRAPPED0x1)
4885 break;
4886 y++;
4887 x = 0;
4888 } else
4889 x++;
4890 }
4891 found = 1;
4892
4893 grid_get_cell(gd, x, y, &gc);
4894 if (gc.flags & GRID_FLAG_PADDING0x4)
4895 break;
4896 if (utf8_cstrhas(ws, &gc.data) ||
4897 (gc.data.size == 1 && *gc.data.data == ' '))
4898 break;
4899
4900 ud = xreallocarray(ud, size + 2, sizeof *ud);
4901 memcpy(&ud[size++], &gc.data, sizeof *ud);
4902 }
4903 if (size != 0) {
4904 ud[size].size = 0;
4905 s = utf8_tocstr(ud);
4906 free(ud);
4907 }
4908 return (s);
4909}
4910
4911/* Return line at given coordinates. Caller frees. */
4912char *
4913format_grid_line(struct grid *gd, u_int y)
4914{
4915 struct grid_cell gc;
4916 struct utf8_data *ud = NULL((void *)0);
4917 u_int x;
4918 size_t size = 0;
4919 char *s = NULL((void *)0);
4920
4921 for (x = 0; x < grid_line_length(gd, y); x++) {
4922 grid_get_cell(gd, x, y, &gc);
4923 if (gc.flags & GRID_FLAG_PADDING0x4)
4924 break;
4925
4926 ud = xreallocarray(ud, size + 2, sizeof *ud);
4927 memcpy(&ud[size++], &gc.data, sizeof *ud);
4928 }
4929 if (size != 0) {
4930 ud[size].size = 0;
4931 s = utf8_tocstr(ud);
4932 free(ud);
4933 }
4934 return (s);
4935}