4 * Copyright (c) 2011 Nicholas Marriott <nicm@users.sourceforge.net>
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.
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.
19 #include <sys/types.h>
30 * Build a list of key-value pairs and use them to expand #{key} entries in a
34 int format_replace(struct format_tree
*,
35 const char *, size_t, char **, size_t *, size_t *);
37 /* Format key-value replacement entry. */
38 RB_GENERATE(format_tree
, format_entry
, entry
, format_cmp
);
40 /* Format tree comparison function. */
42 format_cmp(struct format_entry
*fe1
, struct format_entry
*fe2
)
44 return (strcmp(fe1
->key
, fe2
->key
));
47 /* Single-character aliases. */
48 const char *format_aliases
[26] = {
54 "window_flags", /* F */
57 "window_index", /* I */
67 "session_name", /* S */
71 "window_name", /* W */
77 /* Create a new tree. */
81 struct format_tree
*ft
;
82 char host
[MAXHOSTNAMELEN
];
84 ft
= xmalloc(sizeof *ft
);
87 if (gethostname(host
, sizeof host
) == 0)
88 format_add(ft
, "host", "%s", host
);
95 format_free(struct format_tree
*ft
)
97 struct format_entry
*fe
, *fe_next
;
99 fe_next
= RB_MIN(format_tree
, ft
);
100 while (fe_next
!= NULL
) {
102 fe_next
= RB_NEXT(format_tree
, ft
, fe
);
104 RB_REMOVE(format_tree
, ft
, fe
);
113 /* Add a key-value pair. */
115 format_add(struct format_tree
*ft
, const char *key
, const char *fmt
, ...)
117 struct format_entry
*fe
;
120 fe
= xmalloc(sizeof *fe
);
121 fe
->key
= xstrdup(key
);
124 xvasprintf(&fe
->value
, fmt
, ap
);
127 RB_INSERT(format_tree
, ft
, fe
);
130 /* Find a format entry. */
132 format_find(struct format_tree
*ft
, const char *key
)
134 struct format_entry
*fe
, fe_find
;
136 fe_find
.key
= (char *) key
;
137 fe
= RB_FIND(format_tree
, ft
, &fe_find
);
144 * Replace a key/value pair in buffer. #{blah} is expanded directly,
145 * #{?blah,a,b} is replace with a if blah exists and is nonzero else b.
148 format_replace(struct format_tree
*ft
,
149 const char *key
, size_t keylen
, char **buf
, size_t *len
, size_t *off
)
155 /* Make a copy of the key. */
156 copy
= xmalloc(keylen
+ 1);
157 memcpy(copy
, key
, keylen
);
161 * Is this a conditional? If so, check it exists and extract either the
162 * first or second element. If not, look up the key directly.
165 ptr
= strchr(copy
, ',');
170 value
= format_find(ft
, copy
+ 1);
171 if (value
!= NULL
&& (value
[0] != '0' || value
[1] != '\0')) {
173 ptr
= strchr(value
, ',');
178 ptr
= strchr(ptr
+ 1, ',');
184 value
= format_find(ft
, copy
);
188 valuelen
= strlen(value
);
190 /* Expand the buffer and copy in the value. */
191 while (*len
- *off
< valuelen
+ 1) {
192 *buf
= xrealloc(*buf
, 2, *len
);
195 memcpy(*buf
+ *off
, value
, valuelen
);
206 /* Expand keys in a template. */
208 format_expand(struct format_tree
*ft
, const char *fmt
)
219 while (*fmt
!= '\0') {
221 while (len
- off
< 2) {
222 buf
= xrealloc(buf
, 2, len
);
230 ch
= (u_char
) *fmt
++;
233 ptr
= strchr(fmt
, '}');
238 if (format_replace(ft
, fmt
, n
, &buf
, &len
, &off
) != 0)
243 if (ch
>= 'A' && ch
<= 'Z') {
244 s
= format_aliases
[ch
- 'A'];
248 ft
, s
, n
, &buf
, &len
, &off
) != 0)
253 while (len
- off
< 2) {
254 buf
= xrealloc(buf
, 2, len
);
268 /* Set default format keys for a session. */
270 format_session(struct format_tree
*ft
, struct session
*s
)
272 struct session_group
*sg
;
276 format_add(ft
, "session_name", "%s", s
->name
);
277 format_add(ft
, "session_windows", "%u", winlink_count(&s
->windows
));
278 format_add(ft
, "session_width", "%u", s
->sx
);
279 format_add(ft
, "session_height", "%u", s
->sy
);
281 sg
= session_group_find(s
);
282 format_add(ft
, "session_grouped", "%d", sg
!= NULL
);
284 format_add(ft
, "session_group", "%u", session_group_index(sg
));
286 t
= s
->creation_time
.tv_sec
;
287 format_add(ft
, "session_created", "%ld", (long) t
);
289 *strchr(tim
, '\n') = '\0';
290 format_add(ft
, "session_created_string", "%s", tim
);
292 if (s
->flags
& SESSION_UNATTACHED
)
293 format_add(ft
, "session_attached", "%d", 0);
295 format_add(ft
, "session_attached", "%d", 1);
298 /* Set default format keys for a client. */
300 format_client(struct format_tree
*ft
, struct client
*c
)
305 format_add(ft
, "client_cwd", "%s", c
->cwd
);
306 format_add(ft
, "client_height", "%u", c
->tty
.sx
);
307 format_add(ft
, "client_width", "%u", c
->tty
.sy
);
308 format_add(ft
, "client_tty", "%s", c
->tty
.path
);
309 format_add(ft
, "client_termname", "%s", c
->tty
.termname
);
311 t
= c
->creation_time
.tv_sec
;
312 format_add(ft
, "client_created", "%ld", (long) t
);
314 *strchr(tim
, '\n') = '\0';
315 format_add(ft
, "client_created_string", "%s", tim
);
317 t
= c
->activity_time
.tv_sec
;
318 format_add(ft
, "client_activity", "%ld", (long) t
);
320 *strchr(tim
, '\n') = '\0';
321 format_add(ft
, "client_activity_string", "%s", tim
);
323 if (c
->tty
.flags
& TTY_UTF8
)
324 format_add(ft
, "client_utf8", "%d", 1);
326 format_add(ft
, "client_utf8", "%d", 0);
328 if (c
->flags
& CLIENT_READONLY
)
329 format_add(ft
, "client_readonly", "%d", 1);
331 format_add(ft
, "client_readonly", "%d", 0);
334 /* Set default format keys for a winlink. */
336 format_winlink(struct format_tree
*ft
, struct session
*s
, struct winlink
*wl
)
338 struct window
*w
= wl
->window
;
339 char *layout
, *flags
;
341 layout
= layout_dump(w
);
342 flags
= window_printable_flags(s
, wl
);
344 format_add(ft
, "window_index", "%d", wl
->idx
);
345 format_add(ft
, "window_name", "%s", w
->name
);
346 format_add(ft
, "window_width", "%u", w
->sx
);
347 format_add(ft
, "window_height", "%u", w
->sy
);
348 format_add(ft
, "window_flags", "%s", flags
);
349 format_add(ft
, "window_layout", "%s", layout
);
350 format_add(ft
, "window_active", "%d", wl
== s
->curw
);
356 /* Set default format keys for a window pane. */
358 format_window_pane(struct format_tree
*ft
, struct window_pane
*wp
)
360 struct grid
*gd
= wp
->base
.grid
;
361 struct grid_line
*gl
;
362 unsigned long long size
;
367 for (i
= 0; i
< gd
->hsize
; i
++) {
368 gl
= &gd
->linedata
[i
];
369 size
+= gl
->cellsize
* sizeof *gl
->celldata
;
370 size
+= gl
->utf8size
* sizeof *gl
->utf8data
;
372 size
+= gd
->hsize
* sizeof *gd
->linedata
;
374 if (window_pane_index(wp
, &idx
) != 0)
375 fatalx("index not found");
377 format_add(ft
, "pane_width", "%u", wp
->sx
);
378 format_add(ft
, "pane_height", "%u", wp
->sy
);
379 format_add(ft
, "pane_title", "%s", wp
->base
.title
);
380 format_add(ft
, "pane_index", "%u", idx
);
381 format_add(ft
, "history_size", "%u", gd
->hsize
);
382 format_add(ft
, "history_limit", "%u", gd
->hlimit
);
383 format_add(ft
, "history_bytes", "%llu", size
);
384 format_add(ft
, "pane_id", "%%%u", wp
->id
);
385 format_add(ft
, "pane_active", "%d", wp
== wp
->window
->active
);
386 format_add(ft
, "pane_dead", "%d", wp
->fd
== -1);
388 format_add(ft
, "pane_start_command", "%s", wp
->cmd
);
390 format_add(ft
, "pane_start_path", "%s", wp
->cwd
);
391 format_add(ft
, "pane_pid", "%ld", (long) wp
->pid
);
392 format_add(ft
, "pane_tty", "%s", wp
->tty
);