File: | src/usr.bin/tmux/format.c |
Warning: | line 1126, column 12 Although the value stored to 's' is used in the enclosing expression, the value is never actually read from 's' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | |
41 | struct format_expand_state; |
42 | |
43 | static char *format_job_get(struct format_expand_state *, const char *); |
44 | static char *format_expand1(struct format_expand_state *, const char *); |
45 | static int format_replace(struct format_expand_state *, const char *, |
46 | size_t, char **, size_t *, size_t *); |
47 | static void format_defaults_session(struct format_tree *, |
48 | struct session *); |
49 | static void format_defaults_client(struct format_tree *, struct client *); |
50 | static void format_defaults_winlink(struct format_tree *, |
51 | struct winlink *); |
52 | |
53 | /* Entry in format job tree. */ |
54 | struct 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. */ |
71 | static int format_job_cmp(struct format_job *, struct format_job *); |
72 | static RB_HEAD(format_job_tree, format_job)struct format_job_tree { struct format_job *rbh_root; } format_jobs = RB_INITIALIZER(){ ((void *)0) }; |
73 | RB_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. */ |
76 | static int |
77 | format_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. */ |
114 | struct 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. */ |
123 | enum format_type { |
124 | FORMAT_TYPE_UNKNOWN, |
125 | FORMAT_TYPE_SESSION, |
126 | FORMAT_TYPE_WINDOW, |
127 | FORMAT_TYPE_PANE |
128 | }; |
129 | |
130 | struct 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 | }; |
149 | static int format_entry_cmp(struct format_entry *, struct format_entry *); |
150 | RB_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. */ |
153 | struct 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. */ |
162 | struct 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. */ |
171 | static int |
172 | format_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. */ |
178 | static 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. */ |
208 | static 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? */ |
238 | static inline int |
239 | format_logging(struct format_tree *ft) |
240 | { |
241 | return (log_get_level() != 0 || (ft->flags & FORMAT_VERBOSE0x8)); |
242 | } |
243 | |
244 | /* Log a message if verbose. */ |
245 | static void printflike(3, 4)__attribute__ ((format (printf, 3, 4))) |
246 | format_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. */ |
270 | static void |
271 | format_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. */ |
282 | static void |
283 | format_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. */ |
312 | static void |
313 | format_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. */ |
348 | static char * |
349 | format_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. */ |
415 | static void |
416 | format_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. */ |
441 | void |
442 | format_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. */ |
454 | void |
455 | format_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. */ |
463 | static char * printflike(1, 2)__attribute__ ((format (printf, 1, 2))) |
464 | format_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. */ |
476 | static void * |
477 | format_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. */ |
487 | static void * |
488 | format_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. */ |
500 | static void * |
501 | format_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. */ |
510 | static void * |
511 | format_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. */ |
541 | static void * |
542 | format_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. */ |
571 | static void * |
572 | format_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. */ |
593 | static void * |
594 | format_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. */ |
618 | static void * |
619 | format_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. */ |
648 | static void * |
649 | format_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. */ |
670 | static void * |
671 | format_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. */ |
702 | static void * |
703 | format_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. */ |
729 | static void * |
730 | format_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. */ |
766 | static void * |
767 | format_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. */ |
780 | static void * |
781 | format_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. */ |
792 | static void * |
793 | format_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. */ |
804 | static void * |
805 | format_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. */ |
828 | static void * |
829 | format_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. */ |
844 | static void * |
845 | format_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. */ |
870 | static void * |
871 | format_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. */ |
897 | static void * |
898 | format_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. */ |
927 | static void * |
928 | format_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. */ |
941 | static void * |
942 | format_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. */ |
955 | static void * |
956 | format_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. */ |
988 | static void * |
989 | format_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. */ |
1028 | static void * |
1029 | format_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. */ |
1046 | static void * |
1047 | format_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. */ |
1068 | static void * |
1069 | format_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. */ |
1090 | static void * |
1091 | format_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. */ |
1107 | static void * |
1108 | format_cb_mouse_word(struct format_tree *ft) |
1109 | { |
1110 | struct window_pane *wp; |
1111 | struct grid *gd; |
1112 | u_int x, y; |
1113 | char *s; |
1114 | |
1115 | if (!ft->m.valid) |
1116 | return (NULL((void *)0)); |
1117 | wp = cmd_mouse_pane(&ft->m, NULL((void *)0), NULL((void *)0)); |
1118 | if (wp == NULL((void *)0)) |
1119 | return (NULL((void *)0)); |
1120 | if (cmd_mouse_at(wp, &ft->m, &x, &y, 0) != 0) |
1121 | return (NULL((void *)0)); |
1122 | |
1123 | if (!TAILQ_EMPTY(&wp->modes)(((&wp->modes)->tqh_first) == ((void *)0))) { |
1124 | if (TAILQ_FIRST(&wp->modes)((&wp->modes)->tqh_first)->mode == &window_copy_mode || |
1125 | TAILQ_FIRST(&wp->modes)((&wp->modes)->tqh_first)->mode == &window_view_mode) |
1126 | return (s = window_copy_get_word(wp, x, y)); |
Although the value stored to 's' is used in the enclosing expression, the value is never actually read from 's' | |
1127 | return (NULL((void *)0)); |
1128 | } |
1129 | gd = wp->base.grid; |
1130 | return (format_grid_word(gd, x, gd->hsize + y)); |
1131 | } |
1132 | |
1133 | /* Callback for mouse_line. */ |
1134 | static void * |
1135 | format_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. */ |
1160 | static void * |
1161 | format_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. */ |
1172 | static void * |
1173 | format_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. */ |
1181 | static void * |
1182 | format_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. */ |
1190 | static void * |
1191 | format_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. */ |
1199 | static void * |
1200 | format_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. */ |
1208 | static void * |
1209 | format_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. */ |
1221 | static void * |
1222 | format_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. */ |
1230 | static void * |
1231 | format_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. */ |
1239 | static void * |
1240 | format_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. */ |
1251 | static void * |
1252 | format_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. */ |
1260 | static void * |
1261 | format_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. */ |
1269 | static void * |
1270 | format_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. */ |
1278 | static void * |
1279 | format_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. */ |
1287 | static void * |
1288 | format_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. */ |
1298 | static void * |
1299 | format_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. */ |
1307 | static void * |
1308 | format_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. */ |
1316 | static void * |
1317 | format_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. */ |
1331 | static void * |
1332 | format_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. */ |
1343 | static void * |
1344 | format_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. */ |
1352 | static void * |
1353 | format_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. */ |
1361 | static void * |
1362 | format_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. */ |
1370 | static void * |
1371 | format_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. */ |
1382 | static void * |
1383 | format_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. */ |
1391 | static void * |
1392 | format_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. */ |
1403 | static void * |
1404 | format_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. */ |
1412 | static void * |
1413 | format_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. */ |
1421 | static void * |
1422 | format_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. */ |
1441 | static void * |
1442 | format_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. */ |
1453 | static void * |
1454 | format_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. */ |
1462 | static void * |
1463 | format_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. */ |
1471 | static void * |
1472 | format_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. */ |
1480 | static void * |
1481 | format_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. */ |
1489 | static void * |
1490 | format_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. */ |
1501 | static void * |
1502 | format_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. */ |
1513 | static void * |
1514 | format_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. */ |
1525 | static void * |
1526 | format_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. */ |
1537 | static void * |
1538 | format_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. */ |
1549 | static void * |
1550 | format_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. */ |
1561 | static void * |
1562 | format_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. */ |
1576 | static void * |
1577 | format_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. */ |
1588 | static void * |
1589 | format_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. */ |
1600 | static void * |
1601 | format_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. */ |
1612 | static void * |
1613 | format_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. */ |
1633 | static void * |
1634 | format_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. */ |
1654 | static void * |
1655 | format_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. */ |
1666 | static void * |
1667 | format_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. */ |
1678 | static void * |
1679 | format_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. */ |
1690 | static void * |
1691 | format_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. */ |
1702 | static void * |
1703 | format_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. */ |
1711 | static void * |
1712 | format_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. */ |
1723 | static void * |
1724 | format_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. */ |
1737 | static void * |
1738 | format_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. */ |
1746 | static void * |
1747 | format_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. */ |
1755 | static void * |
1756 | format_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. */ |
1764 | static void * |
1765 | format_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. */ |
1775 | static void * |
1776 | format_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. */ |
1787 | static void * |
1788 | format_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. */ |
1799 | static void * |
1800 | format_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. */ |
1808 | static void * |
1809 | format_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. */ |
1820 | static void * |
1821 | format_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. */ |
1832 | static void * |
1833 | format_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. */ |
1847 | static void * |
1848 | format_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. */ |
1859 | static void * |
1860 | format_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. */ |
1868 | static void * |
1869 | format_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. */ |
1880 | static void * |
1881 | format_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. */ |
1889 | static void * |
1890 | format_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. */ |
1901 | static void * |
1902 | format_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. */ |
1913 | static void * |
1914 | format_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. */ |
1922 | static void * |
1923 | format_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. */ |
1931 | static void * |
1932 | format_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. */ |
1940 | static void * |
1941 | format_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. */ |
1949 | static void * |
1950 | format_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. */ |
1958 | static void * |
1959 | format_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. */ |
1967 | static void * |
1968 | format_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. */ |
1976 | static void * |
1977 | format_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. */ |
1985 | static void * |
1986 | format_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. */ |
1996 | static void * |
1997 | format_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. */ |
2007 | static void * |
2008 | format_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. */ |
2021 | static void * |
2022 | format_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. */ |
2032 | static void * |
2033 | format_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. */ |
2044 | static void * |
2045 | format_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. */ |
2053 | static void * |
2054 | format_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. */ |
2065 | static void * |
2066 | format_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. */ |
2077 | static void * |
2078 | format_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. */ |
2086 | static void * |
2087 | format_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. */ |
2095 | static void * |
2096 | format_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. */ |
2104 | static void * |
2105 | format_cb_socket_path(__unused__attribute__((__unused__)) struct format_tree *ft) |
2106 | { |
2107 | return (xstrdup(socket_path)); |
2108 | } |
2109 | |
2110 | /* Callback for version. */ |
2111 | static void * |
2112 | format_cb_version(__unused__attribute__((__unused__)) struct format_tree *ft) |
2113 | { |
2114 | return (xstrdup(getversion())); |
2115 | } |
2116 | |
2117 | /* Callback for active_window_index. */ |
2118 | static void * |
2119 | format_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. */ |
2127 | static void * |
2128 | format_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. */ |
2140 | static void * |
2141 | format_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. */ |
2152 | static void * |
2153 | format_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. */ |
2164 | static void * |
2165 | format_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. */ |
2176 | static void * |
2177 | format_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. */ |
2190 | static void * |
2191 | format_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. */ |
2199 | static void * |
2200 | format_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. */ |
2208 | static void * |
2209 | format_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. */ |
2220 | static void * |
2221 | format_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. */ |
2229 | static void * |
2230 | format_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. */ |
2238 | static void * |
2239 | format_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. */ |
2247 | static void * |
2248 | format_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. */ |
2256 | static void * |
2257 | format_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. */ |
2265 | static void * |
2266 | format_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. */ |
2277 | static void * |
2278 | format_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. */ |
2289 | static void * |
2290 | format_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. */ |
2298 | static void * |
2299 | format_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. */ |
2310 | static void * |
2311 | format_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. */ |
2319 | static void * |
2320 | format_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. */ |
2333 | static void * |
2334 | format_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. */ |
2347 | static void * |
2348 | format_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. */ |
2356 | static void * |
2357 | format_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. */ |
2365 | static void * |
2366 | format_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. */ |
2377 | static void * |
2378 | format_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. */ |
2389 | static void * |
2390 | format_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. */ |
2398 | static void * |
2399 | format_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. */ |
2410 | static void * |
2411 | format_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. */ |
2422 | static void * |
2423 | format_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. */ |
2436 | static void * |
2437 | format_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. */ |
2445 | static void * |
2446 | format_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. */ |
2454 | static void * |
2455 | format_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. */ |
2463 | static void * |
2464 | format_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. */ |
2472 | static void * |
2473 | format_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. */ |
2481 | static void * |
2482 | format_cb_start_time(__unused__attribute__((__unused__)) struct format_tree *ft) |
2483 | { |
2484 | return (&start_time); |
2485 | } |
2486 | |
2487 | /* Callback for window_activity. */ |
2488 | static void * |
2489 | format_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, */ |
2497 | static void * |
2498 | format_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, */ |
2504 | static void * |
2505 | format_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, */ |
2511 | static void * |
2512 | format_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. */ |
2518 | enum format_table_type { |
2519 | FORMAT_TABLE_STRING, |
2520 | FORMAT_TABLE_TIME |
2521 | }; |
2522 | |
2523 | /* Format table entry. */ |
2524 | struct 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 | */ |
2535 | static 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. */ |
3010 | static int |
3011 | format_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. */ |
3020 | static struct format_table_entry * |
3021 | format_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. */ |
3028 | void |
3029 | format_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. */ |
3040 | struct window_pane * |
3041 | format_get_pane(struct format_tree *ft) |
3042 | { |
3043 | return (ft->wp); |
3044 | } |
3045 | |
3046 | /* Add item bits to tree. */ |
3047 | static void |
3048 | format_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. */ |
3058 | struct format_tree * |
3059 | format_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. */ |
3082 | void |
3083 | format_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. */ |
3100 | static void |
3101 | format_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. */ |
3109 | void |
3110 | format_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. */ |
3116 | void |
3117 | format_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. */ |
3158 | void |
3159 | format_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. */ |
3185 | void |
3186 | format_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. */ |
3208 | void |
3209 | format_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. */ |
3232 | static char * |
3233 | format_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. */ |
3249 | static char * |
3250 | format_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. */ |
3266 | static char * |
3267 | format_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. */ |
3307 | static char * |
3308 | format_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 | |
3377 | found: |
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. */ |
3430 | static char * |
3431 | format_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. */ |
3454 | const char * |
3455 | format_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. */ |
3477 | static int |
3478 | format_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? */ |
3503 | int |
3504 | format_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. */ |
3512 | static int |
3513 | format_is_end(char c) |
3514 | { |
3515 | return (c == ';' || c == ':'); |
3516 | } |
3517 | |
3518 | /* Add to modifier list. */ |
3519 | static void |
3520 | format_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. */ |
3537 | static void |
3538 | format_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. */ |
3548 | static struct format_modifier * |
3549 | format_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. */ |
3659 | static char * |
3660 | format_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. */ |
3689 | static char * |
3690 | format_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. */ |
3705 | static char * |
3706 | format_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? */ |
3722 | static char * |
3723 | format_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. */ |
3740 | static char * |
3741 | format_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? */ |
3775 | static char * |
3776 | format_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. */ |
3799 | static char * |
3800 | format_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. */ |
3853 | static char * |
3854 | format_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 | |
3904 | static char * |
3905 | format_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 | |
4040 | fail: |
4041 | free(right); |
4042 | free(left); |
4043 | return (NULL((void *)0)); |
4044 | } |
4045 | |
4046 | /* Replace a key. */ |
4047 | static int |
4048 | format_replace(struct format_expand_state *es, const char *key, size_t keylen, |
4049 | char **buf, size_t *len, size_t *off) |
4050 | { |
4051 | struct format_tree *ft = es->ft; |
4052 | struct window_pane *wp = ft->wp; |
4053 | const char *errstr, *copy, *cp, *marker = NULL((void *)0); |
4054 | const char *time_format = NULL((void *)0); |
4055 | char *copy0, *condition, *found, *new; |
4056 | char *value, *left, *right; |
4057 | size_t valuelen; |
4058 | int modifiers = 0, limit = 0, width = 0; |
4059 | int j, c; |
4060 | struct format_modifier *list, *cmp = NULL((void *)0), *search = NULL((void *)0); |
4061 | struct format_modifier **sub = NULL((void *)0), *mexp = NULL((void *)0), *fm; |
4062 | u_int i, count, nsub = 0; |
4063 | struct format_expand_state next; |
4064 | |
4065 | /* Make a copy of the key. */ |
4066 | copy = copy0 = xstrndup(key, keylen); |
4067 | |
4068 | /* Process modifier list. */ |
4069 | list = format_build_modifiers(es, ©, &count); |
4070 | for (i = 0; i < count; i++) { |
4071 | fm = &list[i]; |
4072 | if (format_logging(ft)) { |
4073 | format_log(es, "modifier %u is %s", i, fm->modifier)format_log1(es, __func__, "modifier %u is %s", i, fm->modifier ); |
4074 | for (j = 0; j < fm->argc; j++) { |
4075 | format_log(es, "modifier %u argument %d: %s", i,format_log1(es, __func__, "modifier %u argument %d: %s", i, j , fm->argv[j]) |
4076 | j, fm->argv[j])format_log1(es, __func__, "modifier %u argument %d: %s", i, j , fm->argv[j]); |
4077 | } |
4078 | } |
4079 | if (fm->size == 1) { |
4080 | switch (fm->modifier[0]) { |
4081 | case 'm': |
4082 | case '<': |
4083 | case '>': |
4084 | cmp = fm; |
4085 | break; |
4086 | case 'C': |
4087 | search = fm; |
4088 | break; |
4089 | case 's': |
4090 | if (fm->argc < 2) |
4091 | break; |
4092 | sub = xreallocarray(sub, nsub + 1, sizeof *sub); |
4093 | sub[nsub++] = fm; |
4094 | break; |
4095 | case '=': |
4096 | if (fm->argc < 1) |
4097 | break; |
4098 | limit = strtonum(fm->argv[0], INT_MIN(-2147483647 -1), INT_MAX2147483647, |
4099 | &errstr); |
4100 | if (errstr != NULL((void *)0)) |
4101 | limit = 0; |
4102 | if (fm->argc >= 2 && fm->argv[1] != NULL((void *)0)) |
4103 | marker = fm->argv[1]; |
4104 | break; |
4105 | case 'p': |
4106 | if (fm->argc < 1) |
4107 | break; |
4108 | width = strtonum(fm->argv[0], INT_MIN(-2147483647 -1), INT_MAX2147483647, |
4109 | &errstr); |
4110 | if (errstr != NULL((void *)0)) |
4111 | width = 0; |
4112 | break; |
4113 | case 'w': |
4114 | modifiers |= FORMAT_WIDTH0x1000; |
4115 | break; |
4116 | case 'e': |
4117 | if (fm->argc < 1 || fm->argc > 3) |
4118 | break; |
4119 | mexp = fm; |
4120 | break; |
4121 | case 'l': |
4122 | modifiers |= FORMAT_LITERAL0x10; |
4123 | break; |
4124 | case 'a': |
4125 | modifiers |= FORMAT_CHARACTER0x10000; |
4126 | break; |
4127 | case 'b': |
4128 | modifiers |= FORMAT_BASENAME0x2; |
4129 | break; |
4130 | case 'c': |
4131 | modifiers |= FORMAT_COLOUR0x20000; |
4132 | break; |
4133 | case 'd': |
4134 | modifiers |= FORMAT_DIRNAME0x4; |
4135 | break; |
4136 | case 'n': |
4137 | modifiers |= FORMAT_LENGTH0x800; |
4138 | break; |
4139 | case 't': |
4140 | modifiers |= FORMAT_TIMESTRING0x1; |
4141 | if (fm->argc < 1) |
4142 | break; |
4143 | if (strchr(fm->argv[0], 'p') != NULL((void *)0)) |
4144 | modifiers |= FORMAT_PRETTY0x400; |
4145 | else if (fm->argc >= 2 && |
4146 | strchr(fm->argv[0], 'f') != NULL((void *)0)) |
4147 | time_format = format_strip(fm->argv[1]); |
4148 | break; |
4149 | case 'q': |
4150 | if (fm->argc < 1) |
4151 | modifiers |= FORMAT_QUOTE_SHELL0x8; |
4152 | else if (strchr(fm->argv[0], 'e') != NULL((void *)0) || |
4153 | strchr(fm->argv[0], 'h') != NULL((void *)0)) |
4154 | modifiers |= FORMAT_QUOTE_STYLE0x2000; |
4155 | break; |
4156 | case 'E': |
4157 | modifiers |= FORMAT_EXPAND0x20; |
4158 | break; |
4159 | case 'T': |
4160 | modifiers |= FORMAT_EXPANDTIME0x40; |
4161 | break; |
4162 | case 'N': |
4163 | if (fm->argc < 1 || |
4164 | strchr(fm->argv[0], 'w') != NULL((void *)0)) |
4165 | modifiers |= FORMAT_WINDOW_NAME0x4000; |
4166 | else if (strchr(fm->argv[0], 's') != NULL((void *)0)) |
4167 | modifiers |= FORMAT_SESSION_NAME0x8000; |
4168 | break; |
4169 | case 'S': |
4170 | modifiers |= FORMAT_SESSIONS0x80; |
4171 | break; |
4172 | case 'W': |
4173 | modifiers |= FORMAT_WINDOWS0x100; |
4174 | break; |
4175 | case 'P': |
4176 | modifiers |= FORMAT_PANES0x200; |
4177 | break; |
4178 | } |
4179 | } else if (fm->size == 2) { |
4180 | if (strcmp(fm->modifier, "||") == 0 || |
4181 | strcmp(fm->modifier, "&&") == 0 || |
4182 | strcmp(fm->modifier, "==") == 0 || |
4183 | strcmp(fm->modifier, "!=") == 0 || |
4184 | strcmp(fm->modifier, ">=") == 0 || |
4185 | strcmp(fm->modifier, "<=") == 0) |
4186 | cmp = fm; |
4187 | } |
4188 | } |
4189 | |
4190 | /* Is this a literal string? */ |
4191 | if (modifiers & FORMAT_LITERAL0x10) { |
4192 | value = xstrdup(copy); |
4193 | goto done; |
4194 | } |
4195 | |
4196 | /* Is this a character? */ |
4197 | if (modifiers & FORMAT_CHARACTER0x10000) { |
4198 | new = format_expand1(es, copy); |
4199 | c = strtonum(new, 32, 126, &errstr); |
4200 | if (errstr != NULL((void *)0)) |
4201 | value = xstrdup(""); |
4202 | else |
4203 | xasprintf(&value, "%c", c); |
4204 | free(new); |
4205 | goto done; |
4206 | } |
4207 | |
4208 | /* Is this a colour? */ |
4209 | if (modifiers & FORMAT_COLOUR0x20000) { |
4210 | new = format_expand1(es, copy); |
4211 | c = colour_fromstring(new); |
4212 | if (c == -1 || (c = colour_force_rgb(c)) == -1) |
4213 | value = xstrdup(""); |
4214 | else |
4215 | xasprintf(&value, "%06x", c & 0xffffff); |
4216 | free(new); |
4217 | goto done; |
4218 | } |
4219 | |
4220 | /* Is this a loop, comparison or condition? */ |
4221 | if (modifiers & FORMAT_SESSIONS0x80) { |
4222 | value = format_loop_sessions(es, copy); |
4223 | if (value == NULL((void *)0)) |
4224 | goto fail; |
4225 | } else if (modifiers & FORMAT_WINDOWS0x100) { |
4226 | value = format_loop_windows(es, copy); |
4227 | if (value == NULL((void *)0)) |
4228 | goto fail; |
4229 | } else if (modifiers & FORMAT_PANES0x200) { |
4230 | value = format_loop_panes(es, copy); |
4231 | if (value == NULL((void *)0)) |
4232 | goto fail; |
4233 | } else if (modifiers & FORMAT_WINDOW_NAME0x4000) { |
4234 | value = format_window_name(es, copy); |
4235 | if (value == NULL((void *)0)) |
4236 | goto fail; |
4237 | } else if (modifiers & FORMAT_SESSION_NAME0x8000) { |
4238 | value = format_session_name(es, copy); |
4239 | if (value == NULL((void *)0)) |
4240 | goto fail; |
4241 | } else if (search != NULL((void *)0)) { |
4242 | /* Search in pane. */ |
4243 | new = format_expand1(es, copy); |
4244 | if (wp == NULL((void *)0)) { |
4245 | format_log(es, "search '%s' but no pane", new)format_log1(es, __func__, "search '%s' but no pane", new); |
4246 | value = xstrdup("0"); |
4247 | } else { |
4248 | format_log(es, "search '%s' pane %%%u", new, wp->id)format_log1(es, __func__, "search '%s' pane %%%u", new, wp-> id); |
4249 | value = format_search(search, wp, new); |
4250 | } |
4251 | free(new); |
4252 | } else if (cmp != NULL((void *)0)) { |
4253 | /* Comparison of left and right. */ |
4254 | if (format_choose(es, copy, &left, &right, 1) != 0) { |
4255 | format_log(es, "compare %s syntax error: %s",format_log1(es, __func__, "compare %s syntax error: %s", cmp-> modifier, copy) |
4256 | cmp->modifier, copy)format_log1(es, __func__, "compare %s syntax error: %s", cmp-> modifier, copy); |
4257 | goto fail; |
4258 | } |
4259 | format_log(es, "compare %s left is: %s", cmp->modifier, left)format_log1(es, __func__, "compare %s left is: %s", cmp->modifier , left); |
4260 | format_log(es, "compare %s right is: %s", cmp->modifier, right)format_log1(es, __func__, "compare %s right is: %s", cmp-> modifier, right); |
4261 | |
4262 | if (strcmp(cmp->modifier, "||") == 0) { |
4263 | if (format_true(left) || format_true(right)) |
4264 | value = xstrdup("1"); |
4265 | else |
4266 | value = xstrdup("0"); |
4267 | } else if (strcmp(cmp->modifier, "&&") == 0) { |
4268 | if (format_true(left) && format_true(right)) |
4269 | value = xstrdup("1"); |
4270 | else |
4271 | value = xstrdup("0"); |
4272 | } else if (strcmp(cmp->modifier, "==") == 0) { |
4273 | if (strcmp(left, right) == 0) |
4274 | value = xstrdup("1"); |
4275 | else |
4276 | value = xstrdup("0"); |
4277 | } else if (strcmp(cmp->modifier, "!=") == 0) { |
4278 | if (strcmp(left, right) != 0) |
4279 | value = xstrdup("1"); |
4280 | else |
4281 | value = xstrdup("0"); |
4282 | } else if (strcmp(cmp->modifier, "<") == 0) { |
4283 | if (strcmp(left, right) < 0) |
4284 | value = xstrdup("1"); |
4285 | else |
4286 | value = xstrdup("0"); |
4287 | } else if (strcmp(cmp->modifier, ">") == 0) { |
4288 | if (strcmp(left, right) > 0) |
4289 | value = xstrdup("1"); |
4290 | else |
4291 | value = xstrdup("0"); |
4292 | } else if (strcmp(cmp->modifier, "<=") == 0) { |
4293 | if (strcmp(left, right) <= 0) |
4294 | value = xstrdup("1"); |
4295 | else |
4296 | value = xstrdup("0"); |
4297 | } else if (strcmp(cmp->modifier, ">=") == 0) { |
4298 | if (strcmp(left, right) >= 0) |
4299 | value = xstrdup("1"); |
4300 | else |
4301 | value = xstrdup("0"); |
4302 | } else if (strcmp(cmp->modifier, "m") == 0) |
4303 | value = format_match(cmp, left, right); |
4304 | |
4305 | free(right); |
4306 | free(left); |
4307 | } else if (*copy == '?') { |
4308 | /* Conditional: check first and choose second or third. */ |
4309 | cp = format_skip(copy + 1, ","); |
4310 | if (cp == NULL((void *)0)) { |
4311 | format_log(es, "condition syntax error: %s", copy + 1)format_log1(es, __func__, "condition syntax error: %s", copy + 1); |
4312 | goto fail; |
4313 | } |
4314 | condition = xstrndup(copy + 1, cp - (copy + 1)); |
4315 | format_log(es, "condition is: %s", condition)format_log1(es, __func__, "condition is: %s", condition); |
4316 | |
4317 | found = format_find(ft, condition, modifiers, time_format); |
4318 | if (found == NULL((void *)0)) { |
4319 | /* |
4320 | * If the condition not found, try to expand it. If |
4321 | * the expansion doesn't have any effect, then assume |
4322 | * false. |
4323 | */ |
4324 | found = format_expand1(es, condition); |
4325 | if (strcmp(found, condition) == 0) { |
4326 | free(found); |
4327 | found = xstrdup(""); |
4328 | format_log(es,format_log1(es, __func__, "condition '%s' not found; assuming false" , condition) |
4329 | "condition '%s' not found; assuming false",format_log1(es, __func__, "condition '%s' not found; assuming false" , condition) |
4330 | condition)format_log1(es, __func__, "condition '%s' not found; assuming false" , condition); |
4331 | } |
4332 | } else { |
4333 | format_log(es, "condition '%s' found: %s", condition,format_log1(es, __func__, "condition '%s' found: %s", condition , found) |
4334 | found)format_log1(es, __func__, "condition '%s' found: %s", condition , found); |
4335 | } |
4336 | |
4337 | if (format_choose(es, cp + 1, &left, &right, 0) != 0) { |
4338 | format_log(es, "condition '%s' syntax error: %s",format_log1(es, __func__, "condition '%s' syntax error: %s", condition , cp + 1) |
4339 | condition, cp + 1)format_log1(es, __func__, "condition '%s' syntax error: %s", condition , cp + 1); |
4340 | free(found); |
4341 | goto fail; |
4342 | } |
4343 | if (format_true(found)) { |
4344 | format_log(es, "condition '%s' is true", condition)format_log1(es, __func__, "condition '%s' is true", condition ); |
4345 | value = format_expand1(es, left); |
4346 | } else { |
4347 | format_log(es, "condition '%s' is false", condition)format_log1(es, __func__, "condition '%s' is false", condition ); |
4348 | value = format_expand1(es, right); |
4349 | } |
4350 | free(right); |
4351 | free(left); |
4352 | |
4353 | free(condition); |
4354 | free(found); |
4355 | } else if (mexp != NULL((void *)0)) { |
4356 | value = format_replace_expression(mexp, es, copy); |
4357 | if (value == NULL((void *)0)) |
4358 | value = xstrdup(""); |
4359 | } else { |
4360 | if (strstr(copy, "#{") != 0) { |
4361 | format_log(es, "expanding inner format '%s'", copy)format_log1(es, __func__, "expanding inner format '%s'", copy ); |
4362 | value = format_expand1(es, copy); |
4363 | } else { |
4364 | value = format_find(ft, copy, modifiers, time_format); |
4365 | if (value == NULL((void *)0)) { |
4366 | format_log(es, "format '%s' not found", copy)format_log1(es, __func__, "format '%s' not found", copy); |
4367 | value = xstrdup(""); |
4368 | } else { |
4369 | format_log(es, "format '%s' found: %s", copy,format_log1(es, __func__, "format '%s' found: %s", copy, value ) |
4370 | value)format_log1(es, __func__, "format '%s' found: %s", copy, value ); |
4371 | } |
4372 | } |
4373 | } |
4374 | |
4375 | done: |
4376 | /* Expand again if required. */ |
4377 | if (modifiers & FORMAT_EXPAND0x20) { |
4378 | new = format_expand1(es, value); |
4379 | free(value); |
4380 | value = new; |
4381 | } else if (modifiers & FORMAT_EXPANDTIME0x40) { |
4382 | format_copy_state(&next, es, FORMAT_EXPAND_TIME0x1); |
4383 | new = format_expand1(&next, value); |
4384 | free(value); |
4385 | value = new; |
4386 | } |
4387 | |
4388 | /* Perform substitution if any. */ |
4389 | for (i = 0; i < nsub; i++) { |
4390 | left = format_expand1(es, sub[i]->argv[0]); |
4391 | right = format_expand1(es, sub[i]->argv[1]); |
4392 | new = format_sub(sub[i], value, left, right); |
4393 | format_log(es, "substitute '%s' to '%s': %s", left, right, new)format_log1(es, __func__, "substitute '%s' to '%s': %s", left , right, new); |
4394 | free(value); |
4395 | value = new; |
4396 | free(right); |
4397 | free(left); |
4398 | } |
4399 | |
4400 | /* Truncate the value if needed. */ |
4401 | if (limit > 0) { |
4402 | new = format_trim_left(value, limit); |
4403 | if (marker != NULL((void *)0) && strcmp(new, value) != 0) { |
4404 | free(value); |
4405 | xasprintf(&value, "%s%s", new, marker); |
4406 | } else { |
4407 | free(value); |
4408 | value = new; |
4409 | } |
4410 | format_log(es, "applied length limit %d: %s", limit, value)format_log1(es, __func__, "applied length limit %d: %s", limit , value); |
4411 | } else if (limit < 0) { |
4412 | new = format_trim_right(value, -limit); |
4413 | if (marker != NULL((void *)0) && strcmp(new, value) != 0) { |
4414 | free(value); |
4415 | xasprintf(&value, "%s%s", marker, new); |
4416 | } else { |
4417 | free(value); |
4418 | value = new; |
4419 | } |
4420 | format_log(es, "applied length limit %d: %s", limit, value)format_log1(es, __func__, "applied length limit %d: %s", limit , value); |
4421 | } |
4422 | |
4423 | /* Pad the value if needed. */ |
4424 | if (width > 0) { |
4425 | new = utf8_padcstr(value, width); |
4426 | free(value); |
4427 | value = new; |
4428 | format_log(es, "applied padding width %d: %s", width, value)format_log1(es, __func__, "applied padding width %d: %s", width , value); |
4429 | } else if (width < 0) { |
4430 | new = utf8_rpadcstr(value, -width); |
4431 | free(value); |
4432 | value = new; |
4433 | format_log(es, "applied padding width %d: %s", width, value)format_log1(es, __func__, "applied padding width %d: %s", width , value); |
4434 | } |
4435 | |
4436 | /* Replace with the length or width if needed. */ |
4437 | if (modifiers & FORMAT_LENGTH0x800) { |
4438 | xasprintf(&new, "%zu", strlen(value)); |
4439 | free(value); |
4440 | value = new; |
4441 | format_log(es, "replacing with length: %s", new)format_log1(es, __func__, "replacing with length: %s", new); |
4442 | } |
4443 | if (modifiers & FORMAT_WIDTH0x1000) { |
4444 | xasprintf(&new, "%u", format_width(value)); |
4445 | free(value); |
4446 | value = new; |
4447 | format_log(es, "replacing with width: %s", new)format_log1(es, __func__, "replacing with width: %s", new); |
4448 | } |
4449 | |
4450 | /* Expand the buffer and copy in the value. */ |
4451 | valuelen = strlen(value); |
4452 | while (*len - *off < valuelen + 1) { |
4453 | *buf = xreallocarray(*buf, 2, *len); |
4454 | *len *= 2; |
4455 | } |
4456 | memcpy(*buf + *off, value, valuelen); |
4457 | *off += valuelen; |
4458 | |
4459 | format_log(es, "replaced '%s' with '%s'", copy0, value)format_log1(es, __func__, "replaced '%s' with '%s'", copy0, value ); |
4460 | free(value); |
4461 | |
4462 | free(sub); |
4463 | format_free_modifiers(list, count); |
4464 | free(copy0); |
4465 | return (0); |
4466 | |
4467 | fail: |
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. */ |
4477 | static char * |
4478 | format_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. */ |
4642 | char * |
4643 | format_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. */ |
4654 | char * |
4655 | format_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. */ |
4666 | char * |
4667 | format_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. */ |
4680 | char * |
4681 | format_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. */ |
4688 | char * |
4689 | format_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. */ |
4697 | struct format_tree * |
4698 | format_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. */ |
4712 | struct format_tree * |
4713 | format_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. */ |
4720 | struct format_tree * |
4721 | format_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. */ |
4729 | void |
4730 | format_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. */ |
4786 | static void |
4787 | format_defaults_session(struct format_tree *ft, struct session *s) |
4788 | { |
4789 | ft->s = s; |
4790 | } |
4791 | |
4792 | /* Set default format keys for a client. */ |
4793 | static void |
4794 | format_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. */ |
4802 | void |
4803 | format_defaults_window(struct format_tree *ft, struct window *w) |
4804 | { |
4805 | ft->w = w; |
4806 | } |
4807 | |
4808 | /* Set default format keys for a winlink. */ |
4809 | static void |
4810 | format_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. */ |
4818 | void |
4819 | format_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. */ |
4833 | void |
4834 | format_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. */ |
4840 | char * |
4841 | format_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. */ |
4912 | char * |
4913 | format_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 | } |