Bug Summary

File:src/usr.bin/tmux/format.c
Warning:line 4451, column 13
1st function call argument is an uninitialized value

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));
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;
1
'value' declared without an initial value
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++) {
2
Assuming 'i' is < 'count'
3
Loop condition is true. Entering loop body
16
Assuming 'i' is >= 'count'
17
Loop condition is false. Execution continues on line 4191
4071 fm = &list[i];
4072 if (format_logging(ft)) {
4
Assuming the condition is false
5
Taking false branch
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) {
6
Assuming field 'size' is not equal to 1
7
Taking false branch
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) {
8
Assuming field 'size' is equal to 2
9
Taking true branch
4180 if (strcmp(fm->modifier, "||") == 0 ||
10
Assuming the condition is false
15
Taking true branch
4181 strcmp(fm->modifier, "&&") == 0 ||
11
Assuming the condition is false
4182 strcmp(fm->modifier, "==") == 0 ||
12
Assuming the condition is false
4183 strcmp(fm->modifier, "!=") == 0 ||
13
Assuming the condition is false
4184 strcmp(fm->modifier, ">=") == 0 ||
14
Assuming the condition is false
4185 strcmp(fm->modifier, "<=") == 0)
4186 cmp = fm;
4187 }
4188 }
4189
4190 /* Is this a literal string? */
4191 if (modifiers & FORMAT_LITERAL0x10) {
18
Taking false branch
4192 value = xstrdup(copy);
4193 goto done;
4194 }
4195
4196 /* Is this a character? */
4197 if (modifiers & FORMAT_CHARACTER0x10000) {
19
Taking false branch
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) {
20
Taking false branch
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) {
21
Taking false branch
4222 value = format_loop_sessions(es, copy);
4223 if (value == NULL((void *)0))
4224 goto fail;
4225 } else if (modifiers & FORMAT_WINDOWS0x100) {
22
Taking false branch
4226 value = format_loop_windows(es, copy);
4227 if (value == NULL((void *)0))
4228 goto fail;
4229 } else if (modifiers & FORMAT_PANES0x200) {
23
Taking false branch
4230 value = format_loop_panes(es, copy);
4231 if (value == NULL((void *)0))
4232 goto fail;
4233 } else if (modifiers & FORMAT_WINDOW_NAME0x4000) {
24
Taking false branch
4234 value = format_window_name(es, copy);
4235 if (value == NULL((void *)0))
4236 goto fail;
4237 } else if (modifiers & FORMAT_SESSION_NAME0x8000) {
25
Taking false branch
4238 value = format_session_name(es, copy);
4239 if (value == NULL((void *)0))
4240 goto fail;
4241 } else if (search
25.1
'search' is equal to NULL
!= NULL((void *)0)) {
26
Taking false branch
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
26.1
'cmp' is not equal to NULL
!= NULL((void *)0)) {
27
Taking true branch
4253 /* Comparison of left and right. */
4254 if (format_choose(es, copy, &left, &right, 1) != 0) {
28
Taking false branch
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) {
29
Assuming the condition is false
30
Taking false branch
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) {
31
Assuming the condition is false
32
Taking false branch
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) {
33
Assuming the condition is false
34
Taking false branch
4273 if (strcmp(left, right) == 0)
4274 value = xstrdup("1");
4275 else
4276 value = xstrdup("0");
4277 } else if (strcmp(cmp->modifier, "!=") == 0) {
35
Assuming the condition is false
36
Taking false branch
4278 if (strcmp(left, right) != 0)
4279 value = xstrdup("1");
4280 else
4281 value = xstrdup("0");
4282 } else if (strcmp(cmp->modifier, "<") == 0) {
37
Assuming the condition is false
38
Taking false branch
4283 if (strcmp(left, right) < 0)
4284 value = xstrdup("1");
4285 else
4286 value = xstrdup("0");
4287 } else if (strcmp(cmp->modifier, ">") == 0) {
39
Assuming the condition is false
40
Taking false branch
4288 if (strcmp(left, right) > 0)
4289 value = xstrdup("1");
4290 else
4291 value = xstrdup("0");
4292 } else if (strcmp(cmp->modifier, "<=") == 0) {
41
Assuming the condition is false
42
Taking false branch
4293 if (strcmp(left, right) <= 0)
4294 value = xstrdup("1");
4295 else
4296 value = xstrdup("0");
4297 } else if (strcmp(cmp->modifier, ">=") == 0) {
43
Assuming the condition is false
44
Taking false branch
4298 if (strcmp(left, right) >= 0)
4299 value = xstrdup("1");
4300 else
4301 value = xstrdup("0");
4302 } else if (strcmp(cmp->modifier, "m") == 0)
45
Assuming the condition is false
46
Taking false branch
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) {
47
Taking false branch
4378 new = format_expand1(es, value);
4379 free(value);
4380 value = new;
4381 } else if (modifiers & FORMAT_EXPANDTIME0x40) {
48
Taking false branch
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++) {
49
Loop condition is false. Execution continues on line 4401
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
49.1
'limit' is <= 0
> 0) {
50
Taking false branch
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
50.1
'limit' is >= 0
< 0) {
51
Taking false branch
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
51.1
'width' is <= 0
> 0) {
52
Taking false branch
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
52.1
'width' is >= 0
< 0) {
53
Taking false branch
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) {
54
Taking false branch
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) {
55
Taking false branch
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);
56
1st function call argument is an uninitialized 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}