Coverage Report

Created: 2026-10-17 06:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tmux/format.c
Line
Count
Source
1
/* $OpenBSD: format.c,v 1.431 2026/10/16 12:21:12 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.h>
24
#include <fnmatch.h>
25
#include <libgen.h>
26
#include <math.h>
27
#include <pwd.h>
28
#include <regex.h>
29
#include <stdarg.h>
30
#include <stdlib.h>
31
#include <string.h>
32
#include <time.h>
33
#include <unistd.h>
34
35
#include "tmux.h"
36
37
/*
38
 * Build a list of key-value pairs and use them to expand #{key} entries in a
39
 * string.
40
 */
41
42
struct format_expand_state;
43
44
static char *format_job_get(struct format_expand_state *, const char *);
45
static char *format_quote_shell_single(const char *);
46
static char *format_expand1(struct format_expand_state *, const char *);
47
static int   format_replace(struct format_expand_state *, const char *,
48
         size_t, char **, size_t *, size_t *);
49
static void  format_defaults_session(struct format_tree *,
50
         struct session *);
51
static void  format_defaults_client(struct format_tree *, struct client *);
52
static void  format_defaults_winlink(struct format_tree *,
53
         struct winlink *);
54
55
/* Entry in format job tree. */
56
struct format_job {
57
  struct client   *client;
58
  u_int      tag;
59
  const char    *cmd;
60
  const char    *expanded;
61
62
  time_t       last;
63
  char      *out;
64
  int      updated;
65
66
  struct job    *job;
67
  int      status;
68
69
  RB_ENTRY(format_job)   entry;
70
};
71
72
/* Format job tree. */
73
static int format_job_cmp(struct format_job *, struct format_job *);
74
static RB_HEAD(format_job_tree, format_job) format_jobs = RB_INITIALIZER();
75
0
RB_GENERATE_STATIC(format_job_tree, format_job, entry, format_job_cmp);
Unexecuted instantiation: format.c:format_job_tree_RB_MINMAX
Unexecuted instantiation: format.c:format_job_tree_RB_REMOVE
Unexecuted instantiation: format.c:format_job_tree_RB_REMOVE_COLOR
Unexecuted instantiation: format.c:format_job_tree_RB_FIND
Unexecuted instantiation: format.c:format_job_tree_RB_INSERT
76
0
77
0
/* Format job tree comparison function. */
78
0
static int
79
0
format_job_cmp(struct format_job *fj1, struct format_job *fj2)
80
0
{
81
0
  if (fj1->tag < fj2->tag)
82
0
    return (-1);
83
0
  if (fj1->tag > fj2->tag)
84
0
    return (1);
85
0
  return (strcmp(fj1->cmd, fj2->cmd));
86
0
}
87
88
/* Maximum pad and trim width. */
89
232k
#define FORMAT_MAX_WIDTH 10000
90
91
/* Maximum repeat count. */
92
220k
#define FORMAT_MAX_REPEAT 10000
93
94
/* Maximum repeat result size in bytes. */
95
201k
#define FORMAT_MAX_REPEAT_SIZE 65536
96
97
/* Maximum precision. */
98
860
#define FORMAT_MAX_PRECISION 100
99
100
/* Format modifiers. */
101
1.99M
#define FORMAT_TIMESTRING 0x1
102
167k
#define FORMAT_BASENAME 0x2
103
167k
#define FORMAT_DIRNAME 0x4
104
167k
#define FORMAT_QUOTE_SHELL 0x8
105
3.02M
#define FORMAT_LITERAL 0x10
106
3.04M
#define FORMAT_EXPAND 0x20
107
2.98M
#define FORMAT_EXPANDTIME 0x40
108
2.99M
#define FORMAT_SESSIONS 0x80
109
2.96M
#define FORMAT_WINDOWS 0x100
110
2.96M
#define FORMAT_PANES 0x200
111
5.44k
#define FORMAT_PRETTY 0x400
112
3.01M
#define FORMAT_LENGTH 0x800
113
3.01M
#define FORMAT_WIDTH 0x1000
114
168k
#define FORMAT_QUOTE_STYLE 0x2000
115
2.89M
#define FORMAT_WINDOW_NAME 0x4000
116
2.89M
#define FORMAT_SESSION_NAME 0x8000
117
3.02M
#define FORMAT_CHARACTER 0x10000
118
3.06M
#define FORMAT_COLOUR 0x20000
119
2.96M
#define FORMAT_CLIENTS 0x40000
120
2.65M
#define FORMAT_NOT 0x80000
121
2.64M
#define FORMAT_NOT_NOT 0x100000
122
3.13M
#define FORMAT_REPEAT 0x200000
123
186k
#define FORMAT_QUOTE_ARGUMENTS 0x400000
124
3.39k
#define FORMAT_RELATIVE 0x800000
125
3.04M
#define FORMAT_CLIENT_TERMCAP 0x1000000
126
3.04M
#define FORMAT_CLIENT_TERMFEAT 0x2000000
127
3.04M
#define FORMAT_CLIENT_ENVIRON 0x4000000
128
43.1k
#define FORMAT_COLOUR_ESC_FG 0x8000000
129
46.5k
#define FORMAT_COLOUR_ESC_BG 0x10000000
130
168k
#define FORMAT_QUOTE_SHELL_SQ 0x20000000
131
3.01M
#define FORMAT_OPTIONS 0x40000000
132
2.90M
#define FORMAT_ENVIRON 0x80000000ULL
133
3.23k
#define FORMAT_DIFFERENCE 0x100000000ULL
134
3.06M
#define FORMAT_CYCLE 0x200000000ULL
135
136
/* Limit on recursion. */
137
3.44M
#define FORMAT_LOOP_LIMIT 100
138
139
/* Limit on time taken (milliseconds). */
140
9.55M
#define FORMAT_TIME_LIMIT 100
141
142
/* How often to check the time in long loops. */
143
475M
#define FORMAT_TIME_LOOP_CHECK 10000
144
145
/* Fixed animation period (ms): redraw interval and shortest frame step. */
146
0
#define FORMAT_CYCLE_PERIOD 100
147
148
/* Format expand flags. */
149
3.40M
#define FORMAT_EXPAND_TIME 0x1
150
0
#define FORMAT_EXPAND_NOJOBS 0x2
151
0
#define FORMAT_EXPAND_NOCYCLE 0x4
152
153
/* Entry in format tree. */
154
struct format_entry {
155
  char      *key;
156
  char      *value;
157
  time_t       time;
158
  format_cb    cb;
159
  RB_ENTRY(format_entry)   entry;
160
};
161
162
/* Format type. */
163
enum format_type {
164
  FORMAT_TYPE_UNKNOWN,
165
  FORMAT_TYPE_SESSION,
166
  FORMAT_TYPE_WINDOW,
167
  FORMAT_TYPE_PANE
168
};
169
170
static struct sort_criteria sort_crit;
171
172
struct format_tree {
173
  enum format_type   type;
174
175
  struct client   *c;
176
  struct session    *s;
177
  struct winlink    *wl;
178
  struct window   *w;
179
  struct window_pane  *wp;
180
  struct paste_buffer *pb;
181
182
  struct cmdq_item  *item;
183
  struct client   *client;
184
  int      flags;
185
  u_int      tag;
186
187
  struct mouse_event   m;
188
189
  RB_HEAD(format_entry_tree, format_entry) tree;
190
};
191
static int format_entry_cmp(struct format_entry *, struct format_entry *);
192
219M
RB_GENERATE_STATIC(format_entry_tree, format_entry, entry, format_entry_cmp);
format.c:format_entry_tree_RB_MINMAX
Line
Count
Source
192
RB_GENERATE_STATIC(format_entry_tree, format_entry, entry, format_entry_cmp);
format.c:format_entry_tree_RB_REMOVE
Line
Count
Source
192
RB_GENERATE_STATIC(format_entry_tree, format_entry, entry, format_entry_cmp);
format.c:format_entry_tree_RB_REMOVE_COLOR
Line
Count
Source
192
RB_GENERATE_STATIC(format_entry_tree, format_entry, entry, format_entry_cmp);
format.c:format_entry_tree_RB_INSERT
Line
Count
Source
192
RB_GENERATE_STATIC(format_entry_tree, format_entry, entry, format_entry_cmp);
format.c:format_entry_tree_RB_FIND
Line
Count
Source
192
RB_GENERATE_STATIC(format_entry_tree, format_entry, entry, format_entry_cmp);
193
219M
194
219M
/* Format expand state. */
195
219M
struct format_expand_state {
196
219M
  struct format_tree  *ft;
197
219M
  u_int      loop;
198
219M
  uint64_t     start_time;
199
219M
  int      flags;
200
219M
201
219M
  time_t       time;
202
219M
  struct tm    tm;
203
219M
};
204
219M
205
219M
/* Format modifier. */
206
219M
struct format_modifier {
207
219M
  char    modifier[3];
208
219M
  u_int   size;
209
219M
210
219M
  char  **argv;
211
219M
  int   argc;
212
219M
};
213
219M
214
219M
/* Format entry tree comparison function. */
215
219M
static int
216
219M
format_entry_cmp(struct format_entry *fe1, struct format_entry *fe2)
217
219M
{
218
63.5M
  return (strcmp(fe1->key, fe2->key));
219
63.5M
}
220
221
/* Single-character uppercase aliases. */
222
static const char *format_upper[] = {
223
  NULL,   /* A */
224
  NULL,   /* B */
225
  NULL,   /* C */
226
  "pane_id",  /* D */
227
  NULL,   /* E */
228
  "window_flags", /* F */
229
  NULL,   /* G */
230
  "host",   /* H */
231
  "window_index", /* I */
232
  NULL,   /* J */
233
  NULL,   /* K */
234
  NULL,   /* L */
235
  NULL,   /* M */
236
  NULL,   /* N */
237
  NULL,   /* O */
238
  "pane_index", /* P */
239
  NULL,   /* Q */
240
  NULL,   /* R */
241
  "session_name", /* S */
242
  "pane_title", /* T */
243
  NULL,   /* U */
244
  NULL,   /* V */
245
  "window_name",  /* W */
246
  NULL,   /* X */
247
  NULL,   /* Y */
248
  NULL    /* Z */
249
};
250
251
/* Single-character lowercase aliases. */
252
static const char *format_lower[] = {
253
  NULL,   /* a */
254
  NULL,   /* b */
255
  NULL,   /* c */
256
  NULL,   /* d */
257
  NULL,   /* e */
258
  NULL,   /* f */
259
  NULL,   /* g */
260
  "host_short", /* h */
261
  NULL,   /* i */
262
  NULL,   /* j */
263
  NULL,   /* k */
264
  NULL,   /* l */
265
  NULL,   /* m */
266
  NULL,   /* n */
267
  NULL,   /* o */
268
  NULL,   /* p */
269
  NULL,   /* q */
270
  NULL,   /* r */
271
  NULL,   /* s */
272
  NULL,   /* t */
273
  NULL,   /* u */
274
  NULL,   /* v */
275
  NULL,   /* w */
276
  NULL,   /* x */
277
  NULL,   /* y */
278
  NULL    /* z */
279
};
280
281
/* Is logging enabled? */
282
static inline int
283
format_logging(struct format_tree *ft)
284
22.2M
{
285
22.2M
  return (log_get_level() != 0 || (ft->flags & FORMAT_VERBOSE));
286
22.2M
}
287
288
/* Log a message if verbose. */
289
static void printflike(3, 4)
290
format_log1(struct format_expand_state *es, const char *from, const char *fmt,
291
    ...)
292
21.3M
{
293
21.3M
  struct format_tree  *ft = es->ft;
294
21.3M
  va_list      ap;
295
21.3M
  char      *s;
296
21.3M
  static const char  spaces[] = "          ";
297
298
21.3M
  if (!format_logging(ft))
299
21.3M
    return;
300
301
21.3M
  va_start(ap, fmt);
302
0
  xvasprintf(&s, fmt, ap);
303
0
  va_end(ap);
304
305
0
  log_debug("%s: %s", from, s);
306
0
  if (ft->item != NULL && (ft->flags & FORMAT_VERBOSE))
307
0
    cmdq_print(ft->item, "#%.*s%s", es->loop, spaces, s);
308
309
0
  free(s);
310
0
}
311
21.3M
#define format_log(es, fmt, ...) format_log1(es, __func__, fmt, ##__VA_ARGS__)
312
313
/* Copy expand state. */
314
static void
315
format_copy_state(struct format_expand_state *to,
316
    struct format_expand_state *from, int flags)
317
1.84M
{
318
1.84M
  to->ft = from->ft;
319
1.84M
  to->loop = from->loop;
320
1.84M
  to->time = from->time;
321
1.84M
  memcpy(&to->tm, &from->tm, sizeof to->tm);
322
1.84M
  to->flags = from->flags|flags;
323
1.84M
  to->start_time = from->start_time;
324
1.84M
}
325
326
/* Format job update callback. */
327
static void
328
format_job_update(struct job *job)
329
0
{
330
0
  struct format_job *fj = job_get_data(job);
331
0
  struct evbuffer   *evb = job_get_event(job)->input;
332
0
  char      *line = NULL, *next;
333
0
  time_t       t;
334
335
0
  while ((next = evbuffer_readline(evb)) != NULL) {
336
0
    free(line);
337
0
    line = next;
338
0
  }
339
0
  if (line == NULL)
340
0
    return;
341
0
  fj->updated = 1;
342
343
0
  free(fj->out);
344
0
  fj->out = line;
345
346
0
  log_debug("%s: %p %s: %s", __func__, fj, fj->cmd, fj->out);
347
348
0
  t = time(NULL);
349
0
  if (fj->status && fj->last != t) {
350
0
    if (fj->client != NULL)
351
0
      server_status_client(fj->client);
352
0
    fj->last = t;
353
0
  }
354
0
}
355
356
/* Format job complete callback. */
357
static void
358
format_job_complete(struct job *job)
359
0
{
360
0
  struct format_job *fj = job_get_data(job);
361
0
  struct evbuffer   *evb = job_get_event(job)->input;
362
0
  char      *line, *buf;
363
0
  size_t       len;
364
365
0
  fj->job = NULL;
366
367
0
  buf = NULL;
368
0
  if ((line = evbuffer_readline(evb)) == NULL) {
369
0
    len = EVBUFFER_LENGTH(evb);
370
0
    buf = xmalloc(len + 1);
371
0
    if (len != 0)
372
0
      memcpy(buf, EVBUFFER_DATA(evb), len);
373
0
    buf[len] = '\0';
374
0
  } else
375
0
    buf = line;
376
377
0
  log_debug("%s: %p %s: %s", __func__, fj, fj->cmd, buf);
378
379
0
  if (*buf != '\0' || !fj->updated) {
380
0
    free(fj->out);
381
0
    fj->out = buf;
382
0
  } else
383
0
    free(buf);
384
385
0
  if (fj->status) {
386
0
    if (fj->client != NULL)
387
0
      server_status_client(fj->client);
388
0
    fj->status = 0;
389
0
  }
390
0
}
391
392
/* Find a job. */
393
static char *
394
format_job_get(struct format_expand_state *es, const char *cmd)
395
0
{
396
0
  struct format_tree    *ft = es->ft;
397
0
  struct format_job_tree    *jobs;
398
0
  struct format_job    fj0, *fj;
399
0
  time_t         t;
400
0
  char        *expanded;
401
0
  int        force;
402
0
  struct format_expand_state   next;
403
404
0
  if (ft->client == NULL)
405
0
    jobs = &format_jobs;
406
0
  else if (ft->client->jobs != NULL)
407
0
    jobs = ft->client->jobs;
408
0
  else {
409
0
    jobs = ft->client->jobs = xmalloc(sizeof *ft->client->jobs);
410
0
    RB_INIT(jobs);
411
0
  }
412
413
0
  fj0.tag = ft->tag;
414
0
  fj0.cmd = cmd;
415
0
  if ((fj = RB_FIND(format_job_tree, jobs, &fj0)) == NULL) {
416
0
    fj = xcalloc(1, sizeof *fj);
417
0
    fj->client = ft->client;
418
0
    fj->tag = ft->tag;
419
0
    fj->cmd = xstrdup(cmd);
420
421
0
    RB_INSERT(format_job_tree, jobs, fj);
422
0
  }
423
424
0
  format_copy_state(&next, es, FORMAT_EXPAND_NOJOBS|
425
0
      FORMAT_EXPAND_NOCYCLE);
426
0
  next.flags &= ~FORMAT_EXPAND_TIME;
427
428
0
  expanded = format_expand1(&next, cmd);
429
0
  if (fj->expanded == NULL || strcmp(expanded, fj->expanded) != 0) {
430
0
    free((void *)fj->expanded);
431
0
    fj->expanded = xstrdup(expanded);
432
0
    force = 1;
433
0
  } else
434
0
    force = (ft->flags & FORMAT_FORCE);
435
436
0
  t = time(NULL);
437
0
  if (force && fj->job != NULL)
438
0
         job_free(fj->job);
439
0
  if (force || (fj->job == NULL && fj->last != t)) {
440
0
    fj->job = job_run(expanded, 0, NULL, NULL, NULL,
441
0
        server_client_get_cwd(ft->client, NULL), format_job_update,
442
0
        format_job_complete, NULL, fj, JOB_NOWAIT, -1, -1);
443
0
    if (fj->job == NULL) {
444
0
      free(fj->out);
445
0
      xasprintf(&fj->out, "<'%s' didn't start>", fj->cmd);
446
0
    }
447
0
    fj->last = t;
448
0
    fj->updated = 0;
449
0
  } else if (fj->job != NULL && (t - fj->last) > 1 && fj->out == NULL)
450
0
    xasprintf(&fj->out, "<'%s' not ready>", fj->cmd);
451
0
  free(expanded);
452
453
0
  if (ft->flags & FORMAT_STATUS)
454
0
    fj->status = 1;
455
0
  if (fj->out == NULL)
456
0
    return (xstrdup(""));
457
0
  return (format_expand1(&next, fj->out));
458
0
}
459
460
/* Remove old jobs. */
461
static void
462
format_job_tidy(struct format_job_tree *jobs, int force)
463
0
{
464
0
  struct format_job *fj, *fj1;
465
0
  time_t       now;
466
467
0
  now = time(NULL);
468
0
  RB_FOREACH_SAFE(fj, format_job_tree, jobs, fj1) {
469
0
    if (!force && (fj->last > now || now - fj->last < 3600))
470
0
      continue;
471
0
    RB_REMOVE(format_job_tree, jobs, fj);
472
473
0
    log_debug("%s: %s", __func__, fj->cmd);
474
475
0
    if (fj->job != NULL)
476
0
      job_free(fj->job);
477
478
0
    free((void *)fj->expanded);
479
0
    free((void *)fj->cmd);
480
0
    free(fj->out);
481
482
0
    free(fj);
483
0
  }
484
0
}
485
486
/* Work around needless -Wformat-nonliteral gcc warning. */
487
#ifdef __GNUC__
488
#pragma GCC diagnostic push
489
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
490
#endif
491
static size_t
492
format_strftime(char *s, size_t max, const char *fmt, const struct tm *tm)
493
1.74k
{
494
1.74k
  return (strftime(s, max, fmt, tm));
495
1.74k
}
496
#ifdef __GNUC__
497
#pragma GCC diagnostic pop
498
#endif
499
500
/* Tidy old jobs for all clients. */
501
void
502
format_tidy_jobs(void)
503
0
{
504
0
  struct client *c;
505
506
0
  format_job_tidy(&format_jobs, 0);
507
0
  TAILQ_FOREACH(c, &clients, entry) {
508
0
    if (c->jobs != NULL)
509
0
      format_job_tidy(c->jobs, 0);
510
0
  }
511
0
}
512
513
/* Remove old jobs for client. */
514
void
515
format_lost_client(struct client *c)
516
0
{
517
0
  if (c->jobs != NULL)
518
0
    format_job_tidy(c->jobs, 1);
519
0
  free(c->jobs);
520
0
}
521
522
/* Wrapper for asprintf. */
523
static char * printflike(1, 2)
524
format_printf(const char *fmt, ...)
525
1.83k
{
526
1.83k
  va_list  ap;
527
1.83k
  char  *s;
528
529
1.83k
  va_start(ap, fmt);
530
1.83k
  xvasprintf(&s, fmt, ap);
531
1.83k
  va_end(ap);
532
1.83k
  return (s);
533
1.83k
}
534
535
/* Callback for host. */
536
static void *
537
format_cb_host(__unused struct format_tree *ft)
538
22.2k
{
539
22.2k
  char host[HOST_NAME_MAX + 1];
540
541
22.2k
  if (gethostname(host, sizeof host) != 0)
542
0
    return (xstrdup(""));
543
22.2k
  return (xstrdup(host));
544
22.2k
}
545
546
/* Callback for host_short. */
547
static void *
548
format_cb_host_short(__unused struct format_tree *ft)
549
15.7k
{
550
15.7k
  char host[HOST_NAME_MAX + 1], *cp;
551
552
15.7k
  if (gethostname(host, sizeof host) != 0)
553
0
    return (xstrdup(""));
554
15.7k
  if ((cp = strchr(host, '.')) != NULL)
555
0
    *cp = '\0';
556
15.7k
  return (xstrdup(host));
557
15.7k
}
558
559
/* Callback for pid. */
560
static void *
561
format_cb_pid(__unused struct format_tree *ft)
562
3.05k
{
563
3.05k
  char  *value;
564
565
3.05k
  xasprintf(&value, "%ld", (long)getpid());
566
3.05k
  return (value);
567
3.05k
}
568
569
/* Callback for session_attached_list. */
570
static void *
571
format_cb_session_attached_list(struct format_tree *ft)
572
194
{
573
194
  struct session  *s = ft->s;
574
194
  struct client *loop;
575
194
  struct evbuffer *buffer;
576
194
  int    size;
577
194
  char    *value = NULL;
578
579
194
  if (s == NULL)
580
194
    return (NULL);
581
582
0
  buffer = evbuffer_new();
583
0
  if (buffer == NULL)
584
0
    fatalx("out of memory");
585
586
0
  TAILQ_FOREACH(loop, &clients, entry) {
587
0
    if (loop->session == s) {
588
0
      if (EVBUFFER_LENGTH(buffer) > 0)
589
0
        evbuffer_add(buffer, ",", 1);
590
0
      evbuffer_add_printf(buffer, "%s", loop->name);
591
0
    }
592
0
  }
593
594
0
  if ((size = EVBUFFER_LENGTH(buffer)) != 0)
595
0
    value = xmemdup(EVBUFFER_DATA(buffer), size);
596
0
  evbuffer_free(buffer);
597
0
  return (value);
598
0
}
599
600
/* Callback for session_alert. */
601
static void *
602
format_cb_session_alert(struct format_tree *ft)
603
194
{
604
194
  struct session  *s = ft->s;
605
194
  struct winlink  *wl;
606
194
  char     alerts[1024];
607
194
  int    alerted = 0;
608
609
194
  if (s == NULL)
610
194
    return (NULL);
611
612
0
  *alerts = '\0';
613
0
  RB_FOREACH(wl, winlinks, &s->windows) {
614
0
    if ((wl->flags & WINLINK_ALERTFLAGS) == 0)
615
0
      continue;
616
0
    if (~alerted & wl->flags & WINLINK_ACTIVITY) {
617
0
      strlcat(alerts, "#", sizeof alerts);
618
0
      alerted |= WINLINK_ACTIVITY;
619
0
    }
620
0
    if (~alerted & wl->flags & WINLINK_BELL) {
621
0
      strlcat(alerts, "!", sizeof alerts);
622
0
      alerted |= WINLINK_BELL;
623
0
    }
624
0
    if (~alerted & wl->flags & WINLINK_SILENCE) {
625
0
      strlcat(alerts, "~", sizeof alerts);
626
0
      alerted |= WINLINK_SILENCE;
627
0
    }
628
0
  }
629
0
  return (xstrdup(alerts));
630
194
}
631
632
/* Callback for session_alerts. */
633
static void *
634
format_cb_session_alerts(struct format_tree *ft)
635
194
{
636
194
  struct session  *s = ft->s;
637
194
  struct winlink  *wl;
638
194
  char     alerts[1024], tmp[16];
639
640
194
  if (s == NULL)
641
194
    return (NULL);
642
643
0
  *alerts = '\0';
644
0
  RB_FOREACH(wl, winlinks, &s->windows) {
645
0
    if ((wl->flags & WINLINK_ALERTFLAGS) == 0)
646
0
      continue;
647
0
    xsnprintf(tmp, sizeof tmp, "%u", wl->idx);
648
649
0
    if (*alerts != '\0')
650
0
      strlcat(alerts, ",", sizeof alerts);
651
0
    strlcat(alerts, tmp, sizeof alerts);
652
0
    if (wl->flags & WINLINK_ACTIVITY)
653
0
      strlcat(alerts, "#", sizeof alerts);
654
0
    if (wl->flags & WINLINK_BELL)
655
0
      strlcat(alerts, "!", sizeof alerts);
656
0
    if (wl->flags & WINLINK_SILENCE)
657
0
      strlcat(alerts, "~", sizeof alerts);
658
0
  }
659
0
  return (xstrdup(alerts));
660
194
}
661
662
/* Callback for session_stack. */
663
static void *
664
format_cb_session_stack(struct format_tree *ft)
665
286
{
666
286
  struct session  *s = ft->s;
667
286
  struct winlink  *wl;
668
286
  char     result[1024], tmp[16];
669
670
286
  if (s == NULL)
671
286
    return (NULL);
672
673
0
  xsnprintf(result, sizeof result, "%u", s->curw->idx);
674
0
  TAILQ_FOREACH(wl, &s->lastw, sentry) {
675
0
    xsnprintf(tmp, sizeof tmp, "%u", wl->idx);
676
677
0
    if (*result != '\0')
678
0
      strlcat(result, ",", sizeof result);
679
0
    strlcat(result, tmp, sizeof result);
680
0
  }
681
0
  return (xstrdup(result));
682
286
}
683
684
/* Callback for window_stack_index. */
685
static void *
686
format_cb_window_stack_index(struct format_tree *ft)
687
194
{
688
194
  struct session  *s;
689
194
  struct winlink  *wl;
690
194
  u_int    idx;
691
194
  char    *value = NULL;
692
693
194
  if (ft->wl == NULL)
694
194
    return (NULL);
695
0
  s = ft->wl->session;
696
697
0
  idx = 0;
698
0
  TAILQ_FOREACH(wl, &s->lastw, sentry) {
699
0
    idx++;
700
0
    if (wl == ft->wl)
701
0
      break;
702
0
  }
703
0
  if (wl == NULL)
704
0
    return (xstrdup("0"));
705
0
  xasprintf(&value, "%u", idx);
706
0
  return (value);
707
0
}
708
709
/* Callback for window_linked_sessions_list. */
710
static void *
711
format_cb_window_linked_sessions_list(struct format_tree *ft)
712
194
{
713
194
  struct window *w;
714
194
  struct winlink  *wl;
715
194
  struct evbuffer *buffer;
716
194
  int    size;
717
194
  char    *value = NULL;
718
719
194
  if (ft->wl == NULL)
720
194
    return (NULL);
721
0
  w = ft->wl->window;
722
723
0
  buffer = evbuffer_new();
724
0
  if (buffer == NULL)
725
0
    fatalx("out of memory");
726
727
0
  TAILQ_FOREACH(wl, &w->winlinks, wentry) {
728
0
    if (EVBUFFER_LENGTH(buffer) > 0)
729
0
      evbuffer_add(buffer, ",", 1);
730
0
    evbuffer_add_printf(buffer, "%s", wl->session->name);
731
0
  }
732
733
0
  if ((size = EVBUFFER_LENGTH(buffer)) != 0)
734
0
    value = xmemdup(EVBUFFER_DATA(buffer), size);
735
0
  evbuffer_free(buffer);
736
0
  return (value);
737
0
}
738
739
/* Callback for window_active_sessions. */
740
static void *
741
format_cb_window_active_sessions(struct format_tree *ft)
742
194
{
743
194
  struct window *w;
744
194
  struct winlink  *wl;
745
194
  u_int    n = 0;
746
194
  char    *value;
747
748
194
  if (ft->wl == NULL)
749
194
    return (NULL);
750
0
  w = ft->wl->window;
751
752
0
  TAILQ_FOREACH(wl, &w->winlinks, wentry) {
753
0
    if (wl->session->curw == wl)
754
0
      n++;
755
0
  }
756
757
0
  xasprintf(&value, "%u", n);
758
0
  return (value);
759
194
}
760
761
/* Callback for window_active_sessions_list. */
762
static void *
763
format_cb_window_active_sessions_list(struct format_tree *ft)
764
194
{
765
194
  struct window *w;
766
194
  struct winlink  *wl;
767
194
  struct evbuffer *buffer;
768
194
  int    size;
769
194
  char    *value = NULL;
770
771
194
  if (ft->wl == NULL)
772
194
    return (NULL);
773
0
  w = ft->wl->window;
774
775
0
  buffer = evbuffer_new();
776
0
  if (buffer == NULL)
777
0
    fatalx("out of memory");
778
779
0
  TAILQ_FOREACH(wl, &w->winlinks, wentry) {
780
0
    if (wl->session->curw == wl) {
781
0
      if (EVBUFFER_LENGTH(buffer) > 0)
782
0
        evbuffer_add(buffer, ",", 1);
783
0
      evbuffer_add_printf(buffer, "%s", wl->session->name);
784
0
    }
785
0
  }
786
787
0
  if ((size = EVBUFFER_LENGTH(buffer)) != 0)
788
0
    value = xmemdup(EVBUFFER_DATA(buffer), size);
789
0
  evbuffer_free(buffer);
790
0
  return (value);
791
0
}
792
793
/* Callback for window_active_clients. */
794
static void *
795
format_cb_window_active_clients(struct format_tree *ft)
796
194
{
797
194
  struct window *w;
798
194
  struct client *loop;
799
194
  struct session  *client_session;
800
194
  u_int    n = 0;
801
194
  char    *value;
802
803
194
  if (ft->wl == NULL)
804
194
    return (NULL);
805
0
  w = ft->wl->window;
806
807
0
  TAILQ_FOREACH(loop, &clients, entry) {
808
0
    client_session = loop->session;
809
0
    if (client_session == NULL)
810
0
      continue;
811
812
0
    if (w == client_session->curw->window)
813
0
      n++;
814
0
  }
815
816
0
  xasprintf(&value, "%u", n);
817
0
  return (value);
818
194
}
819
820
/* Callback for window_active_clients_list. */
821
static void *
822
format_cb_window_active_clients_list(struct format_tree *ft)
823
198
{
824
198
  struct window *w;
825
198
  struct client *loop;
826
198
  struct session  *client_session;
827
198
  struct evbuffer *buffer;
828
198
  int    size;
829
198
  char    *value = NULL;
830
831
198
  if (ft->wl == NULL)
832
198
    return (NULL);
833
0
  w = ft->wl->window;
834
835
0
  buffer = evbuffer_new();
836
0
  if (buffer == NULL)
837
0
    fatalx("out of memory");
838
839
0
  TAILQ_FOREACH(loop, &clients, entry) {
840
0
    client_session = loop->session;
841
0
    if (client_session == NULL)
842
0
      continue;
843
844
0
    if (w == client_session->curw->window) {
845
0
      if (EVBUFFER_LENGTH(buffer) > 0)
846
0
        evbuffer_add(buffer, ",", 1);
847
0
      evbuffer_add_printf(buffer, "%s", loop->name);
848
0
    }
849
0
  }
850
851
0
  if ((size = EVBUFFER_LENGTH(buffer)) != 0)
852
0
    value = xmemdup(EVBUFFER_DATA(buffer), size);
853
0
  evbuffer_free(buffer);
854
0
  return (value);
855
0
}
856
857
/* Callback for window_layout. */
858
static void *
859
format_cb_window_layout(struct format_tree *ft)
860
194
{
861
194
  struct client   *c = ft->client;
862
194
  struct window   *w = ft->w;
863
194
  struct layout_cell  *lcroot;
864
194
  int      flags = 0;
865
866
194
  if (w == NULL)
867
194
    return (NULL);
868
869
0
  if (w->saved_layout_root != NULL)
870
0
    lcroot = w->saved_layout_root;
871
0
  else
872
0
    lcroot = w->layout_root;
873
874
0
  if (c != NULL &&
875
0
      (c->flags & CLIENT_CONTROL) &&
876
0
      (~c->flags & CLIENT_CONTROL_NEWLAYOUTS))
877
0
    flags |= LAYOUT_CUSTOM_OLD_FORMAT;
878
0
  return (layout_dump(w, lcroot, flags));
879
194
}
880
881
/* Callback for window_visible_layout. */
882
static void *
883
format_cb_window_visible_layout(struct format_tree *ft)
884
198
{
885
198
  struct client *c = ft->client;
886
198
  struct window *w = ft->w;
887
198
  int    flags = 0;
888
889
198
  if (w == NULL)
890
198
    return (NULL);
891
892
0
  if (c != NULL &&
893
0
      (c->flags & CLIENT_CONTROL) &&
894
0
      (~c->flags & CLIENT_CONTROL_NEWLAYOUTS))
895
0
    flags |= LAYOUT_CUSTOM_OLD_FORMAT;
896
0
  return (layout_dump(w, w->layout_root, flags));
897
198
}
898
899
/* Callback for pane_start_command. */
900
static void *
901
format_cb_start_command(struct format_tree *ft)
902
198
{
903
198
  struct window_pane  *wp = ft->wp;
904
905
198
  if (wp == NULL)
906
198
    return (NULL);
907
908
0
  return (cmd_stringify_argv(wp->argc, wp->argv));
909
198
}
910
911
/* Callback for pane_start_command_list. */
912
static void *
913
format_cb_start_command_list(struct format_tree *ft)
914
198
{
915
198
  struct window_pane  *wp = ft->wp;
916
198
  char      *buf = NULL, *s;
917
198
  size_t       len = 0;
918
198
  int      i;
919
920
198
  if (wp == NULL)
921
198
    return (NULL);
922
0
  if (wp->argc == 0)
923
0
    return (xstrdup(""));
924
925
0
  for (i = 0; i < wp->argc; i++) {
926
0
    s = format_quote_shell_single(wp->argv[i]);
927
928
0
    len += strlen(s) + 1;
929
0
    buf = xrealloc(buf, len);
930
931
0
    if (i == 0)
932
0
      *buf = '\0';
933
0
    else
934
0
      strlcat(buf, " ", len);
935
0
    strlcat(buf, s, len);
936
937
0
    free(s);
938
0
  }
939
0
  return (buf);
940
0
}
941
942
/* Callback for pane_start_path. */
943
static void *
944
format_cb_start_path(struct format_tree *ft)
945
194
{
946
194
  struct window_pane  *wp = ft->wp;
947
948
194
  if (wp == NULL)
949
194
    return (NULL);
950
951
0
  if (wp->cwd == NULL)
952
0
    return (xstrdup(""));
953
0
  return (xstrdup(wp->cwd));
954
0
}
955
956
/* Callback for pane_current_command. */
957
static void *
958
format_cb_current_command(struct format_tree *ft)
959
381
{
960
381
  struct window_pane  *wp = ft->wp;
961
381
  char      *cmd, *value;
962
963
381
  if (wp == NULL || wp->shell == NULL)
964
381
    return (NULL);
965
966
0
  cmd = osdep_get_name(wp->fd, wp->tty);
967
0
  if (cmd == NULL || *cmd == '\0') {
968
0
    free(cmd);
969
0
    cmd = cmd_stringify_argv(wp->argc, wp->argv);
970
0
    if (cmd == NULL || *cmd == '\0') {
971
0
      free(cmd);
972
0
      cmd = xstrdup(wp->shell);
973
0
    }
974
0
  }
975
0
  value = parse_window_name(cmd);
976
0
  free(cmd);
977
0
  return (value);
978
381
}
979
980
/* Callback for pane_current_path. */
981
static void *
982
format_cb_current_path(struct format_tree *ft)
983
221
{
984
221
  struct window_pane  *wp = ft->wp;
985
221
  char      *cwd;
986
987
221
  if (wp == NULL)
988
221
    return (NULL);
989
990
0
  cwd = osdep_get_cwd(wp->fd);
991
0
  if (cwd == NULL)
992
0
    return (NULL);
993
0
  return (xstrdup(cwd));
994
0
}
995
996
/* Callback for history_bytes. */
997
static void *
998
format_cb_history_bytes(struct format_tree *ft)
999
198
{
1000
198
  struct window_pane  *wp = ft->wp;
1001
198
  struct grid   *gd;
1002
198
  struct grid_line  *gl;
1003
198
  size_t       size = 0;
1004
198
  u_int      i;
1005
198
  char      *value;
1006
1007
198
  if (wp == NULL)
1008
198
    return (NULL);
1009
0
  gd = wp->base.grid;
1010
1011
0
  for (i = 0; i < gd->hsize + gd->sy; i++) {
1012
0
    gl = grid_get_line(gd, i);
1013
0
    size += gl->cellsize * sizeof *gl->celldata;
1014
0
    size += gl->extdsize * sizeof *gl->extddata;
1015
0
  }
1016
0
  size += (gd->hsize + gd->sy) * sizeof *gl;
1017
1018
0
  xasprintf(&value, "%zu", size);
1019
0
  return (value);
1020
198
}
1021
1022
/* Callback for history_all_bytes. */
1023
static void *
1024
format_cb_history_all_bytes(struct format_tree *ft)
1025
194
{
1026
194
  struct window_pane  *wp = ft->wp;
1027
194
  struct grid   *gd;
1028
194
  struct grid_line  *gl;
1029
194
  u_int      i, lines, cells = 0, extended_cells = 0;
1030
194
  char      *value;
1031
1032
194
  if (wp == NULL)
1033
194
    return (NULL);
1034
0
  gd = wp->base.grid;
1035
1036
0
  lines = gd->hsize + gd->sy;
1037
0
  for (i = 0; i < lines; i++) {
1038
0
    gl = grid_get_line(gd, i);
1039
0
    cells += gl->cellsize;
1040
0
    extended_cells += gl->extdsize;
1041
0
  }
1042
1043
0
  xasprintf(&value, "%u,%zu,%u,%zu,%u,%zu", lines,
1044
0
      lines * sizeof *gl, cells, cells * sizeof *gl->celldata,
1045
0
      extended_cells, extended_cells * sizeof *gl->extddata);
1046
0
  return (value);
1047
194
}
1048
1049
/* Callback for pane_tabs. */
1050
static void *
1051
format_cb_pane_tabs(struct format_tree *ft)
1052
194
{
1053
194
  struct window_pane  *wp = ft->wp;
1054
194
  struct evbuffer   *buffer;
1055
194
  u_int      i;
1056
194
  int      size;
1057
194
  char      *value = NULL;
1058
1059
194
  if (wp == NULL)
1060
194
    return (NULL);
1061
1062
0
  buffer = evbuffer_new();
1063
0
  if (buffer == NULL)
1064
0
    fatalx("out of memory");
1065
0
  for (i = 0; i < wp->base.grid->sx; i++) {
1066
0
    if (!bit_test(wp->base.tabs, i))
1067
0
      continue;
1068
1069
0
    if (EVBUFFER_LENGTH(buffer) > 0)
1070
0
      evbuffer_add(buffer, ",", 1);
1071
0
    evbuffer_add_printf(buffer, "%u", i);
1072
0
  }
1073
0
  if ((size = EVBUFFER_LENGTH(buffer)) != 0)
1074
0
    value = xmemdup(EVBUFFER_DATA(buffer), size);
1075
0
  evbuffer_free(buffer);
1076
0
  return (value);
1077
0
}
1078
1079
/* Callback for pane_fg. */
1080
static void *
1081
format_cb_pane_fg(struct format_tree *ft)
1082
198
{
1083
198
  struct window_pane  *wp = ft->wp;
1084
198
  struct grid_cell   gc;
1085
1086
198
  if (wp == NULL)
1087
198
    return (NULL);
1088
1089
0
  tty_default_colours(&gc, wp, NULL);
1090
0
  return (xstrdup(colour_tostring(gc.fg)));
1091
198
}
1092
1093
/* Callback for pane_flags. */
1094
static void *
1095
format_cb_pane_flags(struct format_tree *ft)
1096
544
{
1097
544
  if (ft->wp != NULL)
1098
0
    return (xstrdup(window_pane_printable_flags(ft->wp)));
1099
544
  return (NULL);
1100
544
}
1101
1102
/* Callback for pane_floating_flag. */
1103
static void *
1104
format_cb_pane_floating_flag(struct format_tree *ft)
1105
466
{
1106
466
  struct window_pane  *wp = ft->wp;
1107
1108
466
  if (wp != NULL) {
1109
0
    if (window_pane_is_floating(wp))
1110
0
      return (xstrdup("1"));
1111
0
    return (xstrdup("0"));
1112
0
  }
1113
466
  return (NULL);
1114
466
}
1115
1116
/* Callback for pane_modal_flag. */
1117
static void *
1118
format_cb_pane_modal_flag(struct format_tree *ft)
1119
194
{
1120
194
  struct window_pane  *wp = ft->wp;
1121
1122
194
  if (wp != NULL) {
1123
0
    if (wp == wp->window->modal)
1124
0
      return (xstrdup("1"));
1125
0
    return (xstrdup("0"));
1126
0
  }
1127
194
  return (NULL);
1128
194
}
1129
1130
/* Callback for pane_bg. */
1131
static void *
1132
format_cb_pane_bg(struct format_tree *ft)
1133
194
{
1134
194
  struct window_pane  *wp = ft->wp;
1135
194
  struct grid_cell   gc;
1136
1137
194
  if (wp == NULL)
1138
194
    return (NULL);
1139
1140
0
  tty_default_colours(&gc, wp, NULL);
1141
0
  return (xstrdup(colour_tostring(gc.bg)));
1142
194
}
1143
1144
/* Callback for session_group_list. */
1145
static void *
1146
format_cb_session_group_list(struct format_tree *ft)
1147
198
{
1148
198
  struct session    *s = ft->s;
1149
198
  struct session_group  *sg;
1150
198
  struct session    *loop;
1151
198
  struct evbuffer   *buffer;
1152
198
  int      size;
1153
198
  char      *value = NULL;
1154
1155
198
  if (s == NULL)
1156
198
    return (NULL);
1157
0
  sg = session_group_contains(s);
1158
0
  if (sg == NULL)
1159
0
    return (NULL);
1160
1161
0
  buffer = evbuffer_new();
1162
0
  if (buffer == NULL)
1163
0
    fatalx("out of memory");
1164
1165
0
  TAILQ_FOREACH(loop, &sg->sessions, gentry) {
1166
0
    if (EVBUFFER_LENGTH(buffer) > 0)
1167
0
      evbuffer_add(buffer, ",", 1);
1168
0
    evbuffer_add_printf(buffer, "%s", loop->name);
1169
0
  }
1170
1171
0
  if ((size = EVBUFFER_LENGTH(buffer)) != 0)
1172
0
    value = xmemdup(EVBUFFER_DATA(buffer), size);
1173
0
  evbuffer_free(buffer);
1174
0
  return (value);
1175
0
}
1176
1177
/* Callback for session_group_attached_list. */
1178
static void *
1179
format_cb_session_group_attached_list(struct format_tree *ft)
1180
194
{
1181
194
  struct session    *s = ft->s, *client_session, *session_loop;
1182
194
  struct session_group  *sg;
1183
194
  struct client   *loop;
1184
194
  struct evbuffer   *buffer;
1185
194
  int      size;
1186
194
  char      *value = NULL;
1187
1188
194
  if (s == NULL)
1189
194
    return (NULL);
1190
0
  sg = session_group_contains(s);
1191
0
  if (sg == NULL)
1192
0
    return (NULL);
1193
1194
0
  buffer = evbuffer_new();
1195
0
  if (buffer == NULL)
1196
0
    fatalx("out of memory");
1197
1198
0
  TAILQ_FOREACH(loop, &clients, entry) {
1199
0
    client_session = loop->session;
1200
0
    if (client_session == NULL)
1201
0
      continue;
1202
0
    TAILQ_FOREACH(session_loop, &sg->sessions, gentry) {
1203
0
      if (session_loop == client_session){
1204
0
        if (EVBUFFER_LENGTH(buffer) > 0)
1205
0
          evbuffer_add(buffer, ",", 1);
1206
0
        evbuffer_add_printf(buffer, "%s", loop->name);
1207
0
      }
1208
0
    }
1209
0
  }
1210
1211
0
  if ((size = EVBUFFER_LENGTH(buffer)) != 0)
1212
0
    value = xmemdup(EVBUFFER_DATA(buffer), size);
1213
0
  evbuffer_free(buffer);
1214
0
  return (value);
1215
0
}
1216
1217
/* Callback for pane_in_mode. */
1218
static void *
1219
format_cb_pane_in_mode(struct format_tree *ft)
1220
194
{
1221
194
  struct window_pane    *wp = ft->wp;
1222
194
  u_int        n = 0;
1223
194
  struct window_mode_entry  *wme;
1224
194
  char        *value;
1225
1226
194
  if (wp == NULL)
1227
194
    return (NULL);
1228
1229
0
  TAILQ_FOREACH(wme, &wp->modes, entry)
1230
0
    n++;
1231
0
  xasprintf(&value, "%u", n);
1232
0
  return (value);
1233
194
}
1234
1235
/* Callback for pane_at_top. */
1236
static void *
1237
format_cb_pane_at_top(struct format_tree *ft)
1238
195
{
1239
195
  struct window_pane  *wp = ft->wp;
1240
195
  int      status, flag;
1241
195
  char      *value;
1242
1243
195
  if (wp == NULL)
1244
195
    return (NULL);
1245
1246
0
  status = window_pane_get_pane_status(wp);
1247
0
  if (status == PANE_STATUS_TOP)
1248
0
    flag = (wp->yoff == 1);
1249
0
  else
1250
0
    flag = (wp->yoff == 0);
1251
0
  xasprintf(&value, "%d", flag);
1252
0
  return (value);
1253
195
}
1254
1255
/* Callback for pane_at_bottom. */
1256
static void *
1257
format_cb_pane_at_bottom(struct format_tree *ft)
1258
194
{
1259
194
  struct window_pane  *wp = ft->wp;
1260
194
  struct window   *w;
1261
194
  int      status, flag;
1262
194
  char      *value;
1263
1264
194
  if (wp == NULL)
1265
194
    return (NULL);
1266
0
  w = wp->window;
1267
1268
0
  status = window_pane_get_pane_status(wp);
1269
0
  if (status == PANE_STATUS_BOTTOM)
1270
0
    flag = (wp->yoff + (int)wp->sy == (int)w->sy - 1);
1271
0
  else
1272
0
    flag = (wp->yoff + (int)wp->sy == (int)w->sy);
1273
0
  xasprintf(&value, "%d", flag);
1274
0
  return (value);
1275
194
}
1276
1277
/* Callback for cursor_character. */
1278
static void *
1279
format_cb_cursor_character(struct format_tree *ft)
1280
194
{
1281
194
  struct window_pane  *wp = ft->wp;
1282
194
  struct grid_cell   gc;
1283
194
  char      *value = NULL;
1284
1285
194
  if (wp == NULL)
1286
194
    return (NULL);
1287
1288
0
  grid_view_get_cell(wp->base.grid, wp->base.cx, wp->base.cy, &gc);
1289
0
  if (~gc.flags & GRID_FLAG_PADDING)
1290
0
    xasprintf(&value, "%.*s", (int)gc.data.size, gc.data.data);
1291
0
  return (value);
1292
194
}
1293
1294
/* Callback for cursor_colour. */
1295
static void *
1296
format_cb_cursor_colour(struct format_tree *ft)
1297
194
{
1298
194
  struct window_pane  *wp = ft->wp;
1299
1300
194
  if (wp == NULL || wp->screen == NULL)
1301
194
    return (NULL);
1302
1303
0
  if (wp->screen->ccolour != -1)
1304
0
    return (xstrdup(colour_tostring(wp->screen->ccolour)));
1305
0
  return (xstrdup(colour_tostring(wp->screen->default_ccolour)));
1306
0
}
1307
1308
/* Callback for mouse_word. */
1309
static void *
1310
format_cb_mouse_word(struct format_tree *ft)
1311
194
{
1312
194
  struct window_pane  *wp;
1313
194
  struct grid   *gd;
1314
194
  u_int      x, y;
1315
1316
194
  if (!ft->m.valid)
1317
194
    return (NULL);
1318
0
  wp = cmd_mouse_pane(&ft->m, NULL, NULL);
1319
0
  if (wp == NULL)
1320
0
    return (NULL);
1321
0
  if (cmd_mouse_at(wp, &ft->m, &x, &y, 0) != 0)
1322
0
    return (NULL);
1323
1324
0
  if (!TAILQ_EMPTY(&wp->modes)) {
1325
0
    if (window_pane_mode(wp) != WINDOW_PANE_NO_MODE)
1326
0
      return (window_copy_get_word(wp, x, y));
1327
0
    return (NULL);
1328
0
  }
1329
0
  gd = wp->base.grid;
1330
0
  return (format_grid_word(gd, x, gd->hsize + y));
1331
0
}
1332
1333
/* Callback for mouse_hyperlink. */
1334
static void *
1335
format_cb_mouse_hyperlink(struct format_tree *ft)
1336
194
{
1337
194
  struct window_pane  *wp;
1338
194
  struct grid   *gd;
1339
194
  u_int      x, y;
1340
1341
194
  if (!ft->m.valid)
1342
194
    return (NULL);
1343
0
  wp = cmd_mouse_pane(&ft->m, NULL, NULL);
1344
0
  if (wp == NULL)
1345
0
    return (NULL);
1346
0
  if (cmd_mouse_at(wp, &ft->m, &x, &y, 0) != 0)
1347
0
    return (NULL);
1348
1349
0
  if (!TAILQ_EMPTY(&wp->modes)) {
1350
0
    if (window_pane_mode(wp) != WINDOW_PANE_NO_MODE)
1351
0
      return (window_copy_get_hyperlink(wp, x, y));
1352
0
    return (NULL);
1353
0
  }
1354
0
  gd = wp->base.grid;
1355
0
  return (format_grid_hyperlink(gd, x, gd->hsize + y, wp->screen));
1356
0
}
1357
1358
/* Callback for mouse_line. */
1359
static void *
1360
format_cb_mouse_line(struct format_tree *ft)
1361
194
{
1362
194
  struct window_pane  *wp;
1363
194
  struct grid   *gd;
1364
194
  u_int      x, y;
1365
1366
194
  if (!ft->m.valid)
1367
194
    return (NULL);
1368
0
  wp = cmd_mouse_pane(&ft->m, NULL, NULL);
1369
0
  if (wp == NULL)
1370
0
    return (NULL);
1371
0
  if (cmd_mouse_at(wp, &ft->m, &x, &y, 0) != 0)
1372
0
    return (NULL);
1373
1374
0
  if (!TAILQ_EMPTY(&wp->modes)) {
1375
0
    if (window_pane_mode(wp) != WINDOW_PANE_NO_MODE)
1376
0
      return (window_copy_get_line(wp, y));
1377
0
    return (NULL);
1378
0
  }
1379
0
  gd = wp->base.grid;
1380
0
  return (format_grid_line(gd, gd->hsize + y));
1381
0
}
1382
1383
/* Get mouse status position: 0 horizontal, 1 side, -1 unavailable. */
1384
static int
1385
format_mouse_status_at(struct format_tree *ft, u_int *x, u_int *y)
1386
555
{
1387
555
  struct mouse_event  *m = &ft->m;
1388
1389
555
  if (!m->valid)
1390
555
    return (-1);
1391
0
  if (ft->c == NULL || (~ft->c->tty.flags & TTY_STARTED))
1392
0
    return (-1);
1393
1394
0
  *x = m->x;
1395
0
  *y = m->y;
1396
0
  if (m->statusat == 0 && m->y < m->statuslines)
1397
0
    return (0);
1398
0
  if (m->statusat > 0 && m->y >= (u_int)m->statusat) {
1399
0
    *y -= m->statusat;
1400
0
    return (0);
1401
0
  }
1402
0
  if (m->sideat == -1 ||
1403
0
      m->x < (u_int)m->sideat ||
1404
0
      m->x >= m->sideat + m->sidewidth)
1405
0
    return (-1);
1406
0
  *x -= m->sideat;
1407
0
  if (m->statusat == 0)
1408
0
    *y -= m->statuslines;
1409
0
  return (1);
1410
0
}
1411
1412
/* Callback for mouse_status_line. */
1413
static void *
1414
format_cb_mouse_status_line(struct format_tree *ft)
1415
194
{
1416
194
  u_int x, y;
1417
1418
194
  if (format_mouse_status_at(ft, &x, &y) == -1)
1419
194
    return (NULL);
1420
0
  return (format_printf("%u", y));
1421
194
}
1422
1423
/* Callback for mouse_status_range. */
1424
static void *
1425
format_cb_mouse_status_range(struct format_tree *ft)
1426
361
{
1427
361
  struct style_range  *sr;
1428
361
  u_int      x, y;
1429
361
  int      side;
1430
1431
361
  side = format_mouse_status_at(ft, &x, &y);
1432
361
  if (side == -1)
1433
361
    return (NULL);
1434
0
  if (side)
1435
0
    sr = status_side_get_range(ft->c, x, y);
1436
0
  else
1437
0
    sr = status_get_range(ft->c, x, y);
1438
1439
0
  if (sr == NULL)
1440
0
    return (NULL);
1441
0
  switch (sr->type) {
1442
0
  case STYLE_RANGE_NONE:
1443
0
    return (NULL);
1444
0
  case STYLE_RANGE_LEFT:
1445
0
    return (xstrdup("left"));
1446
0
  case STYLE_RANGE_RIGHT:
1447
0
    return (xstrdup("right"));
1448
0
  case STYLE_RANGE_PANE:
1449
0
    return (xstrdup("pane"));
1450
0
  case STYLE_RANGE_WINDOW:
1451
0
    return (xstrdup("window"));
1452
0
  case STYLE_RANGE_SESSION:
1453
0
    return (xstrdup("session"));
1454
0
  case STYLE_RANGE_USER:
1455
0
    return (xstrdup(sr->string));
1456
0
  case STYLE_RANGE_CONTROL:
1457
0
    return (xstrdup("control"));
1458
0
  }
1459
0
  return (NULL);
1460
0
}
1461
1462
/* Callback for alternate_on. */
1463
static void *
1464
format_cb_alternate_on(struct format_tree *ft)
1465
194
{
1466
194
  if (ft->wp != NULL) {
1467
0
    if (ft->wp->base.saved_grid != NULL)
1468
0
      return (xstrdup("1"));
1469
0
    return (xstrdup("0"));
1470
0
  }
1471
194
  return (NULL);
1472
194
}
1473
1474
/* Callback for alternate_saved_x. */
1475
static void *
1476
format_cb_alternate_saved_x(struct format_tree *ft)
1477
194
{
1478
194
  if (ft->wp != NULL)
1479
0
    return (format_printf("%u", ft->wp->base.saved_cx));
1480
194
  return (NULL);
1481
194
}
1482
1483
/* Callback for alternate_saved_y. */
1484
static void *
1485
format_cb_alternate_saved_y(struct format_tree *ft)
1486
194
{
1487
194
  if (ft->wp != NULL)
1488
0
    return (format_printf("%u", ft->wp->base.saved_cy));
1489
194
  return (NULL);
1490
194
}
1491
1492
/* Callback for bracket_paste_flag. */
1493
static void *
1494
format_cb_bracket_paste_flag(struct format_tree *ft)
1495
194
{
1496
194
  if (ft->wp != NULL && ft->wp->screen != NULL) {
1497
0
    if (ft->wp->screen->mode & MODE_BRACKETPASTE)
1498
0
      return (xstrdup("1"));
1499
0
    return (xstrdup("0"));
1500
0
  }
1501
194
  return (NULL);
1502
194
}
1503
1504
/* Callback for buffer_name. */
1505
static void *
1506
format_cb_buffer_name(struct format_tree *ft)
1507
194
{
1508
194
  if (ft->pb != NULL)
1509
0
    return (xstrdup(paste_buffer_name(ft->pb)));
1510
194
  return (NULL);
1511
194
}
1512
1513
/* Callback for buffer_sample. */
1514
static void *
1515
format_cb_buffer_sample(struct format_tree *ft)
1516
194
{
1517
194
  if (ft->pb != NULL)
1518
0
    return (paste_make_sample(ft->pb));
1519
194
  return (NULL);
1520
194
}
1521
1522
/* Callback for buffer_full. */
1523
static void *
1524
format_cb_buffer_full(struct format_tree *ft)
1525
194
{
1526
194
  size_t     size;
1527
194
  const char  *s;
1528
1529
194
  if (ft->pb != NULL) {
1530
0
    s = paste_buffer_data(ft->pb, &size);
1531
0
    if (s != NULL)
1532
0
      return (xstrndup(s, size));
1533
0
  }
1534
194
  return (NULL);
1535
194
}
1536
1537
/* Callback for buffer_size. */
1538
static void *
1539
format_cb_buffer_size(struct format_tree *ft)
1540
214
{
1541
214
  size_t  size;
1542
1543
214
  if (ft->pb != NULL) {
1544
0
    paste_buffer_data(ft->pb, &size);
1545
0
    return (format_printf("%zu", size));
1546
0
  }
1547
214
  return (NULL);
1548
214
}
1549
1550
/* Callback for client_cell_height. */
1551
static void *
1552
format_cb_client_cell_height(struct format_tree *ft)
1553
194
{
1554
194
  if (ft->c != NULL && (ft->c->tty.flags & TTY_STARTED))
1555
0
    return (format_printf("%u", ft->c->tty.ypixel));
1556
194
  return (NULL);
1557
194
}
1558
1559
/* Callback for client_cell_width. */
1560
static void *
1561
format_cb_client_cell_width(struct format_tree *ft)
1562
275
{
1563
275
  if (ft->c != NULL && (ft->c->tty.flags & TTY_STARTED))
1564
0
    return (format_printf("%u", ft->c->tty.xpixel));
1565
275
  return (NULL);
1566
275
}
1567
1568
/* Callback for client_colours. */
1569
static void *
1570
format_cb_client_colours(struct format_tree *ft)
1571
199
{
1572
199
  struct tty_term *term;
1573
199
  u_int    colours;
1574
1575
199
  if (ft->c == NULL || (~ft->c->tty.flags & TTY_STARTED))
1576
199
    return (NULL);
1577
0
  term = ft->c->tty.term;
1578
1579
0
  if (term->flags & TERM_RGBCOLOURS)
1580
0
    colours = 16777216;
1581
0
  else if (term->flags & TERM_256COLOURS)
1582
0
    colours = 256;
1583
0
  else {
1584
0
    colours = tty_term_number(term, TTYC_COLORS);
1585
0
    if (colours < 8)
1586
0
      colours = 2;
1587
0
    else if (colours < 16)
1588
0
      colours = 8;
1589
0
    else
1590
0
      colours = 16;
1591
0
  }
1592
0
  return (format_printf("%u", colours));
1593
199
}
1594
1595
/* Callback for client_control_mode. */
1596
static void *
1597
format_cb_client_control_mode(struct format_tree *ft)
1598
231
{
1599
231
  if (ft->c != NULL) {
1600
0
    if (ft->c->flags & CLIENT_CONTROL)
1601
0
      return (xstrdup("1"));
1602
0
    return (xstrdup("0"));
1603
0
  }
1604
231
  return (NULL);
1605
231
}
1606
1607
/* Callback for client_discarded. */
1608
static void *
1609
format_cb_client_discarded(struct format_tree *ft)
1610
194
{
1611
194
  if (ft->c != NULL)
1612
0
    return (format_printf("%zu", ft->c->discarded));
1613
194
  return (NULL);
1614
194
}
1615
1616
/* Callback for client_flags. */
1617
static void *
1618
format_cb_client_flags(struct format_tree *ft)
1619
198
{
1620
198
  if (ft->c != NULL)
1621
0
    return (xstrdup(server_client_get_flags(ft->c)));
1622
198
  return (NULL);
1623
198
}
1624
1625
/* Callback for client_height. */
1626
static void *
1627
format_cb_client_height(struct format_tree *ft)
1628
194
{
1629
194
  if (ft->c != NULL && (ft->c->tty.flags & TTY_STARTED))
1630
0
    return (format_printf("%u", ft->c->tty.sy));
1631
194
  return (NULL);
1632
194
}
1633
1634
/* Callback for client_key_table. */
1635
static void *
1636
format_cb_client_key_table(struct format_tree *ft)
1637
194
{
1638
194
  if (ft->c != NULL)
1639
0
    return (xstrdup(ft->c->keytable->name));
1640
194
  return (NULL);
1641
194
}
1642
1643
/* Callback for client_last_session. */
1644
static void *
1645
format_cb_client_last_session(struct format_tree *ft)
1646
194
{
1647
194
  if (ft->c != NULL &&
1648
0
      ft->c->last_session != NULL &&
1649
0
      session_alive(ft->c->last_session))
1650
0
    return (xstrdup(ft->c->last_session->name));
1651
194
  return (NULL);
1652
194
}
1653
1654
/* Callback for client_name. */
1655
static void *
1656
format_cb_client_name(struct format_tree *ft)
1657
221
{
1658
221
  if (ft->c != NULL && ft->c->name != NULL)
1659
0
    return (xstrdup(ft->c->name));
1660
221
  return (NULL);
1661
221
}
1662
1663
/* Callback for client_pid. */
1664
static void *
1665
format_cb_client_pid(struct format_tree *ft)
1666
194
{
1667
194
  if (ft->c != NULL)
1668
0
    return (format_printf("%ld", (long)ft->c->pid));
1669
194
  return (NULL);
1670
194
}
1671
1672
/* Callback for client_prefix. */
1673
static void *
1674
format_cb_client_prefix(struct format_tree *ft)
1675
221
{
1676
221
  const char  *name;
1677
1678
221
  if (ft->c != NULL) {
1679
0
    name = server_client_get_key_table(ft->c);
1680
0
    if (strcmp(ft->c->keytable->name, name) == 0)
1681
0
      return (xstrdup("0"));
1682
0
    return (xstrdup("1"));
1683
0
  }
1684
221
  return (NULL);
1685
221
}
1686
1687
/* Callback for client_readonly. */
1688
static void *
1689
format_cb_client_readonly(struct format_tree *ft)
1690
194
{
1691
194
  if (ft->c != NULL) {
1692
0
    if (ft->c->flags & CLIENT_READONLY)
1693
0
      return (xstrdup("1"));
1694
0
    return (xstrdup("0"));
1695
0
  }
1696
194
  return (NULL);
1697
194
}
1698
1699
/* Callback for client_session. */
1700
static void *
1701
format_cb_client_session(struct format_tree *ft)
1702
194
{
1703
194
  if (ft->c != NULL && ft->c->session != NULL)
1704
0
    return (xstrdup(ft->c->session->name));
1705
194
  return (NULL);
1706
194
}
1707
1708
/* Callback for client_termfeatures. */
1709
static void *
1710
format_cb_client_termfeatures(struct format_tree *ft)
1711
194
{
1712
194
  if (ft->c != NULL)
1713
0
    return (xstrdup(tty_get_features(ft->c->term_features)));
1714
194
  return (NULL);
1715
194
}
1716
1717
/* Callback for client_termname. */
1718
static void *
1719
format_cb_client_termname(struct format_tree *ft)
1720
194
{
1721
194
  if (ft->c != NULL && ft->c->term_name != NULL)
1722
0
    return (xstrdup(ft->c->term_name));
1723
194
  return (NULL);
1724
194
}
1725
1726
/* Callback for client_termtype. */
1727
static void *
1728
format_cb_client_termtype(struct format_tree *ft)
1729
194
{
1730
194
  if (ft->c != NULL) {
1731
0
    if (ft->c->term_type == NULL)
1732
0
      return (xstrdup(""));
1733
0
    return (xstrdup(ft->c->term_type));
1734
0
  }
1735
194
  return (NULL);
1736
194
}
1737
1738
/* Callback for client_tty. */
1739
static void *
1740
format_cb_client_tty(struct format_tree *ft)
1741
198
{
1742
198
  if (ft->c != NULL && ft->c->ttyname != NULL)
1743
0
    return (xstrdup(ft->c->ttyname));
1744
198
  return (NULL);
1745
198
}
1746
1747
/* Callback for client_uid. */
1748
static void *
1749
format_cb_client_uid(struct format_tree *ft)
1750
194
{
1751
194
  uid_t uid;
1752
1753
194
  if (ft->c != NULL) {
1754
0
    uid = proc_get_peer_uid(ft->c->peer);
1755
0
    if (uid != (uid_t)-1)
1756
0
      return (format_printf("%ld", (long)uid));
1757
0
  }
1758
194
  return (NULL);
1759
194
}
1760
1761
/* Callback for client_user. */
1762
static void *
1763
format_cb_client_user(struct format_tree *ft)
1764
194
{
1765
194
  uid_t    uid;
1766
194
  struct passwd *pw;
1767
1768
194
  if (ft->c != NULL) {
1769
0
    if (ft->c->user != NULL)
1770
0
      return (xstrdup(ft->c->user));
1771
0
    uid = proc_get_peer_uid(ft->c->peer);
1772
0
    if (uid != (uid_t)-1 && (pw = getpwuid(uid)) != NULL) {
1773
0
      ft->c->user = xstrdup(pw->pw_name);
1774
0
      return (xstrdup(ft->c->user));
1775
0
    }
1776
0
  }
1777
194
  return (NULL);
1778
194
}
1779
1780
/* Callback for client_utf8. */
1781
static void *
1782
format_cb_client_utf8(struct format_tree *ft)
1783
194
{
1784
194
  if (ft->c != NULL) {
1785
0
    if (ft->c->flags & CLIENT_UTF8)
1786
0
      return (xstrdup("1"));
1787
0
    return (xstrdup("0"));
1788
0
  }
1789
194
  return (NULL);
1790
194
}
1791
1792
/* Callback for client_width. */
1793
static void *
1794
format_cb_client_width(struct format_tree *ft)
1795
258
{
1796
258
  if (ft->c != NULL)
1797
0
    return (format_printf("%u", ft->c->tty.sx));
1798
258
  return (NULL);
1799
258
}
1800
1801
/* Callback for client_written. */
1802
static void *
1803
format_cb_client_written(struct format_tree *ft)
1804
194
{
1805
194
  if (ft->c != NULL)
1806
0
    return (format_printf("%zu", ft->c->written));
1807
194
  return (NULL);
1808
194
}
1809
1810
/* Callback for client_theme. */
1811
static void *
1812
format_cb_client_theme(struct format_tree *ft)
1813
194
{
1814
194
  if (ft->c != NULL) {
1815
0
    switch (ft->c->theme) {
1816
0
    case THEME_DARK:
1817
0
      return (xstrdup("dark"));
1818
0
    case THEME_LIGHT:
1819
0
      return (xstrdup("light"));
1820
0
    case THEME_UNKNOWN:
1821
0
      return (NULL);
1822
0
    }
1823
0
  }
1824
194
  return (NULL);
1825
194
}
1826
1827
/* Callback for config_files. */
1828
static void *
1829
format_cb_config_files(__unused struct format_tree *ft)
1830
194
{
1831
194
  char  *s = NULL;
1832
194
  size_t   slen = 0;
1833
194
  u_int  i;
1834
194
  size_t   n;
1835
1836
194
  for (i = 0; i < cfg_nfiles; i++) {
1837
0
    n = strlen(cfg_files[i]) + 1;
1838
0
    s = xrealloc(s, slen + n + 1);
1839
0
    slen += xsnprintf(s + slen, n + 1, "%s,", cfg_files[i]);
1840
0
  }
1841
194
  if (s == NULL)
1842
194
    return (xstrdup(""));
1843
0
  s[slen - 1] = '\0';
1844
0
  return (s);
1845
194
}
1846
1847
/* Callback for cursor_flag. */
1848
static void *
1849
format_cb_cursor_flag(struct format_tree *ft)
1850
198
{
1851
198
  if (ft->wp != NULL) {
1852
0
    if (ft->wp->base.mode & MODE_CURSOR)
1853
0
      return (xstrdup("1"));
1854
0
    return (xstrdup("0"));
1855
0
  }
1856
198
  return (NULL);
1857
198
}
1858
1859
/* Callback for cursor_shape. */
1860
static void *
1861
format_cb_cursor_shape(struct format_tree *ft)
1862
194
{
1863
194
  if (ft->wp != NULL && ft->wp->screen != NULL) {
1864
0
    switch (ft->wp->screen->cstyle) {
1865
0
    case SCREEN_CURSOR_BLOCK:
1866
0
      return (xstrdup("block"));
1867
0
    case SCREEN_CURSOR_UNDERLINE:
1868
0
      return (xstrdup("underline"));
1869
0
    case SCREEN_CURSOR_BAR:
1870
0
      return (xstrdup("bar"));
1871
0
    default:
1872
0
      return (xstrdup("default"));
1873
0
    }
1874
0
  }
1875
194
  return (NULL);
1876
194
}
1877
1878
/* Callback for cursor_very_visible. */
1879
static void *
1880
format_cb_cursor_very_visible(struct format_tree *ft)
1881
198
{
1882
198
  if (ft->wp != NULL && ft->wp->screen != NULL) {
1883
0
    if (ft->wp->screen->mode & MODE_CURSOR_VERY_VISIBLE)
1884
0
      return (xstrdup("1"));
1885
0
    return (xstrdup("0"));
1886
0
  }
1887
198
  return (NULL);
1888
198
}
1889
1890
/* Callback for cursor_x. */
1891
static void *
1892
format_cb_cursor_x(struct format_tree *ft)
1893
322
{
1894
322
  if (ft->wp != NULL)
1895
0
    return (format_printf("%u", ft->wp->base.cx));
1896
322
  return (NULL);
1897
322
}
1898
1899
/* Callback for cursor_y. */
1900
static void *
1901
format_cb_cursor_y(struct format_tree *ft)
1902
194
{
1903
194
  if (ft->wp != NULL)
1904
0
    return (format_printf("%u", ft->wp->base.cy));
1905
194
  return (NULL);
1906
194
}
1907
1908
/* Callback for cursor_blinking. */
1909
static void *
1910
format_cb_cursor_blinking(struct format_tree *ft)
1911
194
{
1912
194
  if (ft->wp != NULL && ft->wp->screen != NULL) {
1913
0
    if (ft->wp->screen->mode & MODE_CURSOR_BLINKING)
1914
0
      return (xstrdup("1"));
1915
0
    return (xstrdup("0"));
1916
0
  }
1917
194
  return (NULL);
1918
194
}
1919
1920
/* Callback for history_added. */
1921
static void *
1922
format_cb_history_added(struct format_tree *ft)
1923
221
{
1924
221
  if (ft->wp != NULL)
1925
0
    return (format_printf("%u", ft->wp->base.grid->scroll_added));
1926
221
  return (NULL);
1927
221
}
1928
1929
/* Callback for history_collected. */
1930
static void *
1931
format_cb_history_collected(struct format_tree *ft)
1932
194
{
1933
194
  struct window_pane  *wp = ft->wp;
1934
1935
194
  if (wp != NULL)
1936
0
    return (format_printf("%u", wp->base.grid->scroll_collected));
1937
194
  return (NULL);
1938
194
}
1939
1940
/* Callback for history_generation. */
1941
static void *
1942
format_cb_history_generation(struct format_tree *ft)
1943
198
{
1944
198
  struct window_pane  *wp = ft->wp;
1945
1946
198
  if (wp != NULL)
1947
0
    return (format_printf("%u", wp->base.grid->scroll_generation));
1948
198
  return (NULL);
1949
198
}
1950
1951
/* Callback for history_limit. */
1952
static void *
1953
format_cb_history_limit(struct format_tree *ft)
1954
194
{
1955
194
  if (ft->wp != NULL)
1956
0
    return (format_printf("%u", ft->wp->base.grid->hlimit));
1957
194
  return (NULL);
1958
194
}
1959
1960
/* Callback for history_size. */
1961
static void *
1962
format_cb_history_size(struct format_tree *ft)
1963
221
{
1964
221
  if (ft->wp != NULL)
1965
0
    return (format_printf("%u", ft->wp->base.grid->hsize));
1966
221
  return (NULL);
1967
221
}
1968
1969
/* Callback for insert_flag. */
1970
static void *
1971
format_cb_insert_flag(struct format_tree *ft)
1972
194
{
1973
194
  if (ft->wp != NULL) {
1974
0
    if (ft->wp->base.mode & MODE_INSERT)
1975
0
      return (xstrdup("1"));
1976
0
    return (xstrdup("0"));
1977
0
  }
1978
194
  return (NULL);
1979
194
}
1980
1981
/* Callback for keypad_cursor_flag. */
1982
static void *
1983
format_cb_keypad_cursor_flag(struct format_tree *ft)
1984
194
{
1985
194
  if (ft->wp != NULL) {
1986
0
    if (ft->wp->base.mode & MODE_KCURSOR)
1987
0
      return (xstrdup("1"));
1988
0
    return (xstrdup("0"));
1989
0
  }
1990
194
  return (NULL);
1991
194
}
1992
1993
/* Callback for keypad_flag. */
1994
static void *
1995
format_cb_keypad_flag(struct format_tree *ft)
1996
194
{
1997
194
  if (ft->wp != NULL) {
1998
0
    if (ft->wp->base.mode & MODE_KKEYPAD)
1999
0
      return (xstrdup("1"));
2000
0
    return (xstrdup("0"));
2001
0
  }
2002
194
  return (NULL);
2003
194
}
2004
2005
/* Callback for mouse_all_flag. */
2006
static void *
2007
format_cb_mouse_all_flag(struct format_tree *ft)
2008
194
{
2009
194
  if (ft->wp != NULL) {
2010
0
    if (ft->wp->base.mode & MODE_MOUSE_ALL)
2011
0
      return (xstrdup("1"));
2012
0
    return (xstrdup("0"));
2013
0
  }
2014
194
  return (NULL);
2015
194
}
2016
2017
/* Callback for mouse_any_flag. */
2018
static void *
2019
format_cb_mouse_any_flag(struct format_tree *ft)
2020
194
{
2021
194
  if (ft->wp != NULL) {
2022
0
    if (ft->wp->base.mode & ALL_MOUSE_MODES)
2023
0
      return (xstrdup("1"));
2024
0
    return (xstrdup("0"));
2025
0
  }
2026
194
  return (NULL);
2027
194
}
2028
2029
/* Callback for mouse_button_flag. */
2030
static void *
2031
format_cb_mouse_button_flag(struct format_tree *ft)
2032
194
{
2033
194
  if (ft->wp != NULL) {
2034
0
    if (ft->wp->base.mode & MODE_MOUSE_BUTTON)
2035
0
      return (xstrdup("1"));
2036
0
    return (xstrdup("0"));
2037
0
  }
2038
194
  return (NULL);
2039
194
}
2040
2041
/* Callback for mouse_pane. */
2042
static void *
2043
format_cb_mouse_pane(struct format_tree *ft)
2044
326
{
2045
326
  struct window_pane  *wp;
2046
2047
326
  if (ft->m.valid) {
2048
0
    wp = cmd_mouse_pane(&ft->m, NULL, NULL);
2049
0
    if (wp != NULL)
2050
0
      return (format_printf("%%%u", wp->id));
2051
0
    return (NULL);
2052
0
  }
2053
326
  return (NULL);
2054
326
}
2055
2056
/* Callback for mouse_sgr_flag. */
2057
static void *
2058
format_cb_mouse_sgr_flag(struct format_tree *ft)
2059
194
{
2060
194
  if (ft->wp != NULL) {
2061
0
    if (ft->wp->base.mode & MODE_MOUSE_SGR)
2062
0
      return (xstrdup("1"));
2063
0
    return (xstrdup("0"));
2064
0
  }
2065
194
  return (NULL);
2066
194
}
2067
2068
/* Callback for mouse_standard_flag. */
2069
static void *
2070
format_cb_mouse_standard_flag(struct format_tree *ft)
2071
198
{
2072
198
  if (ft->wp != NULL) {
2073
0
    if (ft->wp->base.mode & MODE_MOUSE_STANDARD)
2074
0
      return (xstrdup("1"));
2075
0
    return (xstrdup("0"));
2076
0
  }
2077
198
  return (NULL);
2078
198
}
2079
2080
/* Callback for mouse_utf8_flag. */
2081
static void *
2082
format_cb_mouse_utf8_flag(struct format_tree *ft)
2083
194
{
2084
194
  if (ft->wp != NULL) {
2085
0
    if (ft->wp->base.mode & MODE_MOUSE_UTF8)
2086
0
      return (xstrdup("1"));
2087
0
    return (xstrdup("0"));
2088
0
  }
2089
194
  return (NULL);
2090
194
}
2091
2092
/* Callback for mouse_absolute_x. */
2093
static void *
2094
format_cb_mouse_absolute_x(struct format_tree *ft)
2095
0
{
2096
0
  if (!ft->m.valid)
2097
0
    return (NULL);
2098
0
  return (format_printf("%u", ft->m.x));
2099
0
}
2100
2101
/* Callback for mouse_absolute_y. */
2102
static void *
2103
format_cb_mouse_absolute_y(struct format_tree *ft)
2104
0
{
2105
0
  if (!ft->m.valid)
2106
0
    return (NULL);
2107
0
  return (format_printf("%u", ft->m.y));
2108
0
}
2109
2110
/* Callback for mouse_x. */
2111
static void *
2112
format_cb_mouse_x(struct format_tree *ft)
2113
198
{
2114
198
  struct window_pane  *wp;
2115
198
  u_int      x, y;
2116
2117
198
  if (!ft->m.valid)
2118
198
    return (NULL);
2119
0
  if (format_mouse_status_at(ft, &x, &y) != -1)
2120
0
    return (format_printf("%u", x));
2121
0
  wp = cmd_mouse_pane(&ft->m, NULL, NULL);
2122
0
  if (wp != NULL && cmd_mouse_at(wp, &ft->m, &x, &y, 0) == 0)
2123
0
    return (format_printf("%u", x));
2124
0
  return (NULL);
2125
0
}
2126
2127
/* Callback for mouse_y. */
2128
static void *
2129
format_cb_mouse_y(struct format_tree *ft)
2130
198
{
2131
198
  struct window_pane  *wp;
2132
198
  u_int      x, y;
2133
2134
198
  if (!ft->m.valid)
2135
198
    return (NULL);
2136
0
  if (format_mouse_status_at(ft, &x, &y) != -1)
2137
0
    return (format_printf("%u", y));
2138
0
  wp = cmd_mouse_pane(&ft->m, NULL, NULL);
2139
0
  if (wp != NULL && cmd_mouse_at(wp, &ft->m, &x, &y, 0) == 0)
2140
0
    return (format_printf("%u", y));
2141
0
  return (NULL);
2142
0
}
2143
2144
/* Callback for next_session_id. */
2145
static void *
2146
format_cb_next_session_id(__unused struct format_tree *ft)
2147
359
{
2148
359
  return (format_printf("$%u", next_session_id));
2149
359
}
2150
2151
/* Callback for origin_flag. */
2152
static void *
2153
format_cb_origin_flag(struct format_tree *ft)
2154
194
{
2155
194
  if (ft->wp != NULL) {
2156
0
    if (ft->wp->base.mode & MODE_ORIGIN)
2157
0
      return (xstrdup("1"));
2158
0
    return (xstrdup("0"));
2159
0
  }
2160
194
  return (NULL);
2161
194
}
2162
2163
/* Callback for synchronized_output_flag. */
2164
static void *
2165
format_cb_synchronized_output_flag(struct format_tree *ft)
2166
309
{
2167
309
  if (ft->wp != NULL) {
2168
0
    if (ft->wp->base.mode & MODE_SYNC)
2169
0
      return (xstrdup("1"));
2170
0
    return (xstrdup("0"));
2171
0
  }
2172
309
  return (NULL);
2173
309
}
2174
2175
/* Callback for pane_private_modes. */
2176
static void *
2177
format_cb_pane_private_modes(struct format_tree *ft)
2178
221
{
2179
221
  static const struct {
2180
221
    int mode;
2181
221
    int number;
2182
221
  } table[] = {
2183
221
    { MODE_KCURSOR,   1 },  /* DECCKM */
2184
221
    { MODE_ORIGIN,   6 },  /* DECOM */
2185
221
    { MODE_WRAP,   7 },  /* DECAWM */
2186
221
    { MODE_CURSOR_BLINKING, 12 }, /* cursor blinking */
2187
221
    { MODE_CURSOR,   25 }, /* DECTCEM */
2188
221
    { MODE_MOUSE_STANDARD, 1000 }, /* mouse normal tracking */
2189
221
    { MODE_MOUSE_BUTTON, 1002 }, /* mouse button tracking */
2190
221
    { MODE_MOUSE_ALL, 1003 }, /* mouse any tracking */
2191
221
    { MODE_FOCUSON,   1004 }, /* focus reporting */
2192
221
    { MODE_MOUSE_UTF8, 1005 }, /* mouse: UTF-8 */
2193
221
    { MODE_MOUSE_SGR, 1006 }, /* mouse: SGR */
2194
221
    { MODE_BRACKETPASTE, 2004 }, /* bracketed paste */
2195
221
    { MODE_SYNC,   2026 }, /* synchronized output */
2196
221
    { MODE_THEME_UPDATES, 2031 }, /* theme update notifications */
2197
221
  };
2198
221
  int  mode;
2199
221
  char  *value = NULL, *tmp;
2200
221
  u_int  i;
2201
2202
221
  if (ft->wp == NULL)
2203
221
    return (NULL);
2204
0
  mode = ft->wp->base.mode;
2205
2206
0
  for (i = 0; i < nitems(table); i++) {
2207
0
    if (~mode & table[i].mode)
2208
0
      continue;
2209
    /*
2210
     * Only report cursor blinking when set by the application, not
2211
     * when it comes from the cursor-style option.
2212
     */
2213
0
    if (table[i].mode == MODE_CURSOR_BLINKING &&
2214
0
        (~mode & MODE_CURSOR_BLINKING_SET))
2215
0
      continue;
2216
0
    if (value == NULL)
2217
0
      xasprintf(&value, "%d", table[i].number);
2218
0
    else {
2219
0
      xasprintf(&tmp, "%s,%d", value, table[i].number);
2220
0
      free(value);
2221
0
      value = tmp;
2222
0
    }
2223
0
  }
2224
0
  if (value == NULL)
2225
0
    return (xstrdup(""));
2226
0
  return (value);
2227
0
}
2228
2229
/* Callback for pane_active. */
2230
static void *
2231
format_cb_pane_active(struct format_tree *ft)
2232
7.48k
{
2233
7.48k
  if (ft->wp != NULL) {
2234
0
    if (ft->wp == ft->wp->window->active)
2235
0
      return (xstrdup("1"));
2236
0
    return (xstrdup("0"));
2237
0
  }
2238
7.48k
  return (NULL);
2239
7.48k
}
2240
2241
/* Callback for pane_at_left. */
2242
static void *
2243
format_cb_pane_at_left(struct format_tree *ft)
2244
217
{
2245
217
  if (ft->wp != NULL) {
2246
0
    if (ft->wp->xoff == 0)
2247
0
      return (xstrdup("1"));
2248
0
    return (xstrdup("0"));
2249
0
  }
2250
217
  return (NULL);
2251
217
}
2252
2253
/* Callback for pane_at_right. */
2254
static void *
2255
format_cb_pane_at_right(struct format_tree *ft)
2256
194
{
2257
194
  if (ft->wp != NULL) {
2258
0
    if (ft->wp->xoff + (int)ft->wp->sx == (int)ft->wp->window->sx)
2259
0
      return (xstrdup("1"));
2260
0
    return (xstrdup("0"));
2261
0
  }
2262
194
  return (NULL);
2263
194
}
2264
2265
/* Callback for pane_bottom. */
2266
static void *
2267
format_cb_pane_bottom(struct format_tree *ft)
2268
194
{
2269
194
  struct window_pane  *wp = ft->wp;
2270
2271
194
  if (wp != NULL)
2272
0
    return (format_printf("%d", wp->yoff + (int)wp->sy - 1));
2273
194
  return (NULL);
2274
194
}
2275
2276
/* Callback for pane_dead. */
2277
static void *
2278
format_cb_pane_dead(struct format_tree *ft)
2279
196
{
2280
196
  struct window_pane  *wp = ft->wp;
2281
2282
196
  if (wp != NULL) {
2283
0
    if (wp->fd == -1 && (wp->flags & PANE_STATUSREADY))
2284
0
      return (xstrdup("1"));
2285
0
    return (xstrdup("0"));
2286
0
  }
2287
196
  return (NULL);
2288
196
}
2289
2290
/* Callback for pane_dead_signal. */
2291
static void *
2292
format_cb_pane_dead_signal(struct format_tree *ft)
2293
194
{
2294
194
  struct window_pane  *wp = ft->wp;
2295
194
  const char    *name;
2296
2297
194
  if (wp != NULL) {
2298
0
    if ((wp->flags & PANE_STATUSREADY) && WIFSIGNALED(wp->status)) {
2299
0
      name = sig2name(WTERMSIG(wp->status));
2300
0
      return (format_printf("%s", name));
2301
0
    }
2302
0
    return (NULL);
2303
0
  }
2304
194
  return (NULL);
2305
194
}
2306
2307
/* Callback for pane_dead_status. */
2308
static void *
2309
format_cb_pane_dead_status(struct format_tree *ft)
2310
369
{
2311
369
  struct window_pane  *wp = ft->wp;
2312
2313
369
  if (wp != NULL) {
2314
0
    if ((wp->flags & PANE_STATUSREADY) && WIFEXITED(wp->status))
2315
0
      return (format_printf("%d", WEXITSTATUS(wp->status)));
2316
0
    return (NULL);
2317
0
  }
2318
369
  return (NULL);
2319
369
}
2320
2321
/* Callback for pane_dead_time. */
2322
static void *
2323
format_cb_pane_dead_time(struct format_tree *ft)
2324
194
{
2325
194
  struct window_pane  *wp = ft->wp;
2326
2327
194
  if (wp != NULL) {
2328
0
    if (wp->flags & PANE_STATUSDRAWN)
2329
0
      return (&wp->dead_time);
2330
0
    return (NULL);
2331
0
  }
2332
194
  return (NULL);
2333
194
}
2334
2335
/* Callback for pane_last_output_time. */
2336
static void *
2337
format_cb_pane_last_output_time(struct format_tree *ft)
2338
307
{
2339
307
  struct window_pane  *wp = ft->wp;
2340
307
  static struct timeval  tv;
2341
2342
307
  if (wp != NULL && wp->last_output_time != 0) {
2343
0
    tv.tv_sec = wp->last_output_time;
2344
0
    tv.tv_usec = 0;
2345
0
    return (&tv);
2346
0
  }
2347
307
  return (NULL);
2348
307
}
2349
2350
/* Callback for pane_output_generation. */
2351
static void *
2352
format_cb_pane_output_generation(struct format_tree *ft)
2353
221
{
2354
221
  unsigned long long   value;
2355
2356
221
  if (ft->wp != NULL) {
2357
0
    value = ft->wp->output_generation;
2358
0
    return (format_printf("%llu", value));
2359
0
  }
2360
221
  return (NULL);
2361
221
}
2362
2363
/* Callback for pane_last_prompt_time. */
2364
static void *
2365
format_cb_pane_last_prompt_time(struct format_tree *ft)
2366
221
{
2367
221
  struct window_pane  *wp = ft->wp;
2368
221
  static struct timeval  tv;
2369
2370
221
  if (wp != NULL && wp->last_prompt_time != 0) {
2371
0
    tv.tv_sec = wp->last_prompt_time;
2372
0
    tv.tv_usec = 0;
2373
0
    return (&tv);
2374
0
  }
2375
221
  return (NULL);
2376
221
}
2377
2378
/* Callback for pane_command_line. */
2379
static void *
2380
format_cb_pane_command_line(struct format_tree *ft)
2381
0
{
2382
0
  struct window_pane  *wp = ft->wp;
2383
2384
0
  if (wp != NULL && wp->cmd_line != NULL)
2385
0
    return (xstrdup(wp->cmd_line));
2386
0
  return (NULL);
2387
0
}
2388
2389
/* Callback for pane_command_start_time. */
2390
static void *
2391
format_cb_pane_command_start_time(struct format_tree *ft)
2392
198
{
2393
198
  struct window_pane  *wp = ft->wp;
2394
198
  static struct timeval  tv;
2395
2396
198
  if (wp != NULL && wp->cmd_start_time != 0) {
2397
0
    tv.tv_sec = wp->cmd_start_time;
2398
0
    tv.tv_usec = 0;
2399
0
    return (&tv);
2400
0
  }
2401
198
  return (NULL);
2402
198
}
2403
2404
/* Callback for pane_command_end_time. */
2405
static void *
2406
format_cb_pane_command_end_time(struct format_tree *ft)
2407
194
{
2408
194
  struct window_pane  *wp = ft->wp;
2409
194
  static struct timeval  tv;
2410
2411
194
  if (wp != NULL && wp->cmd_end_time != 0) {
2412
0
    tv.tv_sec = wp->cmd_end_time;
2413
0
    tv.tv_usec = 0;
2414
0
    return (&tv);
2415
0
  }
2416
194
  return (NULL);
2417
194
}
2418
2419
/* Callback for pane_command_running. */
2420
static void *
2421
format_cb_pane_command_running(struct format_tree *ft)
2422
194
{
2423
194
  struct window_pane  *wp = ft->wp;
2424
2425
194
  if (wp != NULL)
2426
0
    return (format_printf("%d", !!(wp->flags & PANE_CMDRUNNING)));
2427
194
  return (NULL);
2428
194
}
2429
2430
/* Callback for pane_command_duration. */
2431
static void *
2432
format_cb_pane_command_duration(struct format_tree *ft)
2433
361
{
2434
361
  struct window_pane  *wp = ft->wp;
2435
361
  time_t       end;
2436
2437
361
  if (wp == NULL || wp->cmd_start_time == 0)
2438
361
    return (NULL);
2439
0
  if (wp->flags & PANE_CMDRUNNING)
2440
0
    end = time(NULL);
2441
0
  else
2442
0
    end = wp->cmd_end_time;
2443
0
  if (end < wp->cmd_start_time)
2444
0
    end = wp->cmd_start_time;
2445
0
  return (format_printf("%lld", (long long)(end - wp->cmd_start_time)));
2446
361
}
2447
2448
/* Callback for pane_command_status. */
2449
static void *
2450
format_cb_pane_command_status(struct format_tree *ft)
2451
198
{
2452
198
  struct window_pane  *wp = ft->wp;
2453
2454
198
  if (wp != NULL && wp->cmd_status != -1)
2455
0
    return (format_printf("%d", wp->cmd_status));
2456
198
  return (NULL);
2457
198
}
2458
2459
/* Callback for pane_format. */
2460
static void *
2461
format_cb_pane_format(struct format_tree *ft)
2462
199
{
2463
199
  if (ft->type == FORMAT_TYPE_PANE)
2464
0
    return (xstrdup("1"));
2465
199
  return (xstrdup("0"));
2466
199
}
2467
2468
/* Callback for pane_height. */
2469
static void *
2470
format_cb_pane_height(struct format_tree *ft)
2471
275
{
2472
275
  if (ft->wp != NULL)
2473
0
    return (format_printf("%u", ft->wp->sy));
2474
275
  return (NULL);
2475
275
}
2476
2477
/* Callback for pane_id. */
2478
static void *
2479
format_cb_pane_id(struct format_tree *ft)
2480
975
{
2481
975
  if (ft->wp != NULL)
2482
0
    return (format_printf("%%%u", ft->wp->id));
2483
975
  return (NULL);
2484
975
}
2485
2486
/* Callback for pane_index. */
2487
static void *
2488
format_cb_pane_index(struct format_tree *ft)
2489
362
{
2490
362
  u_int idx;
2491
2492
362
  if (ft->wp != NULL && window_pane_index(ft->wp, &idx) == 0)
2493
0
    return (format_printf("%u", idx));
2494
362
  return (NULL);
2495
362
}
2496
2497
/* Callback for pane_input_off. */
2498
static void *
2499
format_cb_pane_input_off(struct format_tree *ft)
2500
194
{
2501
194
  if (ft->wp != NULL) {
2502
0
    if (ft->wp->flags & PANE_INPUTOFF)
2503
0
      return (xstrdup("1"));
2504
0
    return (xstrdup("0"));
2505
0
  }
2506
194
  return (NULL);
2507
194
}
2508
2509
/* Callback for pane_unseen_changes. */
2510
static void *
2511
format_cb_pane_unseen_changes(struct format_tree *ft)
2512
194
{
2513
194
  if (ft->wp != NULL) {
2514
0
    if (ft->wp->flags & PANE_UNSEENCHANGES)
2515
0
      return (xstrdup("1"));
2516
0
    return (xstrdup("0"));
2517
0
  }
2518
194
  return (NULL);
2519
194
}
2520
2521
/* Callback for pane_key_mode. */
2522
static void *
2523
format_cb_pane_key_mode(struct format_tree *ft)
2524
194
{
2525
194
  if (ft->wp != NULL && ft->wp->screen != NULL) {
2526
0
    switch (ft->wp->screen->mode & EXTENDED_KEY_MODES) {
2527
0
    case MODE_KEYS_EXTENDED:
2528
0
      return (xstrdup("Ext 1"));
2529
0
    case MODE_KEYS_EXTENDED_2:
2530
0
      return (xstrdup("Ext 2"));
2531
0
    default:
2532
0
      return (xstrdup("VT10x"));
2533
0
    }
2534
0
  }
2535
194
  return (NULL);
2536
194
}
2537
2538
/* Callback for pane_last. */
2539
static void *
2540
format_cb_pane_last(struct format_tree *ft)
2541
221
{
2542
221
  if (ft->wp != NULL) {
2543
0
    if (ft->wp == TAILQ_FIRST(&ft->wp->window->last_panes))
2544
0
      return (xstrdup("1"));
2545
0
    return (xstrdup("0"));
2546
0
  }
2547
221
  return (NULL);
2548
221
}
2549
2550
/* Callback for pane_left. */
2551
static void *
2552
format_cb_pane_left(struct format_tree *ft)
2553
225
{
2554
225
  if (ft->wp != NULL)
2555
0
    return (format_printf("%d", ft->wp->xoff));
2556
225
  return (NULL);
2557
225
}
2558
2559
/* Callback for pane_marked. */
2560
static void *
2561
format_cb_pane_marked(struct format_tree *ft)
2562
384
{
2563
384
  if (ft->wp != NULL) {
2564
0
    if (server_check_marked() && marked_pane.wp == ft->wp)
2565
0
      return (xstrdup("1"));
2566
0
    return (xstrdup("0"));
2567
0
  }
2568
384
  return (NULL);
2569
384
}
2570
2571
/* Callback for pane_marked_set. */
2572
static void *
2573
format_cb_pane_marked_set(struct format_tree *ft)
2574
194
{
2575
194
  if (ft->wp != NULL) {
2576
0
    if (server_check_marked())
2577
0
      return (xstrdup("1"));
2578
0
    return (xstrdup("0"));
2579
0
  }
2580
194
  return (NULL);
2581
194
}
2582
2583
/* Callback for pane_mode. */
2584
static void *
2585
format_cb_pane_mode(struct format_tree *ft)
2586
214
{
2587
214
  struct window_mode_entry  *wme;
2588
2589
214
  if (ft->wp != NULL) {
2590
0
    wme = TAILQ_FIRST(&ft->wp->modes);
2591
0
    if (wme != NULL)
2592
0
      return (xstrdup(wme->mode->name));
2593
0
    return (NULL);
2594
0
  }
2595
214
  return (NULL);
2596
214
}
2597
2598
/* Callback for pane_path. */
2599
static void *
2600
format_cb_pane_path(struct format_tree *ft)
2601
198
{
2602
198
  if (ft->wp != NULL) {
2603
0
    if (ft->wp->base.path == NULL)
2604
0
      return (xstrdup(""));
2605
0
    return (xstrdup(ft->wp->base.path));
2606
0
  }
2607
198
  return (NULL);
2608
198
}
2609
2610
/* Callback for pane_pid. */
2611
static void *
2612
format_cb_pane_pid(struct format_tree *ft)
2613
198
{
2614
198
  if (ft->wp != NULL && ft->wp->fd != -1)
2615
0
    return (format_printf("%ld", (long)ft->wp->pid));
2616
198
  return (NULL);
2617
198
}
2618
2619
/* Callback for pane_pipe. */
2620
static void *
2621
format_cb_pane_pipe(struct format_tree *ft)
2622
194
{
2623
194
  if (ft->wp != NULL) {
2624
0
    if (ft->wp->pipe_fd != -1)
2625
0
      return (xstrdup("1"));
2626
0
    return (xstrdup("0"));
2627
0
  }
2628
194
  return (NULL);
2629
194
}
2630
2631
/* Callback for pane_pipe_pid. */
2632
static void *
2633
format_cb_pane_pipe_pid(struct format_tree *ft)
2634
194
{
2635
194
  char  *value = NULL;
2636
2637
194
  if (ft->wp != NULL && ft->wp->pipe_fd != -1)
2638
0
    xasprintf(&value, "%ld", (long)ft->wp->pipe_pid);
2639
194
  return (value);
2640
194
}
2641
2642
/* Callback for pane_pb_progress. */
2643
static void *
2644
format_cb_pane_pb_progress(struct format_tree *ft)
2645
194
{
2646
194
  char  *value = NULL;
2647
2648
194
  if (ft->wp != NULL)
2649
0
    xasprintf(&value, "%d", ft->wp->base.progress_bar.progress);
2650
194
  return (value);
2651
194
}
2652
2653
/* Callback for pane_pb_state. */
2654
static void *
2655
format_cb_pane_pb_state(struct format_tree *ft)
2656
194
{
2657
194
  if (ft->wp != NULL) {
2658
0
    switch (ft->wp->base.progress_bar.state) {
2659
0
    case PROGRESS_BAR_HIDDEN:
2660
0
      return xstrdup("hidden");
2661
0
    case PROGRESS_BAR_NORMAL:
2662
0
      return xstrdup("normal");
2663
0
    case PROGRESS_BAR_ERROR:
2664
0
      return xstrdup("error");
2665
0
    case PROGRESS_BAR_INDETERMINATE:
2666
0
      return xstrdup("indeterminate");
2667
0
    case PROGRESS_BAR_PAUSED:
2668
0
      return xstrdup("paused");
2669
0
    }
2670
0
  }
2671
194
  return (NULL);
2672
194
}
2673
2674
/* Callback for pane_right. */
2675
static void *
2676
format_cb_pane_right(struct format_tree *ft)
2677
364
{
2678
364
  struct window_pane  *wp = ft->wp;
2679
2680
364
  if (wp != NULL)
2681
0
    return (format_printf("%d", wp->xoff + (int)wp->sx - 1));
2682
364
  return (NULL);
2683
364
}
2684
2685
/* Callback for pane_search_string. */
2686
static void *
2687
format_cb_pane_search_string(struct format_tree *ft)
2688
196
{
2689
196
  if (ft->wp != NULL) {
2690
0
    if (ft->wp->searchstr == NULL)
2691
0
      return (xstrdup(""));
2692
0
    return (xstrdup(ft->wp->searchstr));
2693
0
  }
2694
196
  return (NULL);
2695
196
}
2696
2697
/* Callback for pane_synchronized. */
2698
static void *
2699
format_cb_pane_synchronized(struct format_tree *ft)
2700
194
{
2701
194
  if (ft->wp != NULL) {
2702
0
    if (options_get_number(ft->wp->options, "synchronize-panes"))
2703
0
      return (xstrdup("1"));
2704
0
    return (xstrdup("0"));
2705
0
  }
2706
194
  return (NULL);
2707
194
}
2708
2709
/* Callback for pane_title. */
2710
static void *
2711
format_cb_pane_title(struct format_tree *ft)
2712
1.13k
{
2713
1.13k
  if (ft->wp != NULL)
2714
0
    return (xstrdup(ft->wp->base.title));
2715
1.13k
  return (NULL);
2716
1.13k
}
2717
2718
/* Callback for pane_top. */
2719
static void *
2720
format_cb_pane_top(struct format_tree *ft)
2721
194
{
2722
194
  if (ft->wp != NULL)
2723
0
    return (format_printf("%d", ft->wp->yoff));
2724
194
  return (NULL);
2725
194
}
2726
2727
/* Callback for pane_tty. */
2728
static void *
2729
format_cb_pane_tty(struct format_tree *ft)
2730
220
{
2731
220
  if (ft->wp != NULL)
2732
0
    return (xstrdup(ft->wp->tty));
2733
220
  return (NULL);
2734
220
}
2735
2736
/* Callback for pane_unzoomed_height. */
2737
static void *
2738
format_cb_pane_unzoomed_height(struct format_tree *ft)
2739
214
{
2740
214
  struct window_pane  *wp = ft->wp;
2741
214
  struct window   *w;
2742
214
  struct layout_cell  *lc, *root;
2743
214
  int      status, floating;
2744
214
  u_int      sy;
2745
2746
214
  if (wp == NULL)
2747
214
    return (NULL);
2748
0
  w = wp->window;
2749
2750
0
  lc = wp->saved_layout_cell;
2751
0
  if (lc == NULL)
2752
0
    lc = wp->layout_cell;
2753
0
  if (lc == NULL)
2754
0
    return (NULL);
2755
0
  sy = lc->g.sy;
2756
0
  floating = (lc->flags & LAYOUT_CELL_FLOATING);
2757
2758
0
  root = w->saved_layout_root;
2759
0
  if (root == NULL)
2760
0
    root = w->layout_root;
2761
0
  if (lc == wp->saved_layout_cell && !floating)
2762
0
    status = window_get_pane_status(w);
2763
0
  else
2764
0
    status = window_pane_get_pane_status(wp);
2765
0
  if (!floating &&
2766
0
      root != NULL &&
2767
0
      layout_add_horizontal_border(root, lc, status) &&
2768
0
      sy > 1)
2769
0
    sy--;
2770
2771
0
  return (format_printf("%u", sy));
2772
0
}
2773
2774
/* Callback for pane_unzoomed_width. */
2775
static void *
2776
format_cb_pane_unzoomed_width(struct format_tree *ft)
2777
198
{
2778
198
  struct window_pane  *wp = ft->wp;
2779
198
  struct layout_cell  *lc;
2780
198
  int      saved, sb_w, sb_pad;
2781
198
  u_int      sx;
2782
2783
198
  if (wp == NULL)
2784
198
    return (NULL);
2785
2786
0
  lc = wp->saved_layout_cell;
2787
0
  saved = (lc != NULL);
2788
0
  if (lc == NULL)
2789
0
    lc = wp->layout_cell;
2790
0
  if (lc == NULL)
2791
0
    return (NULL);
2792
0
  sx = lc->g.sx;
2793
2794
0
  if ((saved && !SCREEN_IS_ALTERNATE(&wp->base) &&
2795
0
      wp->window->sb == PANE_SCROLLBARS_ALWAYS) ||
2796
0
      (!saved && window_pane_scrollbar_reserve(wp))) {
2797
0
    sb_w = wp->scrollbar_style.width;
2798
0
    sb_pad = wp->scrollbar_style.pad;
2799
0
    if (sb_w < 1)
2800
0
      sb_w = 1;
2801
0
    if (sb_pad < 0)
2802
0
      sb_pad = 0;
2803
0
    if ((int)sx - sb_w - sb_pad < PANE_MINIMUM)
2804
0
      sx = PANE_MINIMUM;
2805
0
    else
2806
0
      sx -= sb_w + sb_pad;
2807
0
  }
2808
2809
0
  return (format_printf("%u", sx));
2810
0
}
2811
2812
/* Callback for pane_width. */
2813
static void *
2814
format_cb_pane_width(struct format_tree *ft)
2815
221
{
2816
221
  if (ft->wp != NULL)
2817
0
    return (format_printf("%u", ft->wp->sx));
2818
221
  return (NULL);
2819
221
}
2820
2821
/* Callback for pane_x. */
2822
static void *
2823
format_cb_pane_x(struct format_tree *ft)
2824
194
{
2825
194
  if (ft->wp != NULL)
2826
0
    return (format_printf("%d", ft->wp->xoff));
2827
194
  return (NULL);
2828
194
}
2829
2830
/* Callback for pane_y. */
2831
static void *
2832
format_cb_pane_y(struct format_tree *ft)
2833
198
{
2834
198
  if (ft->wp != NULL)
2835
0
    return (format_printf("%d", ft->wp->yoff));
2836
198
  return (NULL);
2837
198
}
2838
2839
/* Callback for pane_z. */
2840
static void *
2841
format_cb_pane_z(struct format_tree *ft)
2842
202
{
2843
202
  u_int idx;
2844
2845
202
  if (ft->wp != NULL && window_pane_zindex(ft->wp, &idx) == 0)
2846
0
    return (format_printf("%u", idx));
2847
202
  return (NULL);
2848
202
}
2849
2850
/* Callback for pane_zoomed_flag. */
2851
static void *
2852
format_cb_pane_zoomed_flag(struct format_tree *ft)
2853
198
{
2854
198
  struct window_pane  *wp = ft->wp;
2855
2856
198
  if (wp != NULL) {
2857
0
    if (wp->flags & PANE_ZOOMED)
2858
0
      return (xstrdup("1"));
2859
0
    return (xstrdup("0"));
2860
0
  }
2861
198
  return (NULL);
2862
198
}
2863
2864
/* Callback for scroll_region_lower. */
2865
static void *
2866
format_cb_scroll_region_lower(struct format_tree *ft)
2867
194
{
2868
194
  if (ft->wp != NULL)
2869
0
    return (format_printf("%u", ft->wp->base.rlower));
2870
194
  return (NULL);
2871
194
}
2872
2873
/* Callback for scroll_region_upper. */
2874
static void *
2875
format_cb_scroll_region_upper(struct format_tree *ft)
2876
194
{
2877
194
  if (ft->wp != NULL)
2878
0
    return (format_printf("%u", ft->wp->base.rupper));
2879
194
  return (NULL);
2880
194
}
2881
2882
/* Callback for server_sessions. */
2883
static void *
2884
format_cb_server_sessions(__unused struct format_tree *ft)
2885
194
{
2886
194
  struct session  *s;
2887
194
  u_int    n = 0;
2888
2889
194
  RB_FOREACH(s, sessions, &sessions)
2890
0
    n++;
2891
194
  return (format_printf("%u", n));
2892
194
}
2893
2894
/* Callback for session_active. */
2895
static void *
2896
format_cb_session_active(struct format_tree *ft)
2897
194
{
2898
194
  if (ft->s == NULL || ft->c == NULL)
2899
194
    return (NULL);
2900
2901
0
  if (ft->c->session == ft->s)
2902
0
    return (xstrdup("1"));
2903
0
  return (xstrdup("0"));
2904
0
}
2905
2906
/* Callback for session_activity_flag. */
2907
static void *
2908
format_cb_session_activity_flag(struct format_tree *ft)
2909
194
{
2910
194
  struct winlink    *wl;
2911
2912
194
  if (ft->s != NULL) {
2913
0
    RB_FOREACH(wl, winlinks, &ft->s->windows) {
2914
0
      if (wl->flags & WINLINK_ACTIVITY)
2915
0
        return (xstrdup("1"));
2916
0
    }
2917
0
    return (xstrdup("0"));
2918
0
  }
2919
194
  return (NULL);
2920
194
}
2921
2922
/* Callback for session_bell_flag. */
2923
static void *
2924
format_cb_session_bell_flag(struct format_tree *ft)
2925
194
{
2926
194
  struct winlink    *wl;
2927
2928
194
  if (ft->s != NULL) {
2929
0
    RB_FOREACH(wl, winlinks, &ft->s->windows) {
2930
0
      if (wl->flags & WINLINK_BELL)
2931
0
        return (xstrdup("1"));
2932
0
    }
2933
0
    return (xstrdup("0"));
2934
0
  }
2935
194
  return (NULL);
2936
194
}
2937
2938
/* Callback for session_silence_flag. */
2939
static void *
2940
format_cb_session_silence_flag(struct format_tree *ft)
2941
216
{
2942
216
  struct winlink    *wl;
2943
2944
216
  if (ft->s != NULL) {
2945
0
    RB_FOREACH(wl, winlinks, &ft->s->windows) {
2946
0
      if (wl->flags & WINLINK_SILENCE)
2947
0
        return (xstrdup("1"));
2948
0
    }
2949
0
    return (xstrdup("0"));
2950
0
  }
2951
216
  return (NULL);
2952
216
}
2953
2954
/* Callback for session_attached. */
2955
static void *
2956
format_cb_session_attached(struct format_tree *ft)
2957
438
{
2958
438
  if (ft->s != NULL)
2959
0
    return (format_printf("%u", ft->s->attached));
2960
438
  return (NULL);
2961
438
}
2962
2963
/* Callback for session_format. */
2964
static void *
2965
format_cb_session_format(struct format_tree *ft)
2966
194
{
2967
194
  if (ft->type == FORMAT_TYPE_SESSION)
2968
0
    return (xstrdup("1"));
2969
194
  return (xstrdup("0"));
2970
194
}
2971
2972
/* Callback for session_group. */
2973
static void *
2974
format_cb_session_group(struct format_tree *ft)
2975
194
{
2976
194
  struct session_group  *sg;
2977
2978
194
  if (ft->s != NULL && (sg = session_group_contains(ft->s)) != NULL)
2979
0
    return (xstrdup(sg->name));
2980
194
  return (NULL);
2981
194
}
2982
2983
/* Callback for session_group_attached. */
2984
static void *
2985
format_cb_session_group_attached(struct format_tree *ft)
2986
198
{
2987
198
  struct session_group  *sg;
2988
2989
198
  if (ft->s != NULL && (sg = session_group_contains(ft->s)) != NULL)
2990
0
    return (format_printf("%u", session_group_attached_count (sg)));
2991
198
  return (NULL);
2992
198
}
2993
2994
/* Callback for session_group_many_attached. */
2995
static void *
2996
format_cb_session_group_many_attached(struct format_tree *ft)
2997
194
{
2998
194
  struct session_group  *sg;
2999
3000
194
  if (ft->s != NULL && (sg = session_group_contains(ft->s)) != NULL) {
3001
0
    if (session_group_attached_count (sg) > 1)
3002
0
      return (xstrdup("1"));
3003
0
    return (xstrdup("0"));
3004
0
  }
3005
194
  return (NULL);
3006
194
}
3007
3008
/* Callback for session_group_size. */
3009
static void *
3010
format_cb_session_group_size(struct format_tree *ft)
3011
194
{
3012
194
  struct session_group  *sg;
3013
3014
194
  if (ft->s != NULL && (sg = session_group_contains(ft->s)) != NULL)
3015
0
    return (format_printf("%u", session_group_count (sg)));
3016
194
  return (NULL);
3017
194
}
3018
3019
/* Callback for session_grouped. */
3020
static void *
3021
format_cb_session_grouped(struct format_tree *ft)
3022
414
{
3023
414
  if (ft->s != NULL) {
3024
0
    if (session_group_contains(ft->s) != NULL)
3025
0
      return (xstrdup("1"));
3026
0
    return (xstrdup("0"));
3027
0
  }
3028
414
  return (NULL);
3029
414
}
3030
3031
/* Callback for session_id. */
3032
static void *
3033
format_cb_session_id(struct format_tree *ft)
3034
200
{
3035
200
  if (ft->s != NULL)
3036
0
    return (format_printf("$%u", ft->s->id));
3037
200
  return (NULL);
3038
200
}
3039
3040
/* Callback for session_many_attached. */
3041
static void *
3042
format_cb_session_many_attached(struct format_tree *ft)
3043
194
{
3044
194
  if (ft->s != NULL) {
3045
0
    if (ft->s->attached > 1)
3046
0
      return (xstrdup("1"));
3047
0
    return (xstrdup("0"));
3048
0
  }
3049
194
  return (NULL);
3050
194
}
3051
3052
/* Callback for session_marked. */
3053
static void *
3054
format_cb_session_marked(struct format_tree *ft)
3055
194
{
3056
194
  if (ft->s != NULL) {
3057
0
    if (server_check_marked() && marked_pane.s == ft->s)
3058
0
      return (xstrdup("1"));
3059
0
    return (xstrdup("0"));
3060
0
  }
3061
194
  return (NULL);
3062
194
}
3063
3064
/* Callback for session_name. */
3065
static void *
3066
format_cb_session_name(struct format_tree *ft)
3067
1.21M
{
3068
1.21M
  if (ft->s != NULL)
3069
0
    return (xstrdup(ft->s->name));
3070
1.21M
  return (NULL);
3071
1.21M
}
3072
3073
/* Callback for session_path. */
3074
static void *
3075
format_cb_session_path(struct format_tree *ft)
3076
194
{
3077
194
  if (ft->s != NULL)
3078
0
    return (xstrdup(ft->s->cwd));
3079
194
  return (NULL);
3080
194
}
3081
3082
/* Callback for session_windows. */
3083
static void *
3084
format_cb_session_windows(struct format_tree *ft)
3085
414
{
3086
414
  if (ft->s != NULL)
3087
0
    return (format_printf("%u", winlink_count(&ft->s->windows)));
3088
414
  return (NULL);
3089
414
}
3090
3091
/* Callback for socket_path. */
3092
static void *
3093
format_cb_socket_path(__unused struct format_tree *ft)
3094
198
{
3095
198
  return (xstrdup(socket_path));
3096
198
}
3097
3098
/* Callback for version. */
3099
static void *
3100
format_cb_version(__unused struct format_tree *ft)
3101
223
{
3102
223
  return (xstrdup(getversion()));
3103
223
}
3104
3105
/* Callback for image_support. */
3106
static void *
3107
format_cb_image_support(__unused struct format_tree *ft)
3108
287
{
3109
#ifdef ENABLE_IMAGES
3110
  return (xstrdup("1"));
3111
#else
3112
287
  return (xstrdup("0"));
3113
287
#endif
3114
287
}
3115
3116
/* Callback for active_window_index. */
3117
static void *
3118
format_cb_active_window_index(struct format_tree *ft)
3119
194
{
3120
194
  if (ft->s != NULL)
3121
0
    return (format_printf("%u", ft->s->curw->idx));
3122
194
  return (NULL);
3123
194
}
3124
3125
/* Callback for last_window_index. */
3126
static void *
3127
format_cb_last_window_index(struct format_tree *ft)
3128
194
{
3129
194
  struct winlink  *wl;
3130
3131
194
  if (ft->s != NULL) {
3132
0
    wl = RB_MAX(winlinks, &ft->s->windows);
3133
0
    return (format_printf("%u", wl->idx));
3134
0
  }
3135
194
  return (NULL);
3136
194
}
3137
3138
/* Callback for window_active. */
3139
static void *
3140
format_cb_window_active(struct format_tree *ft)
3141
194
{
3142
194
  if (ft->wl != NULL) {
3143
0
    if (ft->wl == ft->wl->session->curw)
3144
0
      return (xstrdup("1"));
3145
0
    return (xstrdup("0"));
3146
0
  }
3147
194
  return (NULL);
3148
194
}
3149
3150
/* Callback for window_activity_flag. */
3151
static void *
3152
format_cb_window_activity_flag(struct format_tree *ft)
3153
635
{
3154
635
  if (ft->wl != NULL) {
3155
0
    if (ft->wl->flags & WINLINK_ACTIVITY)
3156
0
      return (xstrdup("1"));
3157
0
    return (xstrdup("0"));
3158
0
  }
3159
635
  return (NULL);
3160
635
}
3161
3162
/* Callback for window_bell_flag. */
3163
static void *
3164
format_cb_window_bell_flag(struct format_tree *ft)
3165
740
{
3166
740
  if (ft->wl != NULL) {
3167
0
    if (ft->wl->flags & WINLINK_BELL)
3168
0
      return (xstrdup("1"));
3169
0
    return (xstrdup("0"));
3170
0
  }
3171
740
  return (NULL);
3172
740
}
3173
3174
/* Callback for window_bigger. */
3175
static void *
3176
format_cb_window_bigger(struct format_tree *ft)
3177
335
{
3178
335
  u_int ox, oy, sx, sy;
3179
3180
335
  if (ft->c != NULL) {
3181
0
    if (tty_window_offset(&ft->c->tty, &ox, &oy, &sx, &sy))
3182
0
      return (xstrdup("1"));
3183
0
    return (xstrdup("0"));
3184
0
  }
3185
335
  return (NULL);
3186
335
}
3187
3188
/* Callback for window_cell_height. */
3189
static void *
3190
format_cb_window_cell_height(struct format_tree *ft)
3191
194
{
3192
194
  if (ft->w != NULL)
3193
0
    return (format_printf("%u", ft->w->ypixel));
3194
194
  return (NULL);
3195
194
}
3196
3197
/* Callback for window_cell_width. */
3198
static void *
3199
format_cb_window_cell_width(struct format_tree *ft)
3200
194
{
3201
194
  if (ft->w != NULL)
3202
0
    return (format_printf("%u", ft->w->xpixel));
3203
194
  return (NULL);
3204
194
}
3205
3206
/* Callback for window_end_flag. */
3207
static void *
3208
format_cb_window_end_flag(struct format_tree *ft)
3209
198
{
3210
198
  if (ft->wl != NULL) {
3211
0
    if (ft->wl == RB_MAX(winlinks, &ft->wl->session->windows))
3212
0
      return (xstrdup("1"));
3213
0
    return (xstrdup("0"));
3214
0
  }
3215
198
  return (NULL);
3216
198
}
3217
3218
/* Callback for window_flags. */
3219
static void *
3220
format_cb_window_flags(struct format_tree *ft)
3221
456
{
3222
456
  if (ft->wl != NULL)
3223
0
    return (xstrdup(window_printable_flags(ft->wl, 1)));
3224
456
  return (NULL);
3225
456
}
3226
3227
/* Callback for window_format. */
3228
static void *
3229
format_cb_window_format(struct format_tree *ft)
3230
196
{
3231
196
  if (ft->type == FORMAT_TYPE_WINDOW)
3232
0
    return (xstrdup("1"));
3233
196
  return (xstrdup("0"));
3234
196
}
3235
3236
/* Callback for window_height. */
3237
static void *
3238
format_cb_window_height(struct format_tree *ft)
3239
194
{
3240
194
  if (ft->w != NULL)
3241
0
    return (format_printf("%u", ft->w->sy));
3242
194
  return (NULL);
3243
194
}
3244
3245
/* Callback for window_manual_height. */
3246
static void *
3247
format_cb_window_manual_height(struct format_tree *ft)
3248
194
{
3249
194
  struct window *w = ft->w;
3250
3251
194
  if (w == NULL)
3252
194
    return (NULL);
3253
0
  if (options_get_number(w->options, "window-size") != WINDOW_SIZE_MANUAL)
3254
0
    return (xstrdup(""));
3255
0
  return (format_printf("%u", w->manual_sy));
3256
0
}
3257
3258
/* Callback for window_id. */
3259
static void *
3260
format_cb_window_id(struct format_tree *ft)
3261
222
{
3262
222
  if (ft->w != NULL)
3263
0
    return (format_printf("@%u", ft->w->id));
3264
222
  return (NULL);
3265
222
}
3266
3267
/* Callback for window_index. */
3268
static void *
3269
format_cb_window_index(struct format_tree *ft)
3270
13.8k
{
3271
13.8k
  if (ft->wl != NULL)
3272
0
    return (format_printf("%d", ft->wl->idx));
3273
13.8k
  return (NULL);
3274
13.8k
}
3275
3276
/* Callback for window_last_flag. */
3277
static void *
3278
format_cb_window_last_flag(struct format_tree *ft)
3279
580
{
3280
580
  if (ft->wl != NULL) {
3281
0
    if (ft->wl == TAILQ_FIRST(&ft->wl->session->lastw))
3282
0
      return (xstrdup("1"));
3283
0
    return (xstrdup("0"));
3284
0
  }
3285
580
  return (NULL);
3286
580
}
3287
3288
/* Callback for window_linked. */
3289
static void *
3290
format_cb_window_linked(struct format_tree *ft)
3291
207
{
3292
207
  struct winlink  *wl;
3293
207
  struct session  *s;
3294
207
  int    found = 0;
3295
3296
207
  if (ft->wl != NULL) {
3297
0
    RB_FOREACH(s, sessions, &sessions) {
3298
0
      RB_FOREACH(wl, winlinks, &s->windows) {
3299
0
        if (wl->window == ft->wl->window) {
3300
0
          if (found)
3301
0
            return (xstrdup("1"));
3302
0
          found = 1;
3303
0
        }
3304
0
      }
3305
0
    }
3306
0
    return (xstrdup("0"));
3307
0
  }
3308
207
  return (NULL);
3309
207
}
3310
3311
/* Callback for window_linked_sessions. */
3312
static void *
3313
format_cb_window_linked_sessions(struct format_tree *ft)
3314
194
{
3315
194
  struct window   *w;
3316
194
  struct session_group  *sg;
3317
194
  struct session    *s;
3318
194
  u_int      n = 0;
3319
3320
194
  if (ft->wl == NULL)
3321
194
    return (NULL);
3322
0
  w = ft->wl->window;
3323
3324
0
  RB_FOREACH(sg, session_groups, &session_groups) {
3325
0
    s = TAILQ_FIRST(&sg->sessions);
3326
0
    if (winlink_find_by_window(&s->windows, w) != NULL)
3327
0
      n++;
3328
0
  }
3329
0
  RB_FOREACH(s, sessions, &sessions) {
3330
0
    if (session_group_contains(s) != NULL)
3331
0
      continue;
3332
0
    if (winlink_find_by_window(&s->windows, w) != NULL)
3333
0
      n++;
3334
0
  }
3335
0
  return (format_printf("%u", n));
3336
194
}
3337
3338
/* Callback for window_marked_flag. */
3339
static void *
3340
format_cb_window_marked_flag(struct format_tree *ft)
3341
218
{
3342
218
  if (ft->wl != NULL) {
3343
0
    if (server_check_marked() && marked_pane.wl == ft->wl)
3344
0
      return (xstrdup("1"));
3345
0
    return (xstrdup("0"));
3346
0
  }
3347
218
  return (NULL);
3348
218
}
3349
3350
/* Callback for window_modal_pane. */
3351
static void *
3352
format_cb_window_modal_pane(struct format_tree *ft)
3353
311
{
3354
311
  if (ft->w != NULL && ft->w->modal != NULL)
3355
0
    return (format_printf("%%%u", ft->w->modal->id));
3356
311
  return (NULL);
3357
311
}
3358
3359
/* Callback for window_name. */
3360
static void *
3361
format_cb_window_name(struct format_tree *ft)
3362
662
{
3363
662
  if (ft->w != NULL)
3364
0
    return (format_printf("%s", ft->w->name));
3365
662
  return (NULL);
3366
662
}
3367
3368
/* Callback for window_offset_x. */
3369
static void *
3370
format_cb_window_offset_x(struct format_tree *ft)
3371
221
{
3372
221
  u_int ox, oy, sx, sy;
3373
3374
221
  if (ft->c != NULL) {
3375
0
    if (tty_window_offset(&ft->c->tty, &ox, &oy, &sx, &sy))
3376
0
      return (format_printf("%u", ox));
3377
0
    return (NULL);
3378
0
  }
3379
221
  return (NULL);
3380
221
}
3381
3382
/* Callback for window_offset_y. */
3383
static void *
3384
format_cb_window_offset_y(struct format_tree *ft)
3385
221
{
3386
221
  u_int ox, oy, sx, sy;
3387
3388
221
  if (ft->c != NULL) {
3389
0
    if (tty_window_offset(&ft->c->tty, &ox, &oy, &sx, &sy))
3390
0
      return (format_printf("%u", oy));
3391
0
    return (NULL);
3392
0
  }
3393
221
  return (NULL);
3394
221
}
3395
3396
/* Callback for window_panes. */
3397
static void *
3398
format_cb_window_panes(struct format_tree *ft)
3399
218
{
3400
218
  if (ft->w != NULL)
3401
0
    return (format_printf("%u", window_count_panes(ft->w, 1)));
3402
218
  return (NULL);
3403
218
}
3404
3405
/* Callback for window_raw_flags. */
3406
static void *
3407
format_cb_window_raw_flags(struct format_tree *ft)
3408
198
{
3409
198
  if (ft->wl != NULL)
3410
0
    return (xstrdup(window_printable_flags(ft->wl, 0)));
3411
198
  return (NULL);
3412
198
}
3413
3414
/* Callback for window_silence_flag. */
3415
static void *
3416
format_cb_window_silence_flag(struct format_tree *ft)
3417
740
{
3418
740
  if (ft->wl != NULL) {
3419
0
    if (ft->wl->flags & WINLINK_SILENCE)
3420
0
      return (xstrdup("1"));
3421
0
    return (xstrdup("0"));
3422
0
  }
3423
740
  return (NULL);
3424
740
}
3425
3426
/* Callback for window_start_flag. */
3427
static void *
3428
format_cb_window_start_flag(struct format_tree *ft)
3429
196
{
3430
196
  if (ft->wl != NULL) {
3431
0
    if (ft->wl == RB_MIN(winlinks, &ft->wl->session->windows))
3432
0
      return (xstrdup("1"));
3433
0
    return (xstrdup("0"));
3434
0
  }
3435
196
  return (NULL);
3436
196
}
3437
3438
/* Callback for window_width. */
3439
static void *
3440
format_cb_window_width(struct format_tree *ft)
3441
219
{
3442
219
  if (ft->w != NULL)
3443
0
    return (format_printf("%u", ft->w->sx));
3444
219
  return (NULL);
3445
219
}
3446
3447
/* Callback for window_manual_width. */
3448
static void *
3449
format_cb_window_manual_width(struct format_tree *ft)
3450
258
{
3451
258
  struct window *w = ft->w;
3452
3453
258
  if (w == NULL)
3454
258
    return (NULL);
3455
0
  if (options_get_number(w->options, "window-size") != WINDOW_SIZE_MANUAL)
3456
0
    return (xstrdup(""));
3457
0
  return (format_printf("%u", w->manual_sx));
3458
0
}
3459
3460
/* Callback for window_zoomed_flag. */
3461
static void *
3462
format_cb_window_zoomed_flag(struct format_tree *ft)
3463
194
{
3464
194
  if (ft->w != NULL) {
3465
0
    if (ft->w->flags & WINDOW_ZOOMED)
3466
0
      return (xstrdup("1"));
3467
0
    return (xstrdup("0"));
3468
0
  }
3469
194
  return (NULL);
3470
194
}
3471
3472
/* Callback for wrap_flag. */
3473
static void *
3474
format_cb_wrap_flag(struct format_tree *ft)
3475
194
{
3476
194
  if (ft->wp != NULL) {
3477
0
    if (ft->wp->base.mode & MODE_WRAP)
3478
0
      return (xstrdup("1"));
3479
0
    return (xstrdup("0"));
3480
0
  }
3481
194
  return (NULL);
3482
194
}
3483
3484
/* Callback for buffer_created. */
3485
static void *
3486
format_cb_buffer_created(struct format_tree *ft)
3487
194
{
3488
194
  static struct timeval  tv;
3489
3490
194
  if (ft->pb != NULL) {
3491
0
    timerclear(&tv);
3492
0
    tv.tv_sec = paste_buffer_created(ft->pb);
3493
0
    return (&tv);
3494
0
  }
3495
194
  return (NULL);
3496
194
}
3497
3498
/* Callback for client_activity. */
3499
static void *
3500
format_cb_client_activity(struct format_tree *ft)
3501
198
{
3502
198
  if (ft->c != NULL)
3503
0
    return (&ft->c->activity_time);
3504
198
  return (NULL);
3505
198
}
3506
3507
/* Callback for client_created. */
3508
static void *
3509
format_cb_client_created(struct format_tree *ft)
3510
194
{
3511
194
  if (ft->c != NULL)
3512
0
    return (&ft->c->creation_time);
3513
194
  return (NULL);
3514
194
}
3515
3516
/* Callback for session_activity. */
3517
static void *
3518
format_cb_session_activity(struct format_tree *ft)
3519
221
{
3520
221
  if (ft->s != NULL)
3521
0
    return (&ft->s->activity_time);
3522
221
  return (NULL);
3523
221
}
3524
3525
/* Callback for session_created. */
3526
static void *
3527
format_cb_session_created(struct format_tree *ft)
3528
218
{
3529
218
  if (ft->s != NULL)
3530
0
    return (&ft->s->creation_time);
3531
218
  return (NULL);
3532
218
}
3533
3534
/* Callback for session_last_attached. */
3535
static void *
3536
format_cb_session_last_attached(struct format_tree *ft)
3537
210
{
3538
210
  if (ft->s != NULL)
3539
0
    return (&ft->s->last_attached_time);
3540
210
  return (NULL);
3541
210
}
3542
3543
/* Callback for start_time. */
3544
static void *
3545
format_cb_start_time(__unused struct format_tree *ft)
3546
210
{
3547
210
  return (&start_time);
3548
210
}
3549
3550
/* Callback for window_activity. */
3551
static void *
3552
format_cb_window_activity(struct format_tree *ft)
3553
194
{
3554
194
  if (ft->w != NULL)
3555
0
    return (&ft->w->activity_time);
3556
194
  return (NULL);
3557
194
}
3558
3559
/* Callback for buffer_mode_format, */
3560
static void *
3561
format_cb_buffer_mode_format(__unused struct format_tree *ft)
3562
226
{
3563
226
  return (xstrdup(window_buffer_mode.default_format));
3564
226
}
3565
3566
/* Callback for client_mode_format, */
3567
static void *
3568
format_cb_client_mode_format(__unused struct format_tree *ft)
3569
195
{
3570
195
  return (xstrdup(window_client_mode.default_format));
3571
195
}
3572
3573
/* Callback for tree_mode_format, */
3574
static void *
3575
format_cb_tree_mode_format(__unused struct format_tree *ft)
3576
835
{
3577
835
  return (xstrdup(window_tree_mode.default_format));
3578
835
}
3579
3580
/* Callback for uid. */
3581
static void *
3582
format_cb_uid(__unused struct format_tree *ft)
3583
1.27k
{
3584
1.27k
  return (format_printf("%ld", (long)getuid()));
3585
1.27k
}
3586
3587
/* Callback for user. */
3588
static void *
3589
format_cb_user(__unused struct format_tree *ft)
3590
216
{
3591
216
  static char *cached;
3592
216
  struct passwd *pw;
3593
3594
216
  if (cached == NULL && (pw = getpwuid(getuid())) != NULL)
3595
1
    cached = xstrdup(pw->pw_name);
3596
216
  if (cached != NULL)
3597
216
    return (xstrdup(cached));
3598
0
  return (NULL);
3599
216
}
3600
3601
/* Format table type. */
3602
enum format_table_type {
3603
  FORMAT_TABLE_STRING,
3604
  FORMAT_TABLE_TIME
3605
};
3606
3607
/* Format table entry. */
3608
struct format_table_entry {
3609
  const char    *key;
3610
  enum format_table_type   type;
3611
  format_cb    cb;
3612
};
3613
3614
/*
3615
 * Format table. Default format variables (that are almost always in the tree
3616
 * and where the value is expanded by a callback in this file) are listed here.
3617
 * Only variables which are added by the caller go into the tree.
3618
 */
3619
static const struct format_table_entry format_table[] = {
3620
  { "active_window_index", FORMAT_TABLE_STRING,
3621
    format_cb_active_window_index
3622
  },
3623
  { "alternate_on", FORMAT_TABLE_STRING,
3624
    format_cb_alternate_on
3625
  },
3626
  { "alternate_saved_x", FORMAT_TABLE_STRING,
3627
    format_cb_alternate_saved_x
3628
  },
3629
  { "alternate_saved_y", FORMAT_TABLE_STRING,
3630
    format_cb_alternate_saved_y
3631
  },
3632
  { "bracket_paste_flag", FORMAT_TABLE_STRING,
3633
    format_cb_bracket_paste_flag
3634
  },
3635
  { "buffer_created", FORMAT_TABLE_TIME,
3636
    format_cb_buffer_created
3637
  },
3638
  { "buffer_full", FORMAT_TABLE_STRING,
3639
    format_cb_buffer_full
3640
  },
3641
  { "buffer_mode_format", FORMAT_TABLE_STRING,
3642
    format_cb_buffer_mode_format
3643
  },
3644
  { "buffer_name", FORMAT_TABLE_STRING,
3645
    format_cb_buffer_name
3646
  },
3647
  { "buffer_sample", FORMAT_TABLE_STRING,
3648
    format_cb_buffer_sample
3649
  },
3650
  { "buffer_size", FORMAT_TABLE_STRING,
3651
    format_cb_buffer_size
3652
  },
3653
  { "client_activity", FORMAT_TABLE_TIME,
3654
    format_cb_client_activity
3655
  },
3656
  { "client_cell_height", FORMAT_TABLE_STRING,
3657
    format_cb_client_cell_height
3658
  },
3659
  { "client_cell_width", FORMAT_TABLE_STRING,
3660
    format_cb_client_cell_width
3661
  },
3662
  { "client_colours", FORMAT_TABLE_STRING,
3663
    format_cb_client_colours
3664
  },
3665
  { "client_control_mode", FORMAT_TABLE_STRING,
3666
    format_cb_client_control_mode
3667
  },
3668
  { "client_created", FORMAT_TABLE_TIME,
3669
    format_cb_client_created
3670
  },
3671
  { "client_discarded", FORMAT_TABLE_STRING,
3672
    format_cb_client_discarded
3673
  },
3674
  { "client_flags", FORMAT_TABLE_STRING,
3675
    format_cb_client_flags
3676
  },
3677
  { "client_height", FORMAT_TABLE_STRING,
3678
    format_cb_client_height
3679
  },
3680
  { "client_key_table", FORMAT_TABLE_STRING,
3681
    format_cb_client_key_table
3682
  },
3683
  { "client_last_session", FORMAT_TABLE_STRING,
3684
    format_cb_client_last_session
3685
  },
3686
  { "client_mode_format", FORMAT_TABLE_STRING,
3687
    format_cb_client_mode_format
3688
  },
3689
  { "client_name", FORMAT_TABLE_STRING,
3690
    format_cb_client_name
3691
  },
3692
  { "client_pid", FORMAT_TABLE_STRING,
3693
    format_cb_client_pid
3694
  },
3695
  { "client_prefix", FORMAT_TABLE_STRING,
3696
    format_cb_client_prefix
3697
  },
3698
  { "client_readonly", FORMAT_TABLE_STRING,
3699
    format_cb_client_readonly
3700
  },
3701
  { "client_session", FORMAT_TABLE_STRING,
3702
    format_cb_client_session
3703
  },
3704
  { "client_termfeatures", FORMAT_TABLE_STRING,
3705
    format_cb_client_termfeatures
3706
  },
3707
  { "client_termname", FORMAT_TABLE_STRING,
3708
    format_cb_client_termname
3709
  },
3710
  { "client_termtype", FORMAT_TABLE_STRING,
3711
    format_cb_client_termtype
3712
  },
3713
  { "client_theme", FORMAT_TABLE_STRING,
3714
    format_cb_client_theme
3715
  },
3716
  { "client_tty", FORMAT_TABLE_STRING,
3717
    format_cb_client_tty
3718
  },
3719
  { "client_uid", FORMAT_TABLE_STRING,
3720
    format_cb_client_uid
3721
  },
3722
  { "client_user", FORMAT_TABLE_STRING,
3723
    format_cb_client_user
3724
  },
3725
  { "client_utf8", FORMAT_TABLE_STRING,
3726
    format_cb_client_utf8
3727
  },
3728
  { "client_width", FORMAT_TABLE_STRING,
3729
    format_cb_client_width
3730
  },
3731
  { "client_written", FORMAT_TABLE_STRING,
3732
    format_cb_client_written
3733
  },
3734
  { "config_files", FORMAT_TABLE_STRING,
3735
    format_cb_config_files
3736
  },
3737
  { "cursor_blinking", FORMAT_TABLE_STRING,
3738
    format_cb_cursor_blinking
3739
  },
3740
  { "cursor_character", FORMAT_TABLE_STRING,
3741
    format_cb_cursor_character
3742
  },
3743
  { "cursor_colour", FORMAT_TABLE_STRING,
3744
    format_cb_cursor_colour
3745
  },
3746
  { "cursor_flag", FORMAT_TABLE_STRING,
3747
    format_cb_cursor_flag
3748
  },
3749
  { "cursor_shape", FORMAT_TABLE_STRING,
3750
    format_cb_cursor_shape
3751
  },
3752
  { "cursor_very_visible", FORMAT_TABLE_STRING,
3753
    format_cb_cursor_very_visible
3754
  },
3755
  { "cursor_x", FORMAT_TABLE_STRING,
3756
    format_cb_cursor_x
3757
  },
3758
  { "cursor_y", FORMAT_TABLE_STRING,
3759
    format_cb_cursor_y
3760
  },
3761
  { "history_added", FORMAT_TABLE_STRING,
3762
    format_cb_history_added
3763
  },
3764
  { "history_all_bytes", FORMAT_TABLE_STRING,
3765
    format_cb_history_all_bytes
3766
  },
3767
  { "history_bytes", FORMAT_TABLE_STRING,
3768
    format_cb_history_bytes
3769
  },
3770
  { "history_collected", FORMAT_TABLE_STRING,
3771
    format_cb_history_collected
3772
  },
3773
  { "history_generation", FORMAT_TABLE_STRING,
3774
    format_cb_history_generation
3775
  },
3776
  { "history_limit", FORMAT_TABLE_STRING,
3777
    format_cb_history_limit
3778
  },
3779
  { "history_size", FORMAT_TABLE_STRING,
3780
    format_cb_history_size
3781
  },
3782
  { "host", FORMAT_TABLE_STRING,
3783
    format_cb_host
3784
  },
3785
  { "host_short", FORMAT_TABLE_STRING,
3786
    format_cb_host_short
3787
  },
3788
  { "image_support", FORMAT_TABLE_STRING,
3789
    format_cb_image_support
3790
  },
3791
  { "insert_flag", FORMAT_TABLE_STRING,
3792
    format_cb_insert_flag
3793
  },
3794
  { "keypad_cursor_flag", FORMAT_TABLE_STRING,
3795
    format_cb_keypad_cursor_flag
3796
  },
3797
  { "keypad_flag", FORMAT_TABLE_STRING,
3798
    format_cb_keypad_flag
3799
  },
3800
  { "last_window_index", FORMAT_TABLE_STRING,
3801
    format_cb_last_window_index
3802
  },
3803
  { "mouse_absolute_x", FORMAT_TABLE_STRING,
3804
    format_cb_mouse_absolute_x
3805
  },
3806
  { "mouse_absolute_y", FORMAT_TABLE_STRING,
3807
    format_cb_mouse_absolute_y
3808
  },
3809
  { "mouse_all_flag", FORMAT_TABLE_STRING,
3810
    format_cb_mouse_all_flag
3811
  },
3812
  { "mouse_any_flag", FORMAT_TABLE_STRING,
3813
    format_cb_mouse_any_flag
3814
  },
3815
  { "mouse_button_flag", FORMAT_TABLE_STRING,
3816
    format_cb_mouse_button_flag
3817
  },
3818
  { "mouse_hyperlink", FORMAT_TABLE_STRING,
3819
    format_cb_mouse_hyperlink
3820
  },
3821
  { "mouse_line", FORMAT_TABLE_STRING,
3822
    format_cb_mouse_line
3823
  },
3824
  { "mouse_pane", FORMAT_TABLE_STRING,
3825
    format_cb_mouse_pane
3826
  },
3827
  { "mouse_sgr_flag", FORMAT_TABLE_STRING,
3828
    format_cb_mouse_sgr_flag
3829
  },
3830
  { "mouse_standard_flag", FORMAT_TABLE_STRING,
3831
    format_cb_mouse_standard_flag
3832
  },
3833
  { "mouse_status_line", FORMAT_TABLE_STRING,
3834
    format_cb_mouse_status_line
3835
  },
3836
  { "mouse_status_range", FORMAT_TABLE_STRING,
3837
    format_cb_mouse_status_range
3838
  },
3839
  { "mouse_utf8_flag", FORMAT_TABLE_STRING,
3840
    format_cb_mouse_utf8_flag
3841
  },
3842
  { "mouse_word", FORMAT_TABLE_STRING,
3843
    format_cb_mouse_word
3844
  },
3845
  { "mouse_x", FORMAT_TABLE_STRING,
3846
    format_cb_mouse_x
3847
  },
3848
  { "mouse_y", FORMAT_TABLE_STRING,
3849
    format_cb_mouse_y
3850
  },
3851
  { "next_session_id", FORMAT_TABLE_STRING,
3852
    format_cb_next_session_id
3853
  },
3854
  { "origin_flag", FORMAT_TABLE_STRING,
3855
    format_cb_origin_flag
3856
  },
3857
  { "pane_active", FORMAT_TABLE_STRING,
3858
    format_cb_pane_active
3859
  },
3860
  { "pane_at_bottom", FORMAT_TABLE_STRING,
3861
    format_cb_pane_at_bottom
3862
  },
3863
  { "pane_at_left", FORMAT_TABLE_STRING,
3864
    format_cb_pane_at_left
3865
  },
3866
  { "pane_at_right", FORMAT_TABLE_STRING,
3867
    format_cb_pane_at_right
3868
  },
3869
  { "pane_at_top", FORMAT_TABLE_STRING,
3870
    format_cb_pane_at_top
3871
  },
3872
  { "pane_bg", FORMAT_TABLE_STRING,
3873
    format_cb_pane_bg
3874
  },
3875
  { "pane_bottom", FORMAT_TABLE_STRING,
3876
    format_cb_pane_bottom
3877
  },
3878
  { "pane_command_duration", FORMAT_TABLE_STRING,
3879
    format_cb_pane_command_duration
3880
  },
3881
  { "pane_command_end_time", FORMAT_TABLE_TIME,
3882
    format_cb_pane_command_end_time
3883
  },
3884
  { "pane_command_line", FORMAT_TABLE_STRING,
3885
    format_cb_pane_command_line
3886
  },
3887
  { "pane_command_running", FORMAT_TABLE_STRING,
3888
    format_cb_pane_command_running
3889
  },
3890
  { "pane_command_start_time", FORMAT_TABLE_TIME,
3891
    format_cb_pane_command_start_time
3892
  },
3893
  { "pane_command_status", FORMAT_TABLE_STRING,
3894
    format_cb_pane_command_status
3895
  },
3896
  { "pane_current_command", FORMAT_TABLE_STRING,
3897
    format_cb_current_command
3898
  },
3899
  { "pane_current_path", FORMAT_TABLE_STRING,
3900
    format_cb_current_path
3901
  },
3902
  { "pane_dead", FORMAT_TABLE_STRING,
3903
    format_cb_pane_dead
3904
  },
3905
  { "pane_dead_signal", FORMAT_TABLE_STRING,
3906
    format_cb_pane_dead_signal
3907
  },
3908
  { "pane_dead_status", FORMAT_TABLE_STRING,
3909
    format_cb_pane_dead_status
3910
  },
3911
  { "pane_dead_time", FORMAT_TABLE_TIME,
3912
    format_cb_pane_dead_time
3913
  },
3914
  { "pane_fg", FORMAT_TABLE_STRING,
3915
    format_cb_pane_fg
3916
  },
3917
  { "pane_flags", FORMAT_TABLE_STRING,
3918
    format_cb_pane_flags
3919
  },
3920
  { "pane_floating_flag", FORMAT_TABLE_STRING,
3921
    format_cb_pane_floating_flag
3922
  },
3923
  { "pane_format", FORMAT_TABLE_STRING,
3924
    format_cb_pane_format
3925
  },
3926
  { "pane_height", FORMAT_TABLE_STRING,
3927
    format_cb_pane_height
3928
  },
3929
  { "pane_id", FORMAT_TABLE_STRING,
3930
    format_cb_pane_id
3931
  },
3932
  { "pane_in_mode", FORMAT_TABLE_STRING,
3933
    format_cb_pane_in_mode
3934
  },
3935
  { "pane_index", FORMAT_TABLE_STRING,
3936
    format_cb_pane_index
3937
  },
3938
  { "pane_input_off", FORMAT_TABLE_STRING,
3939
    format_cb_pane_input_off
3940
  },
3941
  { "pane_key_mode", FORMAT_TABLE_STRING,
3942
    format_cb_pane_key_mode
3943
  },
3944
  { "pane_last", FORMAT_TABLE_STRING,
3945
    format_cb_pane_last
3946
  },
3947
  { "pane_last_output_time", FORMAT_TABLE_TIME,
3948
    format_cb_pane_last_output_time
3949
  },
3950
  { "pane_last_prompt_time", FORMAT_TABLE_TIME,
3951
    format_cb_pane_last_prompt_time
3952
  },
3953
  { "pane_left", FORMAT_TABLE_STRING,
3954
    format_cb_pane_left
3955
  },
3956
  { "pane_marked", FORMAT_TABLE_STRING,
3957
    format_cb_pane_marked
3958
  },
3959
  { "pane_marked_set", FORMAT_TABLE_STRING,
3960
    format_cb_pane_marked_set
3961
  },
3962
  { "pane_modal_flag", FORMAT_TABLE_STRING,
3963
    format_cb_pane_modal_flag
3964
  },
3965
  { "pane_mode", FORMAT_TABLE_STRING,
3966
    format_cb_pane_mode
3967
  },
3968
  { "pane_output_generation", FORMAT_TABLE_STRING,
3969
    format_cb_pane_output_generation
3970
  },
3971
  { "pane_path", FORMAT_TABLE_STRING,
3972
    format_cb_pane_path
3973
  },
3974
  { "pane_pb_progress", FORMAT_TABLE_STRING,
3975
    format_cb_pane_pb_progress
3976
  },
3977
  { "pane_pb_state", FORMAT_TABLE_STRING,
3978
    format_cb_pane_pb_state
3979
  },
3980
  { "pane_pid", FORMAT_TABLE_STRING,
3981
    format_cb_pane_pid
3982
  },
3983
  { "pane_pipe", FORMAT_TABLE_STRING,
3984
    format_cb_pane_pipe
3985
  },
3986
  { "pane_pipe_pid", FORMAT_TABLE_STRING,
3987
    format_cb_pane_pipe_pid
3988
  },
3989
  { "pane_private_modes", FORMAT_TABLE_STRING,
3990
    format_cb_pane_private_modes
3991
  },
3992
  { "pane_right", FORMAT_TABLE_STRING,
3993
    format_cb_pane_right
3994
  },
3995
  { "pane_search_string", FORMAT_TABLE_STRING,
3996
    format_cb_pane_search_string
3997
  },
3998
  { "pane_start_command", FORMAT_TABLE_STRING,
3999
    format_cb_start_command
4000
  },
4001
  { "pane_start_command_list", FORMAT_TABLE_STRING,
4002
    format_cb_start_command_list
4003
  },
4004
  { "pane_start_path", FORMAT_TABLE_STRING,
4005
    format_cb_start_path
4006
  },
4007
  { "pane_synchronized", FORMAT_TABLE_STRING,
4008
    format_cb_pane_synchronized
4009
  },
4010
  { "pane_tabs", FORMAT_TABLE_STRING,
4011
    format_cb_pane_tabs
4012
  },
4013
  { "pane_title", FORMAT_TABLE_STRING,
4014
    format_cb_pane_title
4015
  },
4016
  { "pane_top", FORMAT_TABLE_STRING,
4017
    format_cb_pane_top
4018
  },
4019
  { "pane_tty", FORMAT_TABLE_STRING,
4020
    format_cb_pane_tty
4021
  },
4022
  { "pane_unseen_changes", FORMAT_TABLE_STRING,
4023
    format_cb_pane_unseen_changes
4024
  },
4025
  { "pane_unzoomed_height", FORMAT_TABLE_STRING,
4026
    format_cb_pane_unzoomed_height
4027
  },
4028
  { "pane_unzoomed_width", FORMAT_TABLE_STRING,
4029
    format_cb_pane_unzoomed_width
4030
  },
4031
  { "pane_width", FORMAT_TABLE_STRING,
4032
    format_cb_pane_width
4033
  },
4034
  { "pane_x", FORMAT_TABLE_STRING,
4035
    format_cb_pane_x
4036
  },
4037
  { "pane_y", FORMAT_TABLE_STRING,
4038
    format_cb_pane_y
4039
  },
4040
  { "pane_z", FORMAT_TABLE_STRING,
4041
    format_cb_pane_z
4042
  },
4043
  { "pane_zoomed_flag", FORMAT_TABLE_STRING,
4044
    format_cb_pane_zoomed_flag
4045
  },
4046
  { "pid", FORMAT_TABLE_STRING,
4047
    format_cb_pid
4048
  },
4049
  { "scroll_region_lower", FORMAT_TABLE_STRING,
4050
    format_cb_scroll_region_lower
4051
  },
4052
  { "scroll_region_upper", FORMAT_TABLE_STRING,
4053
    format_cb_scroll_region_upper
4054
  },
4055
  { "server_sessions", FORMAT_TABLE_STRING,
4056
    format_cb_server_sessions
4057
  },
4058
  { "session_active", FORMAT_TABLE_STRING,
4059
    format_cb_session_active
4060
  },
4061
  { "session_activity", FORMAT_TABLE_TIME,
4062
    format_cb_session_activity
4063
  },
4064
  { "session_activity_flag", FORMAT_TABLE_STRING,
4065
    format_cb_session_activity_flag
4066
  },
4067
  { "session_alert", FORMAT_TABLE_STRING,
4068
    format_cb_session_alert
4069
  },
4070
  { "session_alerts", FORMAT_TABLE_STRING,
4071
    format_cb_session_alerts
4072
  },
4073
  { "session_attached", FORMAT_TABLE_STRING,
4074
    format_cb_session_attached
4075
  },
4076
  { "session_attached_list", FORMAT_TABLE_STRING,
4077
    format_cb_session_attached_list
4078
  },
4079
  { "session_bell_flag", FORMAT_TABLE_STRING,
4080
    format_cb_session_bell_flag
4081
  },
4082
  { "session_created", FORMAT_TABLE_TIME,
4083
    format_cb_session_created
4084
  },
4085
  { "session_format", FORMAT_TABLE_STRING,
4086
    format_cb_session_format
4087
  },
4088
  { "session_group", FORMAT_TABLE_STRING,
4089
    format_cb_session_group
4090
  },
4091
  { "session_group_attached", FORMAT_TABLE_STRING,
4092
    format_cb_session_group_attached
4093
  },
4094
  { "session_group_attached_list", FORMAT_TABLE_STRING,
4095
    format_cb_session_group_attached_list
4096
  },
4097
  { "session_group_list", FORMAT_TABLE_STRING,
4098
    format_cb_session_group_list
4099
  },
4100
  { "session_group_many_attached", FORMAT_TABLE_STRING,
4101
    format_cb_session_group_many_attached
4102
  },
4103
  { "session_group_size", FORMAT_TABLE_STRING,
4104
    format_cb_session_group_size
4105
  },
4106
  { "session_grouped", FORMAT_TABLE_STRING,
4107
    format_cb_session_grouped
4108
  },
4109
  { "session_id", FORMAT_TABLE_STRING,
4110
    format_cb_session_id
4111
  },
4112
  { "session_last_attached", FORMAT_TABLE_TIME,
4113
    format_cb_session_last_attached
4114
  },
4115
  { "session_many_attached", FORMAT_TABLE_STRING,
4116
    format_cb_session_many_attached
4117
  },
4118
  { "session_marked", FORMAT_TABLE_STRING,
4119
    format_cb_session_marked,
4120
  },
4121
  { "session_name", FORMAT_TABLE_STRING,
4122
    format_cb_session_name
4123
  },
4124
  { "session_path", FORMAT_TABLE_STRING,
4125
    format_cb_session_path
4126
  },
4127
  { "session_silence_flag", FORMAT_TABLE_STRING,
4128
    format_cb_session_silence_flag
4129
  },
4130
  { "session_stack", FORMAT_TABLE_STRING,
4131
    format_cb_session_stack
4132
  },
4133
  { "session_windows", FORMAT_TABLE_STRING,
4134
    format_cb_session_windows
4135
  },
4136
  { "sixel_support", FORMAT_TABLE_STRING,
4137
    format_cb_image_support
4138
  },
4139
  { "socket_path", FORMAT_TABLE_STRING,
4140
    format_cb_socket_path
4141
  },
4142
  { "start_time", FORMAT_TABLE_TIME,
4143
    format_cb_start_time
4144
  },
4145
  { "synchronized_output_flag", FORMAT_TABLE_STRING,
4146
    format_cb_synchronized_output_flag
4147
  },
4148
  { "tree_mode_format", FORMAT_TABLE_STRING,
4149
    format_cb_tree_mode_format
4150
  },
4151
  { "uid", FORMAT_TABLE_STRING,
4152
    format_cb_uid
4153
  },
4154
  { "user", FORMAT_TABLE_STRING,
4155
    format_cb_user
4156
  },
4157
  { "version", FORMAT_TABLE_STRING,
4158
    format_cb_version
4159
  },
4160
  { "window_active", FORMAT_TABLE_STRING,
4161
    format_cb_window_active
4162
  },
4163
  { "window_active_clients", FORMAT_TABLE_STRING,
4164
    format_cb_window_active_clients
4165
  },
4166
  { "window_active_clients_list", FORMAT_TABLE_STRING,
4167
    format_cb_window_active_clients_list
4168
  },
4169
  { "window_active_sessions", FORMAT_TABLE_STRING,
4170
    format_cb_window_active_sessions
4171
  },
4172
  { "window_active_sessions_list", FORMAT_TABLE_STRING,
4173
    format_cb_window_active_sessions_list
4174
  },
4175
  { "window_activity", FORMAT_TABLE_TIME,
4176
    format_cb_window_activity
4177
  },
4178
  { "window_activity_flag", FORMAT_TABLE_STRING,
4179
    format_cb_window_activity_flag
4180
  },
4181
  { "window_bell_flag", FORMAT_TABLE_STRING,
4182
    format_cb_window_bell_flag
4183
  },
4184
  { "window_bigger", FORMAT_TABLE_STRING,
4185
    format_cb_window_bigger
4186
  },
4187
  { "window_cell_height", FORMAT_TABLE_STRING,
4188
    format_cb_window_cell_height
4189
  },
4190
  { "window_cell_width", FORMAT_TABLE_STRING,
4191
    format_cb_window_cell_width
4192
  },
4193
  { "window_end_flag", FORMAT_TABLE_STRING,
4194
    format_cb_window_end_flag
4195
  },
4196
  { "window_flags", FORMAT_TABLE_STRING,
4197
    format_cb_window_flags
4198
  },
4199
  { "window_format", FORMAT_TABLE_STRING,
4200
    format_cb_window_format
4201
  },
4202
  { "window_height", FORMAT_TABLE_STRING,
4203
    format_cb_window_height
4204
  },
4205
  { "window_id", FORMAT_TABLE_STRING,
4206
    format_cb_window_id
4207
  },
4208
  { "window_index", FORMAT_TABLE_STRING,
4209
    format_cb_window_index
4210
  },
4211
  { "window_last_flag", FORMAT_TABLE_STRING,
4212
    format_cb_window_last_flag
4213
  },
4214
  { "window_layout", FORMAT_TABLE_STRING,
4215
    format_cb_window_layout
4216
  },
4217
  { "window_linked", FORMAT_TABLE_STRING,
4218
    format_cb_window_linked
4219
  },
4220
  { "window_linked_sessions", FORMAT_TABLE_STRING,
4221
    format_cb_window_linked_sessions
4222
  },
4223
  { "window_linked_sessions_list", FORMAT_TABLE_STRING,
4224
    format_cb_window_linked_sessions_list
4225
  },
4226
  { "window_manual_height", FORMAT_TABLE_STRING,
4227
    format_cb_window_manual_height
4228
  },
4229
  { "window_manual_width", FORMAT_TABLE_STRING,
4230
    format_cb_window_manual_width
4231
  },
4232
  { "window_marked_flag", FORMAT_TABLE_STRING,
4233
    format_cb_window_marked_flag
4234
  },
4235
  { "window_modal_pane", FORMAT_TABLE_STRING,
4236
    format_cb_window_modal_pane
4237
  },
4238
  { "window_name", FORMAT_TABLE_STRING,
4239
    format_cb_window_name
4240
  },
4241
  { "window_offset_x", FORMAT_TABLE_STRING,
4242
    format_cb_window_offset_x
4243
  },
4244
  { "window_offset_y", FORMAT_TABLE_STRING,
4245
    format_cb_window_offset_y
4246
  },
4247
  { "window_panes", FORMAT_TABLE_STRING,
4248
    format_cb_window_panes
4249
  },
4250
  { "window_raw_flags", FORMAT_TABLE_STRING,
4251
    format_cb_window_raw_flags
4252
  },
4253
  { "window_silence_flag", FORMAT_TABLE_STRING,
4254
    format_cb_window_silence_flag
4255
  },
4256
  { "window_stack_index", FORMAT_TABLE_STRING,
4257
    format_cb_window_stack_index
4258
  },
4259
  { "window_start_flag", FORMAT_TABLE_STRING,
4260
    format_cb_window_start_flag
4261
  },
4262
  { "window_visible_layout", FORMAT_TABLE_STRING,
4263
    format_cb_window_visible_layout
4264
  },
4265
  { "window_width", FORMAT_TABLE_STRING,
4266
    format_cb_window_width
4267
  },
4268
  { "window_zoomed_flag", FORMAT_TABLE_STRING,
4269
    format_cb_window_zoomed_flag
4270
  },
4271
  { "wrap_flag", FORMAT_TABLE_STRING,
4272
    format_cb_wrap_flag
4273
  }
4274
};
4275
4276
/* Compare format table entries. */
4277
static int
4278
format_table_compare(const void *key0, const void *entry0)
4279
15.1M
{
4280
15.1M
  const char      *key = key0;
4281
15.1M
  const struct format_table_entry *entry = entry0;
4282
4283
15.1M
  return (strcmp(key, entry->key));
4284
15.1M
}
4285
4286
/* Get a format callback. */
4287
static const struct format_table_entry *
4288
format_table_get(const char *key)
4289
1.94M
{
4290
1.94M
  return (bsearch(key, format_table, nitems(format_table),
4291
1.94M
      sizeof *format_table, format_table_compare));
4292
1.94M
}
4293
4294
/* Merge one format tree into another. */
4295
void
4296
format_merge(struct format_tree *ft, struct format_tree *from)
4297
0
{
4298
0
  struct format_entry *fe;
4299
4300
0
  RB_FOREACH(fe, format_entry_tree, &from->tree) {
4301
0
    if (fe->value != NULL)
4302
0
      format_add(ft, fe->key, "%s", fe->value);
4303
0
  }
4304
0
}
4305
4306
/* Get format pane. */
4307
struct window_pane *
4308
format_get_pane(struct format_tree *ft)
4309
0
{
4310
0
  return (ft->wp);
4311
0
}
4312
4313
/* Add item bits to tree. */
4314
static void
4315
format_create_add_item(struct format_tree *ft, struct cmdq_item *item)
4316
0
{
4317
0
  struct key_event  *event = cmdq_get_event(item);
4318
0
  struct mouse_event  *m = &event->m;
4319
0
  struct client   *c = cmdq_get_client(item);
4320
4321
0
  if (c != NULL && (c->flags & CLIENT_READONLY))
4322
0
    ft->flags |= FORMAT_NOJOBS;
4323
0
  cmdq_merge_formats(item, ft);
4324
0
  memcpy(&ft->m, m, sizeof ft->m);
4325
0
}
4326
4327
/* Create a new tree. */
4328
struct format_tree *
4329
format_create(struct client *c, struct cmdq_item *item, int tag, int flags)
4330
1.84M
{
4331
1.84M
  struct format_tree  *ft;
4332
4333
1.84M
  ft = xcalloc(1, sizeof *ft);
4334
1.84M
  RB_INIT(&ft->tree);
4335
4336
1.84M
  if (c != NULL) {
4337
0
    ft->client = c;
4338
0
    ft->client->references++;
4339
0
  }
4340
1.84M
  ft->item = item;
4341
4342
1.84M
  ft->tag = tag;
4343
1.84M
  ft->flags = flags;
4344
4345
1.84M
  if (item != NULL)
4346
0
    format_create_add_item(ft, item);
4347
4348
1.84M
  return (ft);
4349
1.84M
}
4350
4351
/* Free a tree. */
4352
void
4353
format_free(struct format_tree *ft)
4354
1.84M
{
4355
1.84M
  struct format_entry *fe, *fe1;
4356
4357
22.1M
  RB_FOREACH_SAFE(fe, format_entry_tree, &ft->tree, fe1) {
4358
22.1M
    RB_REMOVE(format_entry_tree, &ft->tree, fe);
4359
22.1M
    free(fe->value);
4360
22.1M
    free(fe->key);
4361
22.1M
    free(fe);
4362
22.1M
  }
4363
4364
1.84M
  if (ft->client != NULL)
4365
0
    server_client_unref(ft->client);
4366
1.84M
  free(ft);
4367
1.84M
}
4368
4369
/* Log each format. */
4370
static void
4371
format_log_debug_cb(const char *key, const char *value, void *arg)
4372
0
{
4373
0
  const char  *prefix = arg;
4374
4375
0
  log_debug("%s: %s=%s", prefix, key, value);
4376
0
}
4377
4378
/* Log a format tree. */
4379
void
4380
format_log_debug(struct format_tree *ft, const char *prefix)
4381
0
{
4382
0
  if (log_get_level() == 0)
4383
0
    return;
4384
0
  format_each(ft, format_log_debug_cb, (void *)prefix);
4385
0
}
4386
4387
/* Walk each format. */
4388
void
4389
format_each(struct format_tree *ft, void (*cb)(const char *, const char *,
4390
    void *), void *arg)
4391
0
{
4392
0
  const struct format_table_entry *fte;
4393
0
  struct format_entry   *fe;
4394
0
  u_int        i;
4395
0
  char         s[64];
4396
0
  void        *value;
4397
0
  struct timeval      *tv;
4398
4399
0
  for (i = 0; i < nitems(format_table); i++) {
4400
0
    fte = &format_table[i];
4401
4402
0
    value = fte->cb(ft);
4403
0
    if (value == NULL)
4404
0
      continue;
4405
0
    if (fte->type == FORMAT_TABLE_TIME) {
4406
0
      tv = value;
4407
0
      xsnprintf(s, sizeof s, "%lld", (long long)tv->tv_sec);
4408
0
      cb(fte->key, s, arg);
4409
0
    } else {
4410
0
      cb(fte->key, value, arg);
4411
0
      free(value);
4412
0
    }
4413
0
  }
4414
0
  RB_FOREACH(fe, format_entry_tree, &ft->tree) {
4415
0
    if (fe->time != 0) {
4416
0
      xsnprintf(s, sizeof s, "%lld", (long long)fe->time);
4417
0
      cb(fe->key, s, arg);
4418
0
    } else {
4419
0
      if (fe->value == NULL && fe->cb != NULL) {
4420
0
        fe->value = fe->cb(ft);
4421
0
        if (fe->value == NULL)
4422
0
          fe->value = xstrdup("");
4423
0
      }
4424
0
      cb(fe->key, fe->value, arg);
4425
0
    }
4426
0
  }
4427
0
}
4428
4429
/* Add a key-value pair. */
4430
void
4431
format_add(struct format_tree *ft, const char *key, const char *fmt, ...)
4432
22.1M
{
4433
22.1M
  struct format_entry *fe;
4434
22.1M
  struct format_entry *fe_now;
4435
22.1M
  va_list      ap;
4436
4437
22.1M
  fe = xmalloc(sizeof *fe);
4438
22.1M
  fe->key = xstrdup(key);
4439
4440
22.1M
  fe_now = RB_INSERT(format_entry_tree, &ft->tree, fe);
4441
22.1M
  if (fe_now != NULL) {
4442
0
    free(fe->key);
4443
0
    free(fe);
4444
0
    free(fe_now->value);
4445
0
    fe = fe_now;
4446
0
  }
4447
4448
22.1M
  fe->cb = NULL;
4449
22.1M
  fe->time = 0;
4450
4451
22.1M
  va_start(ap, fmt);
4452
22.1M
  xvasprintf(&fe->value, fmt, ap);
4453
22.1M
  va_end(ap);
4454
22.1M
}
4455
4456
/* Add a key and time. */
4457
void
4458
format_add_tv(struct format_tree *ft, const char *key, struct timeval *tv)
4459
0
{
4460
0
  struct format_entry *fe, *fe_now;
4461
4462
0
  fe = xmalloc(sizeof *fe);
4463
0
  fe->key = xstrdup(key);
4464
4465
0
  fe_now = RB_INSERT(format_entry_tree, &ft->tree, fe);
4466
0
  if (fe_now != NULL) {
4467
0
    free(fe->key);
4468
0
    free(fe);
4469
0
    free(fe_now->value);
4470
0
    fe = fe_now;
4471
0
  }
4472
4473
0
  fe->cb = NULL;
4474
0
  fe->time = tv->tv_sec;
4475
4476
0
  fe->value = NULL;
4477
0
}
4478
4479
/* Add a key and function. */
4480
void
4481
format_add_cb(struct format_tree *ft, const char *key, format_cb cb)
4482
0
{
4483
0
  struct format_entry *fe;
4484
0
  struct format_entry *fe_now;
4485
4486
0
  fe = xmalloc(sizeof *fe);
4487
0
  fe->key = xstrdup(key);
4488
4489
0
  fe_now = RB_INSERT(format_entry_tree, &ft->tree, fe);
4490
0
  if (fe_now != NULL) {
4491
0
    free(fe->key);
4492
0
    free(fe);
4493
0
    free(fe_now->value);
4494
0
    fe = fe_now;
4495
0
  }
4496
4497
0
  fe->cb = cb;
4498
0
  fe->time = 0;
4499
4500
0
  fe->value = NULL;
4501
0
}
4502
4503
/* Quote shell special characters in string. */
4504
static char *
4505
format_quote_shell(const char *s)
4506
545
{
4507
545
  const char  *cp;
4508
545
  char    *out, *at;
4509
4510
545
  at = out = xmalloc(strlen(s) * 2 + 1);
4511
4.75k
  for (cp = s; *cp != '\0'; cp++) {
4512
4.21k
    if (strchr("|&;<>(){}$`\\\"'*?[# =%\n\t", *cp) != NULL)
4513
780
      *at++ = '\\';
4514
4.21k
    *at++ = *cp;
4515
4.21k
  }
4516
545
  *at = '\0';
4517
545
  return (out);
4518
545
}
4519
4520
/* Quote string with POSIX shell single quotes. */
4521
static char *
4522
format_quote_shell_single(const char *s)
4523
828
{
4524
828
  const char  *cp;
4525
828
  char    *out, *at;
4526
4527
828
  at = out = xmalloc(strlen(s) * 4 + 3);
4528
828
  *at++ = '\'';
4529
11.6k
  for (cp = s; *cp != '\0'; cp++) {
4530
10.7k
    if (*cp == '\'') {
4531
194
      *at++ = '\'';
4532
194
      *at++ = '\\';
4533
194
      *at++ = '\'';
4534
194
      *at++ = '\'';
4535
194
    } else
4536
10.5k
      *at++ = *cp;
4537
10.7k
  }
4538
828
  *at++ = '\'';
4539
828
  *at = '\0';
4540
828
  return (out);
4541
828
}
4542
4543
/* Quote #s in string. */
4544
static char *
4545
format_quote_style(const char *s)
4546
1.37k
{
4547
1.37k
  const char  *cp;
4548
1.37k
  char    *out, *at;
4549
4550
1.37k
  at = out = xmalloc(strlen(s) * 2 + 1);
4551
2.63M
  for (cp = s; *cp != '\0'; cp++) {
4552
2.63M
    if (*cp == '#')
4553
142k
      *at++ = '#';
4554
2.63M
    *at++ = *cp;
4555
2.63M
  }
4556
1.37k
  *at = '\0';
4557
1.37k
  return (out);
4558
1.37k
}
4559
4560
/* Make a prettier time. */
4561
char *
4562
format_pretty_time(time_t t, int seconds)
4563
2.10k
{
4564
2.10k
  struct tm now_tm, tm;
4565
2.10k
  time_t    now, age;
4566
2.10k
  char    s[9];
4567
4568
2.10k
  time(&now);
4569
2.10k
  if (now < t)
4570
0
    now = t;
4571
2.10k
  age = now - t;
4572
4573
2.10k
  if (localtime_r(&now, &now_tm) == NULL || localtime_r(&t, &tm) == NULL)
4574
0
    return (xstrdup(""));
4575
4576
  /* Last 24 hours. */
4577
2.10k
  if (age < 24 * 3600) {
4578
0
    if (seconds)
4579
0
      strftime(s, sizeof s, "%H:%M:%S", &tm);
4580
0
    else
4581
0
      strftime(s, sizeof s, "%H:%M", &tm);
4582
0
    return (xstrdup(s));
4583
0
  }
4584
4585
  /* This month or last 28 days. */
4586
2.10k
  if ((tm.tm_year == now_tm.tm_year && tm.tm_mon == now_tm.tm_mon) ||
4587
2.10k
      age < 28 * 24 * 3600) {
4588
0
    strftime(s, sizeof s, "%a%d", &tm);
4589
0
    return (xstrdup(s));
4590
0
  }
4591
4592
  /* Last 12 months. */
4593
2.10k
  if ((tm.tm_year == now_tm.tm_year && tm.tm_mon < now_tm.tm_mon) ||
4594
2.10k
      (tm.tm_year == now_tm.tm_year - 1 && tm.tm_mon > now_tm.tm_mon)) {
4595
0
    strftime(s, sizeof s, "%d%b", &tm);
4596
0
    return (xstrdup(s));
4597
0
  }
4598
4599
  /* Older than that. */
4600
2.10k
  strftime(s, sizeof s, "%h%y", &tm);
4601
2.10k
  return (xstrdup(s));
4602
2.10k
}
4603
4604
/* Make a relative time. */
4605
static char *
4606
format_relative_time(time_t t)
4607
226
{
4608
226
  time_t  now, age;
4609
226
  u_int d, h, m, s;
4610
226
  char  out[32];
4611
4612
226
  time(&now);
4613
226
  if (t > now)
4614
0
    return (NULL);
4615
226
  if (t == now)
4616
0
    return (xstrdup("0s"));
4617
226
  age = now - t;
4618
4619
226
  d = age / 86400;
4620
226
  h = (age % 86400) / 3600;
4621
226
  m = (age % 3600) / 60;
4622
226
  s = age % 60;
4623
4624
226
  if (d != 0) {
4625
226
    if (h != 0)
4626
226
      xsnprintf(out, sizeof out, "%ud%uh", d, h);
4627
0
    else
4628
0
      xsnprintf(out, sizeof out, "%ud", d);
4629
226
  } else if (h != 0) {
4630
0
    if (m != 0)
4631
0
      xsnprintf(out, sizeof out, "%uh%um", h, m);
4632
0
    else
4633
0
      xsnprintf(out, sizeof out, "%uh", h);
4634
0
  } else if (m != 0) {
4635
0
    if (s != 0)
4636
0
      xsnprintf(out, sizeof out, "%um%us", m, s);
4637
0
    else
4638
0
      xsnprintf(out, sizeof out, "%um", m);
4639
0
  } else
4640
0
    xsnprintf(out, sizeof out, "%us", s);
4641
226
  return (xstrdup(out));
4642
226
}
4643
4644
/* Make a time difference in seconds. */
4645
static char *
4646
format_time_difference(time_t t)
4647
199
{
4648
199
  time_t   now = time(NULL);
4649
199
  char  *out;
4650
4651
199
  xasprintf(&out, "%ld", (long)now - (long)t);
4652
199
  return (out);
4653
199
}
4654
4655
/* Find a format entry. */
4656
static char *
4657
format_find(struct format_tree *ft, const char *key, uint64_t modifiers,
4658
    const char *time_format)
4659
1.96M
{
4660
1.96M
  const struct format_table_entry *fte;
4661
1.96M
  void        *value;
4662
1.96M
  struct format_entry   *fe, fe_find;
4663
1.96M
  struct environ_entry    *envent;
4664
1.96M
  struct options_entry    *o;
4665
1.96M
  char        *found = NULL, *saved, s[512];
4666
1.96M
  char        *array_key = NULL;
4667
1.96M
  const char      *errstr;
4668
1.96M
  time_t         t = 0;
4669
1.96M
  struct tm      tm;
4670
4671
1.96M
  o = options_parse_get(global_options, key, &array_key, 0);
4672
1.96M
  if (o == NULL && ft->wp != NULL)
4673
0
    o = options_parse_get(ft->wp->options, key, &array_key, 0);
4674
1.96M
  if (o == NULL && ft->w != NULL)
4675
0
    o = options_parse_get(ft->w->options, key, &array_key, 0);
4676
1.96M
  if (o == NULL)
4677
1.96M
    o = options_parse_get(global_w_options, key, &array_key, 0);
4678
1.96M
  if (o == NULL && ft->s != NULL)
4679
0
    o = options_parse_get(ft->s->options, key, &array_key, 0);
4680
1.96M
  if (o == NULL)
4681
1.95M
    o = options_parse_get(global_s_options, key, &array_key, 0);
4682
1.96M
  if (o != NULL) {
4683
13.0k
    found = options_to_string(o, array_key, 1);
4684
13.0k
    free(array_key);
4685
13.0k
    goto found;
4686
13.0k
  }
4687
4688
1.94M
  fte = format_table_get(key);
4689
1.94M
  if (fte != NULL) {
4690
1.32M
    value = fte->cb(ft);
4691
1.32M
    if (fte->type == FORMAT_TABLE_TIME && value != NULL)
4692
210
      t = ((struct timeval *)value)->tv_sec;
4693
1.32M
    else
4694
1.32M
      found = value;
4695
1.32M
    goto found;
4696
1.32M
  }
4697
621k
  fe_find.key = (char *)key;
4698
621k
  fe = RB_FIND(format_entry_tree, &ft->tree, &fe_find);
4699
621k
  if (fe != NULL) {
4700
111k
    if (fe->time != 0) {
4701
0
      t = fe->time;
4702
0
      goto found;
4703
0
    }
4704
111k
    if (fe->value == NULL && fe->cb != NULL) {
4705
0
      fe->value = fe->cb(ft);
4706
0
      if (fe->value == NULL)
4707
0
        fe->value = xstrdup("");
4708
0
    }
4709
111k
    found = xstrdup(fe->value);
4710
111k
    goto found;
4711
111k
  }
4712
4713
509k
  if (~modifiers & FORMAT_TIMESTRING) {
4714
478k
    envent = NULL;
4715
478k
    if (ft->s != NULL)
4716
0
      envent = environ_find(ft->s->environ, key);
4717
478k
    if (envent == NULL)
4718
478k
      envent = environ_find(global_environ, key);
4719
478k
    if (envent != NULL && envent->value != NULL) {
4720
0
      found = xstrdup(envent->value);
4721
0
      goto found;
4722
0
    }
4723
478k
  }
4724
4725
509k
  return (NULL);
4726
4727
1.45M
found:
4728
1.45M
  if (modifiers & FORMAT_TIMESTRING) {
4729
4.08k
    if (t == 0 && found != NULL) {
4730
3.38k
      t = strtonum(found, 0, INT64_MAX, &errstr);
4731
3.38k
      if (errstr != NULL)
4732
246
        t = 0;
4733
3.38k
      free(found);
4734
3.38k
    }
4735
4.08k
    if (t == 0)
4736
1.08k
      return (NULL);
4737
3.00k
    if (modifiers & FORMAT_RELATIVE)
4738
226
      found = format_relative_time(t);
4739
2.77k
    else if (modifiers & FORMAT_DIFFERENCE)
4740
199
      found = format_time_difference(t);
4741
2.57k
    else if (modifiers & FORMAT_PRETTY)
4742
2.10k
      found = format_pretty_time(t, 0);
4743
477
    else {
4744
477
      if (time_format != NULL) {
4745
202
        if (localtime_r(&t, &tm) == NULL)
4746
0
          return (NULL);
4747
202
        format_strftime(s, sizeof s, time_format, &tm);
4748
275
      } else {
4749
275
        if (ctime_r(&t, s) == NULL)
4750
0
          return (NULL);
4751
275
        s[strcspn(s, "\n")] = '\0';
4752
275
      }
4753
477
      found = xstrdup(s);
4754
477
    }
4755
3.00k
    return (found);
4756
3.00k
  }
4757
4758
1.44M
  if (t != 0)
4759
0
    xasprintf(&found, "%lld", (long long)t);
4760
1.44M
  else if (found == NULL)
4761
1.28M
    return (NULL);
4762
166k
  if (modifiers & FORMAT_BASENAME) {
4763
194
    saved = found;
4764
194
    found = xstrdup(basename(saved));
4765
194
    free(saved);
4766
194
  }
4767
166k
  if (modifiers & FORMAT_DIRNAME) {
4768
214
    saved = found;
4769
214
    found = xstrdup(dirname(saved));
4770
214
    free(saved);
4771
214
  }
4772
166k
  if (modifiers & FORMAT_QUOTE_SHELL) {
4773
545
    saved = found;
4774
545
    found = format_quote_shell(saved);
4775
545
    free(saved);
4776
545
  }
4777
166k
  if (modifiers & FORMAT_QUOTE_SHELL_SQ) {
4778
828
    saved = found;
4779
828
    found = format_quote_shell_single(saved);
4780
828
    free(saved);
4781
828
  }
4782
166k
  if (modifiers & FORMAT_QUOTE_STYLE) {
4783
1.37k
    saved = found;
4784
1.37k
    found = format_quote_style(saved);
4785
1.37k
    free(saved);
4786
1.37k
  }
4787
166k
  if (modifiers & FORMAT_QUOTE_ARGUMENTS) {
4788
1.50k
    saved = found;
4789
1.50k
    found = args_escape(saved);
4790
1.50k
    free(saved);
4791
1.50k
  }
4792
166k
  return (found);
4793
1.44M
}
4794
4795
/* Check if format has not taken too long. */
4796
static int
4797
format_check_time(struct format_expand_state *es, u_int *check)
4798
485M
{
4799
485M
  uint64_t t;
4800
4801
485M
  if (check != NULL && ++*check % FORMAT_TIME_LOOP_CHECK != 0)
4802
475M
    return (1);
4803
4804
9.55M
  t = get_timer();
4805
9.55M
  if (t - es->start_time < FORMAT_TIME_LIMIT)
4806
7.34M
    return (1);
4807
2.20M
  t -= es->start_time;
4808
4809
2.20M
  format_log(es, "reached time limit (%llu)", (unsigned long long)t);
4810
2.20M
  return (0);
4811
9.55M
}
4812
4813
/* Unescape escaped characters. */
4814
static char *
4815
format_unescape(struct format_expand_state *es, const char *s, size_t n)
4816
853k
{
4817
853k
  const char  *end = s + n;
4818
853k
  char    *out, *cp;
4819
853k
  int    brackets = 0;
4820
853k
  u_int    check = 0;
4821
4822
853k
  cp = out = xmalloc(n + 1);
4823
17.9M
  for (; s != end; s++) {
4824
17.1M
    if (!format_check_time(es, &check)) {
4825
0
      free(out);
4826
0
      return (xstrdup(""));
4827
0
    }
4828
17.1M
    if (*s == '#' && s + 1 != end && s[1] == '{')
4829
502k
      brackets++;
4830
17.1M
    if (brackets == 0 &&
4831
9.94M
        *s == '#' &&
4832
327k
        s + 1 != end &&
4833
317k
        strchr(",#{}:", s[1]) != NULL) {
4834
23.1k
      *cp++ = *++s;
4835
23.1k
      continue;
4836
23.1k
    }
4837
17.1M
    if (*s == '}')
4838
515k
      brackets--;
4839
17.1M
    *cp++ = *s;
4840
17.1M
  }
4841
853k
  *cp = '\0';
4842
853k
  return (out);
4843
853k
}
4844
4845
/* Remove escaped characters. */
4846
static char *
4847
format_strip(struct format_expand_state *es, const char *s)
4848
1.31k
{
4849
1.31k
  char  *out, *cp;
4850
1.31k
  int  brackets = 0;
4851
1.31k
  u_int  check = 0;
4852
4853
1.31k
  cp = out = xmalloc(strlen(s) + 1);
4854
21.7M
  for (; *s != '\0'; s++) {
4855
21.7M
    if (!format_check_time(es, &check)) {
4856
0
      free(out);
4857
0
      return (xstrdup(""));
4858
0
    }
4859
21.7M
    if (*s == '#' && s[1] == '{')
4860
9.67k
      brackets++;
4861
21.7M
    if (*s == '#' && strchr(",#{}:", s[1]) != NULL) {
4862
35.6k
      if (brackets != 0)
4863
21.2k
        *cp++ = *s;
4864
35.6k
      continue;
4865
35.6k
    }
4866
21.7M
    if (*s == '}')
4867
1.11M
      brackets--;
4868
21.7M
    *cp++ = *s;
4869
21.7M
  }
4870
1.31k
  *cp = '\0';
4871
1.31k
  return (out);
4872
1.31k
}
4873
4874
/* Skip until end. */
4875
static const char *
4876
format_skip1(struct format_expand_state *es, const char *s, const char *end)
4877
6.50M
{
4878
6.50M
  int brackets = 0;
4879
6.50M
  u_int check = 0;
4880
4881
6.50M
  if (es != NULL && !format_check_time(es, NULL))
4882
2.14M
    return (NULL);
4883
4884
803M
  for (; *s != '\0'; s++) {
4885
802M
    if (es != NULL && !format_check_time(es, &check))
4886
14
      return (NULL);
4887
802M
    if (*s == '#' && s[1] == '{')
4888
6.15M
      brackets++;
4889
802M
    if (*s == '#' &&
4890
72.3M
        s[1] != '\0' &&
4891
72.3M
        strchr(",#{}:", s[1]) != NULL) {
4892
31.9M
      s++;
4893
31.9M
      continue;
4894
31.9M
    }
4895
770M
    if (*s == '}')
4896
177M
      brackets--;
4897
770M
    if (strchr(end, *s) != NULL && brackets == 0)
4898
3.61M
      break;
4899
770M
  }
4900
4.35M
  if (*s == '\0')
4901
739k
    return (NULL);
4902
3.61M
  return (s);
4903
4.35M
}
4904
4905
/* Skip until end. */
4906
const char *
4907
format_skip(const char *s, const char *end)
4908
462k
{
4909
462k
    return (format_skip1(NULL, s, end));
4910
462k
}
4911
4912
/* Return left and right alternatives separated by commas. */
4913
static int
4914
format_choose(struct format_expand_state *es, const char *s, char **left,
4915
    char **right, int expand)
4916
442k
{
4917
442k
  const char  *cp;
4918
442k
  char    *left0, *right0;
4919
4920
442k
  cp = format_skip1(es, s, ",");
4921
442k
  if (cp == NULL)
4922
94.7k
    return (-1);
4923
347k
  left0 = xstrndup(s, cp - s);
4924
347k
  right0 = xstrdup(cp + 1);
4925
4926
347k
  if (expand) {
4927
347k
    *left = format_expand1(es, left0);
4928
347k
    free(left0);
4929
347k
    *right = format_expand1(es, right0);
4930
347k
    free(right0);
4931
347k
  } else {
4932
355
    *left = left0;
4933
355
    *right = right0;
4934
355
  }
4935
347k
  return (0);
4936
442k
}
4937
4938
/* Is this true? */
4939
int
4940
format_true(const char *s)
4941
65.7k
{
4942
65.7k
  if (s != NULL && *s != '\0' && (s[0] != '0' || s[1] != '\0'))
4943
46.2k
    return (1);
4944
19.4k
  return (0);
4945
65.7k
}
4946
4947
/* Check if modifier end. */
4948
static int
4949
format_is_end(char c)
4950
3.61M
{
4951
3.61M
  return (c == ';' || c == ':');
4952
3.61M
}
4953
4954
/* Add to modifier list. */
4955
static void
4956
format_add_modifier(struct format_modifier **list, u_int *count,
4957
    const char *c, size_t n, char **argv, int argc)
4958
1.15M
{
4959
1.15M
  struct format_modifier *fm;
4960
4961
1.15M
  *list = xreallocarray(*list, (*count) + 1, sizeof **list);
4962
1.15M
  fm = &(*list)[(*count)++];
4963
4964
1.15M
  memcpy(fm->modifier, c, n);
4965
1.15M
  fm->modifier[n] = '\0';
4966
1.15M
  fm->size = n;
4967
4968
1.15M
  fm->argv = argv;
4969
1.15M
  fm->argc = argc;
4970
1.15M
}
4971
4972
/* Free modifier list. */
4973
static void
4974
format_free_modifiers(struct format_modifier *list, u_int count)
4975
5.21M
{
4976
5.21M
  u_int i;
4977
4978
6.36M
  for (i = 0; i < count; i++)
4979
1.15M
    cmd_free_argv(list[i].argc, list[i].argv);
4980
5.21M
  free(list);
4981
5.21M
}
4982
4983
/* Build modifier list. */
4984
static struct format_modifier *
4985
format_build_modifiers(struct format_expand_state *es, const char **s,
4986
    u_int *count)
4987
3.04M
{
4988
3.04M
  const char    *cp = *s, *end;
4989
3.04M
  struct format_modifier  *list = NULL;
4990
3.04M
  char       c, last[] = "X;:", **argv, *value;
4991
3.04M
  int      argc;
4992
4993
  /*
4994
   * Modifiers are a ; separated list of the forms:
4995
   *  l,m,C,a,b,c,d,I,n,t,w,q,E,T,S,W,P,O,V,R,A,<,>
4996
   *  =a
4997
   *  =/a
4998
   *  =/a/
4999
   *  s/a/b/
5000
   *  s/a/b
5001
   *  ||,&&,!=,==,<=,>=
5002
   */
5003
5004
3.04M
  *count = 0;
5005
5006
4.19M
  while (*cp != '\0' && *cp != ':') {
5007
    /* Skip any separator character. */
5008
3.27M
    if (*cp == ';')
5009
172k
      cp++;
5010
3.27M
    if (*cp == '\0')
5011
106k
      break;
5012
5013
    /* Check single character modifiers with no arguments. */
5014
3.16M
    if (strchr("labdnwETSWPOVL!<>A", cp[0]) != NULL &&
5015
391k
        format_is_end(cp[1])) {
5016
61.3k
      format_add_modifier(&list, count, cp, 1, NULL, 0);
5017
61.3k
      cp++;
5018
61.3k
      continue;
5019
61.3k
    }
5020
5021
    /* Then try double character with no arguments. */
5022
3.10M
    if ((memcmp("||", cp, 2) == 0 ||
5023
3.07M
        memcmp("&&", cp, 2) == 0 ||
5024
3.07M
        memcmp("!!", cp, 2) == 0 ||
5025
3.07M
        memcmp("!=", cp, 2) == 0 ||
5026
3.06M
        memcmp("==", cp, 2) == 0 ||
5027
3.03M
        memcmp("<=", cp, 2) == 0 ||
5028
3.03M
        memcmp(">=", cp, 2) == 0) &&
5029
74.7k
        format_is_end(cp[2])) {
5030
47.7k
      format_add_modifier(&list, count, cp, 2, NULL, 0);
5031
47.7k
      cp += 2;
5032
47.7k
      continue;
5033
47.7k
    }
5034
5035
    /* Now try single character with arguments. */
5036
3.05M
    if (strchr("ImCLNPSOVst=pReqWcA", cp[0]) == NULL)
5037
708k
      break;
5038
2.34M
    c = cp[0];
5039
5040
    /* No arguments provided. */
5041
2.34M
    if (format_is_end(cp[1])) {
5042
134k
      format_add_modifier(&list, count, cp, 1, NULL, 0);
5043
134k
      cp++;
5044
134k
      continue;
5045
134k
    }
5046
2.21M
    argv = NULL;
5047
2.21M
    argc = 0;
5048
5049
    /* Single argument with no wrapper character. */
5050
2.21M
    if (!ispunct((u_char)cp[1]) || cp[1] == '-') {
5051
1.82M
      end = format_skip1(es, cp + 1, ":;");
5052
1.82M
      if (end == NULL)
5053
1.30M
        break;
5054
5055
521k
      argv = xcalloc(1, sizeof *argv);
5056
521k
      value = format_unescape(es, cp + 1, end - (cp + 1));
5057
521k
      argv[0] = format_expand1(es, value);
5058
521k
      free(value);
5059
521k
      argc = 1;
5060
5061
521k
      format_add_modifier(&list, count, &c, 1, argv, argc);
5062
521k
      cp = end;
5063
521k
      continue;
5064
1.82M
    }
5065
5066
    /* Multiple arguments with a wrapper character. */
5067
387k
    last[0] = cp[1];
5068
387k
    cp++;
5069
471k
    do {
5070
471k
      if (cp[0] == last[0] && format_is_end(cp[1])) {
5071
4.42k
        cp++;
5072
4.42k
        break;
5073
4.42k
      }
5074
467k
      end = format_skip1(es, cp + 1, last);
5075
467k
      if (end == NULL)
5076
136k
        break;
5077
330k
      cp++;
5078
5079
330k
      argv = xreallocarray(argv, argc + 1, sizeof *argv);
5080
330k
      value = format_unescape(es, cp, end - cp);
5081
330k
      argv[argc++] = format_expand1(es, value);
5082
330k
      free(value);
5083
5084
330k
      cp = end;
5085
330k
    } while (!format_is_end(cp[0]));
5086
387k
    format_add_modifier(&list, count, &c, 1, argv, argc);
5087
387k
  }
5088
3.04M
  if (*cp != ':') {
5089
2.16M
    format_free_modifiers(list, *count);
5090
2.16M
    *count = 0;
5091
2.16M
    return (NULL);
5092
2.16M
  }
5093
878k
  *s = cp + 1;
5094
878k
  return (list);
5095
3.04M
}
5096
5097
/* Match using the fuzzy matcher. */
5098
static char *
5099
format_match_fuzzy(const char *pattern, const char *text, int positions)
5100
86.1k
{
5101
86.1k
  struct evbuffer *buffer;
5102
86.1k
  bitstr_t  *bs;
5103
86.1k
  char    *value;
5104
86.1k
  size_t     size;
5105
86.1k
  u_int    i, width = 1;
5106
5107
86.1k
  if (positions) {
5108
82.5k
    width = format_width(text);
5109
82.5k
    if (width == 0)
5110
10.1k
      width = 1;
5111
82.5k
  }
5112
86.1k
  bs = fuzzy_match(pattern, text, width, NULL);
5113
86.1k
  if (bs == NULL)
5114
79.5k
    return (xstrdup(positions ? "" : "0"));
5115
5116
6.60k
  if (!positions) {
5117
296
    free(bs);
5118
296
    return (xstrdup("1"));
5119
296
  }
5120
5121
6.30k
  buffer = evbuffer_new();
5122
6.30k
  if (buffer == NULL)
5123
0
    fatalx("out of memory");
5124
17.8M
  for (i = 0; i < width; i++) {
5125
17.8M
    if (!bit_test(bs, i))
5126
17.2M
      continue;
5127
574k
    if (EVBUFFER_LENGTH(buffer) != 0)
5128
570k
      evbuffer_add(buffer, ",", 1);
5129
574k
    evbuffer_add_printf(buffer, "%u", i);
5130
574k
  }
5131
6.30k
  if ((size = EVBUFFER_LENGTH(buffer)) != 0)
5132
3.93k
    value = xmemdup(EVBUFFER_DATA(buffer), size);
5133
2.36k
  else
5134
2.36k
    value = xstrdup("");
5135
6.30k
  evbuffer_free(buffer);
5136
6.30k
  free(bs);
5137
6.30k
  return (value);
5138
6.30k
}
5139
5140
/* Match against an fnmatch(3) pattern or regular expression. */
5141
static char *
5142
format_match(struct format_modifier *fm, const char *pattern, const char *text)
5143
87.2k
{
5144
87.2k
  const char  *s = "";
5145
87.2k
  regex_t    r;
5146
87.2k
  int    flags = 0;
5147
5148
87.2k
  if (fm->argc >= 1)
5149
86.9k
    s = fm->argv[0];
5150
87.2k
  if (strchr(s, 'p') != NULL)
5151
82.5k
    return (format_match_fuzzy(pattern, text, 1));
5152
4.67k
  if (strchr(s, 'z') != NULL)
5153
3.61k
    return (format_match_fuzzy(pattern, text, 0));
5154
1.05k
  if (strchr(s, 'r') == NULL) {
5155
784
    if (strchr(s, 'i') != NULL)
5156
237
      flags |= FNM_CASEFOLD;
5157
784
    if (fnmatch(pattern, text, flags) != 0)
5158
512
      return (xstrdup("0"));
5159
784
  } else {
5160
275
    flags = REG_EXTENDED|REG_NOSUB;
5161
275
    if (strchr(s, 'i') != NULL)
5162
109
      flags |= REG_ICASE;
5163
275
    if (regcomp(&r, pattern, flags) != 0)
5164
0
      return (xstrdup("0"));
5165
275
    if (regexec(&r, text, 0, NULL, 0) != 0) {
5166
275
      regfree(&r);
5167
275
      return (xstrdup("0"));
5168
275
    }
5169
0
    regfree(&r);
5170
0
  }
5171
272
  return (xstrdup("1"));
5172
1.05k
}
5173
5174
/* Perform substitution in string. */
5175
static char *
5176
format_sub(struct format_modifier *fm, const char *text, const char *pattern,
5177
    const char *with)
5178
2.61k
{
5179
2.61k
  char  *value;
5180
2.61k
  int  flags = REG_EXTENDED;
5181
5182
2.61k
  if (fm->argc >= 3 && strchr(fm->argv[2], 'i') != NULL)
5183
200
    flags |= REG_ICASE;
5184
2.61k
  value = regsub(pattern, with, text, flags);
5185
2.61k
  if (value == NULL)
5186
0
    return (xstrdup(text));
5187
2.61k
  return (value);
5188
2.61k
}
5189
5190
/* Search inside pane. */
5191
static char *
5192
format_search(struct format_modifier *fm, struct window_pane *wp, const char *s)
5193
0
{
5194
0
  int  ignore = 0, regex = 0;
5195
0
  char  *value;
5196
5197
0
  if (fm->argc >= 1) {
5198
0
    if (strchr(fm->argv[0], 'i') != NULL)
5199
0
      ignore = 1;
5200
0
    if (strchr(fm->argv[0], 'r') != NULL)
5201
0
      regex = 1;
5202
0
  }
5203
0
  xasprintf(&value, "%u", window_pane_search(wp, s, regex, ignore));
5204
0
  return (value);
5205
0
}
5206
5207
/* Handle unary boolean operators, "!" and "!!". */
5208
static char *
5209
format_bool_op_1(struct format_expand_state *es, const char *fmt, int not)
5210
1.17k
{
5211
1.17k
  int  result;
5212
1.17k
  char  *expanded;
5213
5214
1.17k
  expanded = format_expand1(es, fmt);
5215
1.17k
  result = format_true(expanded);
5216
1.17k
  if (not)
5217
937
    result = !result;
5218
1.17k
  free(expanded);
5219
5220
1.17k
  return (xstrdup(result ? "1" : "0"));
5221
1.17k
}
5222
5223
/* Handle n-ary boolean operators, "&&" and "||". */
5224
static char *
5225
format_bool_op_n(struct format_expand_state *es, const char *fmt, int and)
5226
28.6k
{
5227
28.6k
  int    result;
5228
28.6k
  const char  *cp1, *cp2;
5229
28.6k
  char    *raw, *expanded;
5230
5231
28.6k
  result = and ? 1 : 0;
5232
28.6k
  cp1 = fmt;
5233
5234
31.9k
  while (and ? result : !result) {
5235
29.6k
    cp2 = format_skip1(es, cp1, ",");
5236
5237
29.6k
    if (cp2 == NULL)
5238
26.3k
      raw = xstrdup(cp1);
5239
3.25k
    else
5240
3.25k
      raw = xstrndup(cp1, cp2 - cp1);
5241
29.6k
    expanded = format_expand1(es, raw);
5242
29.6k
    free(raw);
5243
29.6k
    format_log(es, "operator %s has operand: %s",
5244
29.6k
        and ? "&&" : "||", expanded);
5245
5246
29.6k
    if (and)
5247
3.14k
      result = result && format_true(expanded);
5248
26.4k
    else
5249
26.4k
      result = result || format_true(expanded);
5250
29.6k
    free(expanded);
5251
5252
29.6k
    if (cp2 == NULL)
5253
26.3k
      break;
5254
3.25k
    else
5255
3.25k
      cp1 = cp2 + 1;
5256
29.6k
  }
5257
5258
28.6k
  return (xstrdup(result ? "1" : "0"));
5259
28.6k
}
5260
5261
/* Does session name exist? */
5262
static char *
5263
format_session_name(struct format_expand_state *es, const char *fmt)
5264
478
{
5265
478
  char    *name;
5266
478
  struct session  *s;
5267
5268
478
  name = format_expand1(es, fmt);
5269
478
  RB_FOREACH(s, sessions, &sessions) {
5270
0
    if (strcmp(s->name, name) == 0) {
5271
0
      free(name);
5272
0
      return (xstrdup("1"));
5273
0
    }
5274
0
  }
5275
478
  free(name);
5276
478
  return (xstrdup("0"));
5277
478
}
5278
5279
/* Loop over sessions. */
5280
static char *
5281
format_loop_sessions(struct format_expand_state *es, const char *fmt)
5282
17.5k
{
5283
17.5k
  struct sort_criteria     *sc = &sort_crit;
5284
17.5k
  struct format_tree     *ft = es->ft;
5285
17.5k
  struct client      *c = ft->client;
5286
17.5k
  struct cmdq_item     *item = ft->item;
5287
17.5k
  struct format_tree     *nft;
5288
17.5k
  struct format_expand_state    next;
5289
17.5k
  char         *all, *active, *use, *expanded, *value;
5290
17.5k
  struct evbuffer      *buffer;
5291
17.5k
  size_t          size;
5292
17.5k
  struct session       *s, **l;
5293
17.5k
  int         i, n;
5294
5295
17.5k
  if (format_choose(es, fmt, &all, &active, 0) != 0) {
5296
17.1k
    all = xstrdup(fmt);
5297
17.1k
    active = NULL;
5298
17.1k
  }
5299
5300
17.5k
  buffer = evbuffer_new();
5301
17.5k
  if (buffer == NULL)
5302
0
    fatalx("out of memory");
5303
5304
17.5k
  l = sort_get_sessions(&n, sc);
5305
17.5k
  for (i = 0; i < n; i++) {
5306
0
    s = l[i];
5307
0
    format_log(es, "session loop: $%u", s->id);
5308
0
    if (active != NULL &&
5309
0
        ft->c != NULL &&
5310
0
        ft->c->session != NULL &&
5311
0
        s->id == ft->c->session->id)
5312
0
      use = active;
5313
0
    else
5314
0
      use = all;
5315
0
    nft = format_create(c, item, FORMAT_NONE, ft->flags);
5316
5317
0
    format_add(nft, "loop_index", "%d", i);
5318
0
    format_add(nft, "loop_last_flag", "%d", i == n - 1);
5319
5320
0
    format_defaults(nft, ft->c, s, NULL, NULL);
5321
0
    format_copy_state(&next, es, 0);
5322
0
    next.ft = nft;
5323
5324
0
    expanded = format_expand1(&next, use);
5325
0
    format_free(next.ft);
5326
5327
0
    evbuffer_add(buffer, expanded, strlen(expanded));
5328
0
    free(expanded);
5329
0
  }
5330
5331
17.5k
  free(active);
5332
17.5k
  free(all);
5333
5334
17.5k
  if ((size = EVBUFFER_LENGTH(buffer)) != 0)
5335
0
    value = xmemdup(EVBUFFER_DATA(buffer), size);
5336
17.5k
  else
5337
17.5k
    value = xstrdup("");
5338
17.5k
  evbuffer_free(buffer);
5339
17.5k
  return (value);
5340
17.5k
}
5341
5342
/* Does window name exist? */
5343
static char *
5344
format_window_name(struct format_expand_state *es, const char *fmt)
5345
408
{
5346
408
  struct format_tree  *ft = es->ft;
5347
408
  char      *name;
5348
408
  struct winlink    *wl;
5349
5350
408
  if (ft->s == NULL) {
5351
408
    format_log(es, "window name but no session");
5352
408
    return (NULL);
5353
408
  }
5354
5355
0
  name = format_expand1(es, fmt);
5356
0
  RB_FOREACH(wl, winlinks, &ft->s->windows) {
5357
0
    if (strcmp(wl->window->name, name) == 0) {
5358
0
      free(name);
5359
0
      return (xstrdup("1"));
5360
0
    }
5361
0
  }
5362
0
  free(name);
5363
0
  return (xstrdup("0"));
5364
0
}
5365
5366
/* Add neighbour window variables to the format tree. */
5367
static void
5368
format_add_window_neighbour(struct format_tree *nft, struct winlink *wl,
5369
    struct session *s, const char *prefix)
5370
0
{
5371
0
  struct options_entry  *o;
5372
0
  const char    *oname;
5373
0
  char      *key, *prefixed, *oval;
5374
5375
0
  xasprintf(&key, "%s_window_index", prefix);
5376
0
  format_add(nft, key, "%u", wl->idx);
5377
0
  free(key);
5378
5379
0
  xasprintf(&key, "%s_window_active", prefix);
5380
0
  format_add(nft, key, "%d", wl == s->curw);
5381
0
  free(key);
5382
5383
0
  o = options_first(wl->window->options);
5384
0
  while (o != NULL) {
5385
0
    oname = options_name(o);
5386
0
    if (*oname == '@') {
5387
0
      xasprintf(&prefixed, "%s_%s", prefix, oname);
5388
0
      oval = options_to_string(o, NULL, 1);
5389
0
      format_add(nft, prefixed, "%s", oval);
5390
0
      free(oval);
5391
0
      free(prefixed);
5392
0
    }
5393
0
    o = options_next(o);
5394
0
  }
5395
0
}
5396
5397
/* Loop over windows. */
5398
static char *
5399
format_loop_windows(struct format_expand_state *es, const char *fmt)
5400
1.21k
{
5401
1.21k
  struct sort_criteria    *sc = &sort_crit;
5402
1.21k
  struct format_tree    *ft = es->ft;
5403
1.21k
  struct client     *c = ft->client;
5404
1.21k
  struct session      *s = ft->s;
5405
1.21k
  struct cmdq_item    *item = ft->item;
5406
1.21k
  struct format_tree    *nft;
5407
1.21k
  struct format_expand_state   next;
5408
1.21k
  char        *all, *active, *use, *expanded, *value;
5409
1.21k
  struct evbuffer     *buffer;
5410
1.21k
  size_t         size;
5411
1.21k
  struct winlink      *wl, **l;
5412
1.21k
  struct window     *w;
5413
1.21k
  int        i, n;
5414
5415
1.21k
  if (s == NULL) {
5416
1.21k
    format_log(es, "window loop but no session");
5417
1.21k
    return (NULL);
5418
1.21k
  }
5419
5420
0
  if (format_choose(es, fmt, &all, &active, 0) != 0) {
5421
0
    all = xstrdup(fmt);
5422
0
    active = NULL;
5423
0
  }
5424
5425
0
  buffer = evbuffer_new();
5426
0
  if (buffer == NULL)
5427
0
    fatalx("out of memory");
5428
5429
0
  l = sort_get_winlinks_session(s, &n, sc);
5430
0
  for (i = 0; i < n; i++) {
5431
0
    wl = l[i];
5432
0
    w = wl->window;
5433
0
    format_log(es, "window loop: %u @%u", wl->idx, w->id);
5434
0
    if (active != NULL && wl == s->curw)
5435
0
      use = active;
5436
0
    else
5437
0
      use = all;
5438
0
    nft = format_create(c, item, FORMAT_WINDOW|w->id, ft->flags);
5439
5440
0
    format_add(nft, "loop_index", "%d", i);
5441
0
    format_add(nft, "loop_last_flag", "%d", i == n - 1);
5442
5443
    /* Add neighbour window data to the format tree. */
5444
0
    if (i > 0 && l[i - 1] == s->curw)
5445
0
      format_add(nft, "window_after_active", "1");
5446
0
    else
5447
0
      format_add(nft, "window_after_active", "0");
5448
0
    if (i + 1 < n && l[i + 1] == s->curw)
5449
0
      format_add(nft, "window_before_active", "1");
5450
0
    else
5451
0
      format_add(nft, "window_before_active", "0");
5452
0
    if (i + 1 < n)
5453
0
      format_add_window_neighbour(nft, l[i + 1], s, "next");
5454
0
    if (i > 0)
5455
0
      format_add_window_neighbour(nft, l[i - 1], s, "prev");
5456
5457
0
    format_defaults(nft, ft->c, s, wl, NULL);
5458
0
    format_copy_state(&next, es, 0);
5459
0
    next.ft = nft;
5460
5461
0
    expanded = format_expand1(&next, use);
5462
0
    format_free(nft);
5463
5464
0
    evbuffer_add(buffer, expanded, strlen(expanded));
5465
0
    free(expanded);
5466
0
  }
5467
5468
0
  free(active);
5469
0
  free(all);
5470
5471
0
  if ((size = EVBUFFER_LENGTH(buffer)) != 0)
5472
0
    value = xmemdup(EVBUFFER_DATA(buffer), size);
5473
0
  else
5474
0
    value = xstrdup("");
5475
0
  evbuffer_free(buffer);
5476
0
  return (value);
5477
0
}
5478
5479
/* Loop over panes. */
5480
static char *
5481
format_loop_panes(struct format_expand_state *es, const char *fmt)
5482
1.37k
{
5483
1.37k
  struct sort_criteria    *sc = &sort_crit;
5484
1.37k
  struct format_tree    *ft = es->ft;
5485
1.37k
  struct client     *c = ft->client;
5486
1.37k
  struct cmdq_item    *item = ft->item;
5487
1.37k
  struct format_tree    *nft;
5488
1.37k
  struct format_expand_state   next;
5489
1.37k
  char        *all, *active, *use, *expanded, *value;
5490
1.37k
  struct evbuffer     *buffer;
5491
1.37k
  size_t         size;
5492
1.37k
  struct window_pane    *wp, **l;
5493
1.37k
  int         i, n;
5494
5495
1.37k
  if (ft->w == NULL) {
5496
1.37k
    format_log(es, "pane loop but no window");
5497
1.37k
    return (NULL);
5498
1.37k
  }
5499
5500
0
  if (format_choose(es, fmt, &all, &active, 0) != 0) {
5501
0
    all = xstrdup(fmt);
5502
0
    active = NULL;
5503
0
  }
5504
5505
0
  buffer = evbuffer_new();
5506
0
  if (buffer == NULL)
5507
0
    fatalx("out of memory");
5508
5509
0
  l = sort_get_panes_window(ft->w, &n, sc);
5510
0
  for (i = 0; i < n; i++) {
5511
0
    wp = l[i];
5512
0
    format_log(es, "pane loop: %%%u", wp->id);
5513
0
    if (active != NULL && wp == ft->w->active)
5514
0
      use = active;
5515
0
    else
5516
0
      use = all;
5517
0
    nft = format_create(c, item, FORMAT_PANE|wp->id, ft->flags);
5518
5519
0
    format_add(nft, "loop_index", "%d", i);
5520
0
    format_add(nft, "loop_last_flag", "%d", i == n - 1);
5521
5522
0
    format_defaults(nft, ft->c, ft->s, ft->wl, wp);
5523
0
    format_copy_state(&next, es, 0);
5524
0
    next.ft = nft;
5525
5526
0
    expanded = format_expand1(&next, use);
5527
0
    format_free(nft);
5528
5529
0
    evbuffer_add(buffer, expanded, strlen(expanded));
5530
0
    free(expanded);
5531
0
  }
5532
5533
0
  free(active);
5534
0
  free(all);
5535
5536
0
  if ((size = EVBUFFER_LENGTH(buffer)) != 0)
5537
0
    value = xmemdup(EVBUFFER_DATA(buffer), size);
5538
0
  else
5539
0
    value = xstrdup("");
5540
0
  evbuffer_free(buffer);
5541
0
  return (value);
5542
0
}
5543
5544
/* Add an option to an options loop. */
5545
static void
5546
format_loop_add_option(struct format_expand_state *es, const char *fmt,
5547
    struct evbuffer *buffer, struct options_entry *o, u_int n, u_int i)
5548
1.63M
{
5549
1.63M
  struct format_tree      *ft = es->ft, *nft;
5550
1.63M
  struct format_expand_state     next;
5551
1.63M
  const struct options_table_entry  *oe = options_table_entry(o);
5552
1.63M
  const char        *name = options_name(o);
5553
1.63M
  char          *expanded, *s;
5554
1.63M
  int          is_array = options_is_array(o);
5555
5556
1.63M
  format_log(es, "option loop: %s", name);
5557
1.63M
  nft = format_create(ft->client, ft->item, FORMAT_NONE, ft->flags);
5558
5559
1.63M
  format_add(nft, "option_name", "%s", name);
5560
1.63M
  s = options_to_string(o, NULL, 0);
5561
1.63M
  format_add(nft, "option_value", "%s", s);
5562
1.63M
  free(s);
5563
5564
1.63M
  format_add(nft, "option_is_array", "%d", is_array);
5565
1.63M
  format_add(nft, "option_array_key", "%s", "");
5566
1.63M
  format_add(nft, "option_array_index", "%s", "");
5567
1.63M
  format_add(nft, "option_array_first", "%d", is_array);
5568
1.63M
  format_add(nft, "option_array_last", "%d", is_array);
5569
1.63M
  format_add(nft, "option_array_count", "%u", n);
5570
5571
1.63M
  if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_HOOK))
5572
574k
    format_add(nft, "option_is_hook", "1");
5573
1.05M
  else
5574
1.05M
    format_add(nft, "option_is_hook", "0");
5575
1.63M
  format_add(nft, "option_is_user", "%d", oe == NULL);
5576
5577
1.63M
  if (options_next(o) == NULL)
5578
18.9k
    format_add(nft, "loop_last_flag", "1");
5579
1.61M
  else
5580
1.61M
    format_add(nft, "loop_last_flag", "0");
5581
1.63M
  format_add(nft, "loop_index", "%u", i);
5582
5583
1.63M
  format_defaults(nft, ft->c, ft->s, ft->wl, ft->wp);
5584
1.63M
  format_copy_state(&next, es, 0);
5585
1.63M
  next.ft = nft;
5586
5587
1.63M
  expanded = format_expand1(&next, fmt);
5588
1.63M
  format_free(nft);
5589
1.63M
  evbuffer_add(buffer, expanded, strlen(expanded));
5590
1.63M
  free(expanded);
5591
1.63M
}
5592
5593
/* Add an array option item to an options loop. */
5594
static void
5595
format_loop_add_array_item(struct format_expand_state *es, const char *fmt,
5596
    struct evbuffer *buffer, struct options_entry *o,
5597
    struct options_array_item *a, int n, u_int i)
5598
203k
{
5599
203k
  struct format_tree      *ft = es->ft, *nft;
5600
203k
  struct format_expand_state     next;
5601
203k
  const struct options_table_entry  *oe = options_table_entry(o);
5602
203k
  const char        *name = options_name(o);
5603
203k
  const char        *array_key;
5604
203k
  char          *expanded, *s;
5605
5606
203k
  array_key = options_array_item_key(a);
5607
203k
  format_log(es, "option loop: %s[%s]", name, array_key);
5608
203k
  nft = format_create(ft->client, ft->item, FORMAT_NONE, ft->flags);
5609
5610
203k
  format_add(nft, "option_name", "%s", name);
5611
203k
  s = options_to_string(o, array_key, 0);
5612
203k
  format_add(nft, "option_value", "%s", s);
5613
203k
  free(s);
5614
5615
203k
  format_add(nft, "option_is_array", "1");
5616
203k
  format_add(nft, "option_array_key", "%s", array_key);
5617
203k
  format_add(nft, "option_array_index", "%s", array_key);
5618
203k
  if (a == options_array_first(o))
5619
37.7k
    format_add(nft, "option_array_first", "1");
5620
166k
  else
5621
166k
    format_add(nft, "option_array_first", "0");
5622
203k
  if (options_array_next(a) == NULL)
5623
37.7k
    format_add(nft, "option_array_last", "1");
5624
166k
  else
5625
166k
    format_add(nft, "option_array_last", "0");
5626
203k
  format_add(nft, "option_array_count", "%u", n);
5627
5628
203k
  if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_HOOK))
5629
0
    format_add(nft, "option_is_hook", "1");
5630
203k
  else
5631
203k
    format_add(nft, "option_is_hook", "0");
5632
203k
  format_add(nft, "option_is_user", "%d", oe == NULL);
5633
5634
203k
  if (options_array_next(a) == NULL && options_next(o) == NULL)
5635
0
    format_add(nft, "loop_last_flag", "1");
5636
203k
  else
5637
203k
    format_add(nft, "loop_last_flag", "0");
5638
203k
  format_add(nft, "loop_index", "%u", i);
5639
5640
203k
  format_defaults(nft, ft->c, ft->s, ft->wl, ft->wp);
5641
203k
  format_copy_state(&next, es, 0);
5642
203k
  next.ft = nft;
5643
5644
203k
  expanded = format_expand1(&next, fmt);
5645
203k
  format_free(nft);
5646
203k
  evbuffer_add(buffer, expanded, strlen(expanded));
5647
203k
  free(expanded);
5648
203k
}
5649
5650
/* Loop over options. */
5651
static char *
5652
format_loop_options(struct format_expand_state *es, const char *fmt,
5653
    const char *flags)
5654
57.0k
{
5655
57.0k
  struct format_tree    *ft = es->ft;
5656
57.0k
  struct options      *oo = NULL;
5657
57.0k
  struct options_entry    *o;
5658
57.0k
  struct options_array_item *a;
5659
57.0k
  char        *value;
5660
57.0k
  struct evbuffer     *buffer;
5661
57.0k
  size_t         size;
5662
57.0k
  u_int        i = 0, n;
5663
57.0k
  int        global = 0;
5664
5665
57.0k
  if (flags == NULL || *flags == '\0')
5666
22.0k
    flags = "s";
5667
57.0k
  if (strchr(flags, 'v') != NULL)
5668
7.52k
    oo = global_options;
5669
49.4k
  else {
5670
49.4k
    if (strchr(flags, 'g') != NULL)
5671
26.1k
      global = 1;
5672
49.4k
    if (strchr(flags, 'w') != NULL) {
5673
4.11k
      if (global)
5674
3.89k
        oo = global_w_options;
5675
221
      else if (ft->w != NULL)
5676
0
        oo = ft->w->options;
5677
45.3k
    } else if (strchr(flags, 's') != NULL) {
5678
22.4k
      if (global)
5679
388
        oo = global_s_options;
5680
22.0k
      else if (ft->s != NULL)
5681
0
        oo = ft->s->options;
5682
22.9k
    } else if (strchr(flags, 'p') != NULL) {
5683
14.9k
      if (global)
5684
14.7k
        /* invalid */;
5685
221
      else if (ft->wp != NULL)
5686
0
        oo = ft->wp->options;
5687
14.9k
    } else if (global)
5688
7.17k
      oo = global_s_options;
5689
49.4k
  }
5690
57.0k
  if (oo == NULL)
5691
38.0k
    return (xstrdup(""));
5692
5693
18.9k
  buffer = evbuffer_new();
5694
18.9k
  if (buffer == NULL)
5695
0
    fatalx("out of memory");
5696
5697
18.9k
  o = options_first(oo);
5698
1.68M
  while (o != NULL) {
5699
5700
1.67M
    n = 0;
5701
1.67M
    if (options_is_array(o)) {
5702
630k
      a = options_array_first(o);
5703
834k
      while (a != NULL) {
5704
203k
        n++;
5705
203k
        a = options_array_next(a);
5706
203k
      }
5707
630k
    }
5708
5709
1.67M
    if (!options_is_array(o) || n == 0) {
5710
1.63M
      format_loop_add_option(es, fmt, buffer, o, n, i);
5711
1.63M
      i++;
5712
1.63M
      o = options_next(o);
5713
1.63M
      continue;
5714
1.63M
    }
5715
5716
37.7k
    a = options_array_first(o);
5717
241k
    while (a != NULL) {
5718
203k
      format_loop_add_array_item(es, fmt, buffer, o, a, n, i);
5719
203k
      i++;
5720
203k
      a = options_array_next(a);
5721
203k
    }
5722
37.7k
    o = options_next(o);
5723
37.7k
  }
5724
5725
18.9k
  if ((size = EVBUFFER_LENGTH(buffer)) != 0)
5726
13.1k
    value = xmemdup(EVBUFFER_DATA(buffer), size);
5727
5.78k
  else
5728
5.78k
    value = xstrdup("");
5729
18.9k
  evbuffer_free(buffer);
5730
18.9k
  return (value);
5731
18.9k
}
5732
5733
/* Loop over an environment. */
5734
static char *
5735
format_loop_environ(struct format_expand_state *es, const char *fmt,
5736
    const char *flags)
5737
1.19k
{
5738
1.19k
  struct format_tree    *ft = es->ft, *nft;
5739
1.19k
  struct client     *c = ft->client;
5740
1.19k
  struct cmdq_item    *item = ft->item;
5741
1.19k
  struct format_expand_state   next;
5742
1.19k
  struct environ      *env = NULL;
5743
1.19k
  struct environ_entry    *envent;
5744
1.19k
  char        *expanded, *value;
5745
1.19k
  struct evbuffer     *buffer;
5746
1.19k
  size_t         size;
5747
1.19k
  u_int        i = 0;
5748
5749
1.19k
  if (flags == NULL || *flags == '\0' || strcmp(flags, "s") == 0) {
5750
438
    if (ft->s != NULL)
5751
0
      env = ft->s->environ;
5752
758
  } else if (strcmp(flags, "g") == 0)
5753
309
    env = global_environ;
5754
449
  else if (strcmp(flags, "c") == 0) {
5755
223
    if (ft->client != NULL)
5756
0
      env = ft->client->environ;
5757
223
  }
5758
1.19k
  if (env == NULL)
5759
887
    return (xstrdup(""));
5760
5761
309
  buffer = evbuffer_new();
5762
309
  if (buffer == NULL)
5763
0
    fatalx("out of memory");
5764
5765
309
  envent = environ_first(env);
5766
309
  while (envent != NULL) {
5767
0
    format_log(es, "environment loop: %s", envent->name);
5768
0
    nft = format_create(c, item, FORMAT_NONE, ft->flags);
5769
5770
0
    format_add(nft, "environ_name", "%s", envent->name);
5771
0
    if (envent->value == NULL)
5772
0
      format_add(nft, "environ_value", "%s", "");
5773
0
    else
5774
0
      format_add(nft, "environ_value", "%s", envent->value);
5775
5776
0
    if (envent->flags & ENVIRON_HIDDEN)
5777
0
      format_add(nft, "environ_hidden", "1");
5778
0
    else
5779
0
      format_add(nft, "environ_hidden", "0");
5780
0
    format_add(nft, "environ_removed", "%d", envent->value == NULL);
5781
5782
0
    if (environ_next(envent) == NULL)
5783
0
      format_add(nft, "loop_last_flag", "1");
5784
0
    else
5785
0
      format_add(nft, "loop_last_flag", "0");
5786
0
    format_add(nft, "loop_index", "%u", i);
5787
5788
0
    format_defaults(nft, ft->c, ft->s, ft->wl, ft->wp);
5789
0
    format_copy_state(&next, es, 0);
5790
0
    next.ft = nft;
5791
5792
0
    expanded = format_expand1(&next, fmt);
5793
0
    format_free(nft);
5794
0
    evbuffer_add(buffer, expanded, strlen(expanded));
5795
0
    free(expanded);
5796
5797
0
    i++;
5798
0
    envent = environ_next(envent);
5799
0
  }
5800
5801
309
  if ((size = EVBUFFER_LENGTH(buffer)) != 0)
5802
0
    value = xmemdup(EVBUFFER_DATA(buffer), size);
5803
309
  else
5804
309
    value = xstrdup("");
5805
309
  evbuffer_free(buffer);
5806
309
  return (value);
5807
309
}
5808
5809
/* Loop over clients. */
5810
static char *
5811
format_loop_clients(struct format_expand_state *es, const char *fmt)
5812
1.67k
{
5813
1.67k
  struct sort_criteria     *sc = &sort_crit;
5814
1.67k
  struct format_tree     *ft = es->ft;
5815
1.67k
  struct client      *c, **l;
5816
1.67k
  struct cmdq_item     *item = ft->item;
5817
1.67k
  struct format_tree     *nft;
5818
1.67k
  struct format_expand_state    next;
5819
1.67k
  char         *expanded, *value;
5820
1.67k
  struct evbuffer      *buffer;
5821
1.67k
  size_t          size;
5822
1.67k
  int         i, n;
5823
5824
1.67k
  buffer = evbuffer_new();
5825
1.67k
  if (buffer == NULL)
5826
0
    fatalx("out of memory");
5827
5828
1.67k
  l = sort_get_clients(&n, sc);
5829
1.67k
  for (i = 0; i < n; i++) {
5830
0
    c = l[i];
5831
0
    format_log(es, "client loop: %s", c->name);
5832
0
    nft = format_create(c, item, 0, ft->flags);
5833
5834
0
    format_add(nft, "loop_index", "%d", i);
5835
0
    format_add(nft, "loop_last_flag", "%d", i == n - 1);
5836
5837
0
    format_defaults(nft, c, ft->s, ft->wl, ft->wp);
5838
0
    format_copy_state(&next, es, 0);
5839
0
    next.ft = nft;
5840
5841
0
    expanded = format_expand1(&next, fmt);
5842
0
    format_free(nft);
5843
0
    evbuffer_add(buffer, expanded, strlen(expanded));
5844
0
    free(expanded);
5845
0
  }
5846
5847
1.67k
  if ((size = EVBUFFER_LENGTH(buffer)) != 0)
5848
0
    value = xmemdup(EVBUFFER_DATA(buffer), size);
5849
1.67k
  else
5850
1.67k
    value = xstrdup("");
5851
1.67k
  evbuffer_free(buffer);
5852
1.67k
  return (value);
5853
1.67k
}
5854
5855
/* Truncate a value to a long long, failing if it is NaN or out of range. */
5856
static int
5857
format_truncate_integer(double *v)
5858
53.4k
{
5859
  /* (double)LLONG_MAX is 2^63, which does not fit; -2^63 does. */
5860
53.4k
  if (isnan(*v) || *v >= (double)LLONG_MAX || *v < (double)LLONG_MIN)
5861
2.08k
    return (-1);
5862
51.3k
  *v = (long long)*v;
5863
51.3k
  return (0);
5864
53.4k
}
5865
5866
static char *
5867
format_replace_expression(struct format_modifier *mexp,
5868
    struct format_expand_state *es, const char *copy)
5869
92.4k
{
5870
92.4k
  int      argc = mexp->argc;
5871
92.4k
  const char    *errstr;
5872
92.4k
  char      *endch, *value, *left = NULL, *right = NULL;
5873
92.4k
  int      use_fp = 0;
5874
92.4k
  u_int      prec = 0;
5875
92.4k
  double       mleft, mright, result;
5876
92.4k
  enum { ADD,
5877
92.4k
         SUBTRACT,
5878
92.4k
         MULTIPLY,
5879
92.4k
         DIVIDE,
5880
92.4k
         MODULUS,
5881
92.4k
         EQUAL,
5882
92.4k
         NOT_EQUAL,
5883
92.4k
         GREATER_THAN,
5884
92.4k
         GREATER_THAN_EQUAL,
5885
92.4k
         LESS_THAN,
5886
92.4k
         LESS_THAN_EQUAL } operator;
5887
5888
92.4k
  if (strcmp(mexp->argv[0], "+") == 0)
5889
447
    operator = ADD;
5890
92.0k
  else if (strcmp(mexp->argv[0], "-") == 0)
5891
2.08k
    operator = SUBTRACT;
5892
89.9k
  else if (strcmp(mexp->argv[0], "*") == 0)
5893
13.2k
    operator = MULTIPLY;
5894
76.7k
  else if (strcmp(mexp->argv[0], "/") == 0)
5895
2.13k
    operator = DIVIDE;
5896
74.5k
  else if (strcmp(mexp->argv[0], "%") == 0 ||
5897
68.8k
      strcmp(mexp->argv[0], "m") == 0)
5898
6.08k
    operator = MODULUS;
5899
68.5k
  else if (strcmp(mexp->argv[0], "==") == 0)
5900
30.8k
    operator = EQUAL;
5901
37.7k
  else if (strcmp(mexp->argv[0], "!=") == 0)
5902
275
    operator = NOT_EQUAL;
5903
37.4k
  else if (strcmp(mexp->argv[0], ">") == 0)
5904
11.0k
    operator = GREATER_THAN;
5905
26.3k
  else if (strcmp(mexp->argv[0], "<") == 0)
5906
288
    operator = LESS_THAN;
5907
26.0k
  else if (strcmp(mexp->argv[0], ">=") == 0)
5908
349
    operator = GREATER_THAN_EQUAL;
5909
25.7k
  else if (strcmp(mexp->argv[0], "<=") == 0)
5910
543
    operator = LESS_THAN_EQUAL;
5911
25.1k
  else {
5912
25.1k
    format_log(es, "expression has no valid operator: '%s'",
5913
25.1k
        mexp->argv[0]);
5914
25.1k
    goto fail;
5915
25.1k
  }
5916
5917
  /* The second argument may be flags. */
5918
67.3k
  if (argc >= 2 && strchr(mexp->argv[1], 'f') != NULL) {
5919
221
    use_fp = 1;
5920
221
    prec = 2;
5921
221
  }
5922
5923
  /* The third argument may be precision. */
5924
67.3k
  if (argc >= 3) {
5925
430
    prec = strtonum(mexp->argv[2], -FORMAT_MAX_PRECISION,
5926
430
        FORMAT_MAX_PRECISION, &errstr);
5927
430
    if (errstr != NULL) {
5928
200
      format_log(es, "expression precision %s: %s", errstr,
5929
200
          mexp->argv[2]);
5930
200
      goto fail;
5931
200
    }
5932
430
  }
5933
5934
67.1k
  if (format_choose(es, copy, &left, &right, 1) != 0) {
5935
46.3k
    format_log(es, "expression syntax error");
5936
46.3k
    goto fail;
5937
46.3k
  }
5938
5939
20.7k
  mleft = strtod(left, &endch);
5940
20.7k
  if (*endch != '\0') {
5941
1.82k
    format_log(es, "expression left side is invalid: %s", left);
5942
1.82k
    goto fail;
5943
1.82k
  }
5944
5945
18.8k
  mright = strtod(right, &endch);
5946
18.8k
  if (*endch != '\0') {
5947
362
    format_log(es, "expression right side is invalid: %s", right);
5948
362
    goto fail;
5949
362
  }
5950
5951
18.5k
  if (!use_fp &&
5952
18.3k
      (format_truncate_integer(&mleft) != 0 ||
5953
17.8k
      format_truncate_integer(&mright) != 0)) {
5954
1.02k
    format_log(es, "expression side is out of range");
5955
1.02k
    goto fail;
5956
1.02k
  }
5957
17.4k
  format_log(es, "expression left side is: %.*f", prec, mleft);
5958
17.4k
  format_log(es, "expression right side is: %.*f", prec, mright);
5959
5960
17.4k
  switch (operator) {
5961
194
  case ADD:
5962
194
    result = mleft + mright;
5963
194
    break;
5964
569
  case SUBTRACT:
5965
569
    result = mleft - mright;
5966
569
    break;
5967
412
  case MULTIPLY:
5968
412
    result = mleft * mright;
5969
412
    break;
5970
700
  case DIVIDE:
5971
700
    result = mleft / mright;
5972
700
    break;
5973
354
  case MODULUS:
5974
354
    result = fmod(mleft, mright);
5975
354
    break;
5976
3.36k
  case EQUAL:
5977
3.36k
    result = fabs(mleft - mright) < 1e-9;
5978
3.36k
    break;
5979
275
  case NOT_EQUAL:
5980
275
    result = fabs(mleft - mright) > 1e-9;
5981
275
    break;
5982
10.6k
  case GREATER_THAN:
5983
10.6k
    result = (mleft > mright);
5984
10.6k
    break;
5985
221
  case GREATER_THAN_EQUAL:
5986
221
    result = (mleft >= mright);
5987
221
    break;
5988
275
  case LESS_THAN:
5989
275
    result = (mleft < mright);
5990
275
    break;
5991
485
  case LESS_THAN_EQUAL:
5992
485
    result = (mleft <= mright);
5993
485
    break;
5994
17.4k
  }
5995
17.4k
  if (!use_fp && format_truncate_integer(&result) != 0) {
5996
1.05k
    format_log(es, "expression result is out of range");
5997
1.05k
    goto fail;
5998
1.05k
  }
5999
16.4k
  xasprintf(&value, "%.*f", prec, result);
6000
16.4k
  format_log(es, "expression result is %s", value);
6001
6002
16.4k
  free(right);
6003
16.4k
  free(left);
6004
16.4k
  return (value);
6005
6006
76.0k
fail:
6007
76.0k
  free(right);
6008
76.0k
  free(left);
6009
76.0k
  return (NULL);
6010
17.4k
}
6011
6012
/* Callback for the cycle timer; redraw the status line. */
6013
static void
6014
format_cycle_callback(__unused int fd, __unused short events, void *arg)
6015
0
{
6016
0
  struct client *c = arg;
6017
6018
0
  if (c->message_string == NULL && c->prompt == NULL)
6019
0
    c->flags |= CLIENT_REDRAWSTATUS;
6020
0
}
6021
6022
/* Arm the cycle timer to redraw the status line if it is not already. */
6023
static void
6024
format_cycle_start_timer(struct client *c)
6025
0
{
6026
0
  struct timeval  tv;
6027
6028
0
  tv.tv_sec = FORMAT_CYCLE_PERIOD / 1000;
6029
0
  tv.tv_usec = (FORMAT_CYCLE_PERIOD % 1000) * 1000L;
6030
6031
0
  if (!event_initialized(&c->cycle_timer))
6032
0
    evtimer_set(&c->cycle_timer, format_cycle_callback, c);
6033
0
  if (!evtimer_pending(&c->cycle_timer, NULL))
6034
0
    evtimer_add(&c->cycle_timer, &tv);
6035
0
}
6036
6037
/* Expand the "A" animation modifier; see the manual for the syntax. */
6038
static char *
6039
format_cycle(struct format_expand_state *es, const char *frames, u_int count)
6040
18.5k
{
6041
18.5k
  struct format_tree  *ft = es->ft;
6042
18.5k
  const char    *start, *end, *cp;
6043
18.5k
  u_int      n, index, i;
6044
6045
  /*
6046
   * A cycle is only expanded in a status format, and never in the
6047
   * command or output of #() where it would change on every frame and
6048
   * make the job run again.
6049
   */
6050
18.5k
  if (!(ft->flags & FORMAT_STATUS) || (es->flags & FORMAT_EXPAND_NOCYCLE))
6051
18.5k
    return (xstrdup(""));
6052
0
  if (*frames == '\0')
6053
0
    return (xstrdup(""));
6054
6055
  /* Count the comma-separated frames (there is at least one). */
6056
0
  n = 1;
6057
0
  for (cp = frames; *cp != '\0'; cp++) {
6058
0
    if (*cp == ',')
6059
0
      n++;
6060
0
  }
6061
0
  index = (es->start_time / (count * FORMAT_CYCLE_PERIOD)) % n;
6062
6063
  /*
6064
   * Redraw the status line so the frames advance on their own; a
6065
   * single frame never changes so there is nothing to redraw for.
6066
   */
6067
0
  if (n > 1 && ft->client != NULL)
6068
0
    format_cycle_start_timer(ft->client);
6069
6070
  /* Walk to the chosen frame and return a copy of it. */
6071
0
  start = frames;
6072
0
  for (i = 0; i < index; i++)
6073
0
    start = strchr(start, ',') + 1;
6074
0
  end = strchr(start, ',');
6075
0
  if (end == NULL)
6076
0
    end = start + strlen(start);
6077
0
  return (xstrndup(start, end - start));
6078
0
}
6079
6080
/* Replace a key. */
6081
static int
6082
format_replace(struct format_expand_state *es, const char *key, size_t keylen,
6083
    char **buf, size_t *len, size_t *off)
6084
3.04M
{
6085
3.04M
  struct sort_criteria     *sc = &sort_crit;
6086
3.04M
  struct format_tree     *ft = es->ft;
6087
3.04M
  struct window_pane     *wp = ft->wp;
6088
3.04M
  const char       *errstr, *copy, *cp, *cp2;
6089
3.04M
  const char       *marker = NULL;
6090
3.04M
  char         *time_format = NULL;
6091
3.04M
  char         *copy0, *condition, *found, *new;
6092
3.04M
  char         *value, *left, *right;
6093
3.04M
  size_t          n;
6094
3.04M
  uint64_t        modifiers = 0;
6095
3.04M
  int         limit = 0, width = 0;
6096
3.04M
  int         j, c;
6097
3.04M
  struct format_modifier     *list, *cmp = NULL, *search = NULL;
6098
3.04M
  struct format_modifier    **sub = NULL, *mexp = NULL, *fm;
6099
3.04M
  struct format_modifier     *bool_op_n = NULL;
6100
3.04M
  u_int         cycle_count = 1;
6101
3.04M
  u_int         i, count, nsub = 0, nrep;
6102
3.04M
  const char       *loop_flags = "";
6103
3.04M
  struct format_expand_state    next;
6104
3.04M
  struct environ_entry     *envent;
6105
6106
  /* Set sorting defaults. */
6107
3.04M
  sc->order = SORT_ORDER;
6108
3.04M
  sc->reversed = 0;
6109
6110
  /* Make a copy of the key. */
6111
3.04M
  copy = copy0 = xstrndup(key, keylen);
6112
6113
  /* Process modifier list. */
6114
3.04M
  list = format_build_modifiers(es, &copy, &count);
6115
3.91M
  for (i = 0; i < count; i++) {
6116
866k
    fm = &list[i];
6117
866k
    if (format_logging(ft)) {
6118
0
      format_log(es, "modifier %u is %s", i, fm->modifier);
6119
0
      for (j = 0; j < fm->argc; j++) {
6120
0
        format_log(es, "modifier %u argument %d: %s", i,
6121
0
            j, fm->argv[j]);
6122
0
      }
6123
0
    }
6124
866k
    if (fm->size == 1) {
6125
818k
      switch (fm->modifier[0]) {
6126
95.9k
      case 'm':
6127
96.8k
      case '<':
6128
97.6k
      case '>':
6129
97.6k
        cmp = fm;
6130
97.6k
        break;
6131
1.22k
      case '!':
6132
1.22k
        modifiers |= FORMAT_NOT;
6133
1.22k
        break;
6134
7.37k
      case 'C':
6135
7.37k
        search = fm;
6136
7.37k
        break;
6137
4.78k
      case 's':
6138
4.78k
        if (fm->argc < 2)
6139
2.16k
          break;
6140
2.61k
        sub = xreallocarray(sub, nsub + 1, sizeof *sub);
6141
2.61k
        sub[nsub++] = fm;
6142
2.61k
        break;
6143
22.7k
      case '=':
6144
22.7k
        if (fm->argc < 1)
6145
1.20k
          break;
6146
21.5k
        limit = strtonum(fm->argv[0], -FORMAT_MAX_WIDTH,
6147
21.5k
            FORMAT_MAX_WIDTH, &errstr);
6148
21.5k
        if (errstr != NULL)
6149
14.6k
          limit = 0;
6150
21.5k
        if (fm->argc >= 2 && fm->argv[1] != NULL)
6151
13.2k
          marker = fm->argv[1];
6152
21.5k
        break;
6153
95.4k
      case 'p':
6154
95.4k
        if (fm->argc < 1)
6155
549
          break;
6156
94.8k
        width = strtonum(fm->argv[0], -FORMAT_MAX_WIDTH,
6157
94.8k
            FORMAT_MAX_WIDTH, &errstr);
6158
94.8k
        if (errstr != NULL)
6159
15.5k
          width = 0;
6160
94.8k
        break;
6161
18.5k
      case 'A':
6162
18.5k
        modifiers |= FORMAT_CYCLE;
6163
18.5k
        if (fm->argc < 1)
6164
353
          break;
6165
18.1k
        cycle_count = strtonum(fm->argv[0], 1, 100,
6166
18.1k
            &errstr);
6167
18.1k
        if (errstr != NULL)
6168
17.9k
          cycle_count = 1;
6169
18.1k
        break;
6170
978
      case 'w':
6171
978
        modifiers |= FORMAT_WIDTH;
6172
978
        break;
6173
93.8k
      case 'e':
6174
93.8k
        if (fm->argc < 1 || fm->argc > 3)
6175
1.10k
          break;
6176
92.7k
        mexp = fm;
6177
92.7k
        break;
6178
1.81k
      case 'l':
6179
1.81k
        modifiers |= FORMAT_LITERAL;
6180
1.81k
        break;
6181
3.77k
      case 'a':
6182
3.77k
        modifiers |= FORMAT_CHARACTER;
6183
3.77k
        break;
6184
465
      case 'b':
6185
465
        modifiers |= FORMAT_BASENAME;
6186
465
        break;
6187
41.8k
      case 'c':
6188
41.8k
        modifiers |= FORMAT_COLOUR;
6189
41.8k
        if (fm->argc < 1)
6190
30.2k
          break;
6191
11.5k
        if (strchr(fm->argv[0], 'f') != NULL)
6192
1.24k
          modifiers |= FORMAT_COLOUR_ESC_FG;
6193
11.5k
        if (strchr(fm->argv[0], 'b') != NULL)
6194
2.34k
          modifiers |= FORMAT_COLOUR_ESC_BG;
6195
11.5k
        break;
6196
627
      case 'd':
6197
627
        modifiers |= FORMAT_DIRNAME;
6198
627
        break;
6199
521
      case 'n':
6200
521
        modifiers |= FORMAT_LENGTH;
6201
521
        break;
6202
4.35k
      case 'I':
6203
4.35k
        if (fm->argc < 1)
6204
3.35k
          break;
6205
1.00k
        if (strchr(fm->argv[0], 'f') != NULL)
6206
324
          modifiers |= FORMAT_CLIENT_TERMFEAT;
6207
1.00k
        if (strchr(fm->argv[0], 'c') != NULL)
6208
231
          modifiers |= FORMAT_CLIENT_TERMCAP;
6209
1.00k
        if (strchr(fm->argv[0], 'e') != NULL)
6210
281
          modifiers |= FORMAT_CLIENT_ENVIRON;
6211
1.00k
        break;
6212
35.8k
      case 't':
6213
35.8k
        modifiers |= FORMAT_TIMESTRING;
6214
35.8k
        if (fm->argc < 1)
6215
16.6k
          break;
6216
19.2k
        if (strchr(fm->argv[0], 'p') != NULL)
6217
2.86k
          modifiers |= FORMAT_PRETTY;
6218
16.3k
        else if (strchr(fm->argv[0], 'r') != NULL)
6219
391
          modifiers |= FORMAT_RELATIVE;
6220
15.9k
        else if (strchr(fm->argv[0], 'd') != NULL)
6221
460
          modifiers |= FORMAT_DIFFERENCE;
6222
15.5k
        else if (fm->argc >= 2 &&
6223
1.54k
            strchr(fm->argv[0], 'f') != NULL) {
6224
1.31k
          free(time_format);
6225
1.31k
          time_format = format_strip(es,
6226
1.31k
              fm->argv[1]);
6227
1.31k
        }
6228
19.2k
        break;
6229
24.1k
      case 'q':
6230
24.1k
        if (fm->argc < 1)
6231
787
          modifiers |= FORMAT_QUOTE_SHELL;
6232
23.3k
        else if (strchr(fm->argv[0], 's') != NULL)
6233
1.10k
          modifiers |= FORMAT_QUOTE_SHELL_SQ;
6234
22.2k
        else if (strchr(fm->argv[0], 'e') != NULL ||
6235
21.6k
            strchr(fm->argv[0], 'h') != NULL)
6236
1.77k
          modifiers |= FORMAT_QUOTE_STYLE;
6237
20.4k
        else if (strchr(fm->argv[0], 'a') != NULL)
6238
19.2k
          modifiers |= FORMAT_QUOTE_ARGUMENTS;
6239
24.1k
        break;
6240
35.0k
      case 'E':
6241
35.0k
        modifiers |= FORMAT_EXPAND;
6242
35.0k
        break;
6243
5.04k
      case 'T':
6244
5.04k
        modifiers |= FORMAT_EXPANDTIME;
6245
5.04k
        break;
6246
1.27k
      case 'N':
6247
1.27k
        if (fm->argc < 1 ||
6248
1.06k
            strchr(fm->argv[0], 'w') != NULL)
6249
414
          modifiers |= FORMAT_WINDOW_NAME;
6250
861
        else if (strchr(fm->argv[0], 's') != NULL)
6251
478
          modifiers |= FORMAT_SESSION_NAME;
6252
1.27k
        break;
6253
17.5k
      case 'S':
6254
17.5k
        modifiers |= FORMAT_SESSIONS;
6255
17.5k
        if (fm->argc < 1) {
6256
8.03k
          sc->order= SORT_INDEX;
6257
8.03k
          sc->reversed = 0;
6258
8.03k
          break;
6259
8.03k
        }
6260
9.47k
        if (strchr(fm->argv[0], 'i') != NULL)
6261
353
          sc->order = SORT_INDEX;
6262
9.12k
        else if (strchr(fm->argv[0], 'n') != NULL)
6263
221
          sc->order = SORT_NAME;
6264
8.90k
        else if (strchr(fm->argv[0], 't') != NULL)
6265
198
          sc->order = SORT_ACTIVITY;
6266
8.70k
        else
6267
8.70k
          sc->order = SORT_INDEX;
6268
9.47k
        if (strchr(fm->argv[0], 'r') != NULL)
6269
200
          sc->reversed = 1;
6270
9.27k
        else
6271
9.27k
          sc->reversed = 0;
6272
9.47k
        break;
6273
1.25k
      case 'W':
6274
1.25k
        modifiers |= FORMAT_WINDOWS;
6275
1.25k
        if (fm->argc < 1) {
6276
300
          sc->order = SORT_ORDER;
6277
300
          sc->reversed = 0;
6278
300
          break;
6279
300
        }
6280
950
        if (strchr(fm->argv[0], 'i') != NULL)
6281
198
          sc->order = SORT_ORDER;
6282
752
        else if (strchr(fm->argv[0], 'n') != NULL)
6283
221
          sc->order = SORT_NAME;
6284
531
        else if (strchr(fm->argv[0], 't') != NULL)
6285
199
          sc->order = SORT_ACTIVITY;
6286
332
        else
6287
332
          sc->order = SORT_ORDER;
6288
950
        if (strchr(fm->argv[0], 'r') != NULL)
6289
307
          sc->reversed = 1;
6290
643
        else
6291
643
          sc->reversed = 0;
6292
950
        break;
6293
1.38k
      case 'P':
6294
1.38k
        modifiers |= FORMAT_PANES;
6295
1.38k
        sc->order = SORT_CREATION;
6296
1.38k
        if (fm->argc < 1) {
6297
634
          sc->reversed = 0;
6298
634
          break;
6299
634
        }
6300
748
        if (strchr(fm->argv[0], 'i') != NULL)
6301
221
          sc->order = SORT_INDEX;
6302
527
        else if (strchr(fm->argv[0], 'z') != NULL)
6303
223
          sc->order = SORT_Z;
6304
304
        else
6305
304
          sc->order = SORT_CREATION;
6306
748
        if (strchr(fm->argv[0], 'r') != NULL)
6307
237
          sc->reversed = 1;
6308
511
        else
6309
511
          sc->reversed = 0;
6310
748
        break;
6311
57.0k
      case 'O':
6312
57.0k
        modifiers |= FORMAT_OPTIONS;
6313
57.0k
        if (fm->argc == 1)
6314
56.7k
          loop_flags = fm->argv[0];
6315
57.0k
        break;
6316
1.19k
      case 'V':
6317
1.19k
        modifiers |= FORMAT_ENVIRON;
6318
1.19k
        if (fm->argc == 1)
6319
975
          loop_flags = fm->argv[0];
6320
1.19k
        break;
6321
1.75k
      case 'L':
6322
1.75k
        modifiers |= FORMAT_CLIENTS;
6323
1.75k
        if (fm->argc < 1) {
6324
427
          sc->order = SORT_ORDER;
6325
427
          sc->reversed = 0;
6326
427
          break;
6327
427
        }
6328
1.32k
        if (strchr(fm->argv[0], 'i') != NULL)
6329
222
          sc->order = SORT_ORDER;
6330
1.10k
        else if (strchr(fm->argv[0], 'n') != NULL)
6331
212
          sc->order = SORT_NAME;
6332
894
        else if (strchr(fm->argv[0], 't') != NULL)
6333
206
          sc->order = SORT_ACTIVITY;
6334
688
        else
6335
688
          sc->order = SORT_ORDER;
6336
1.32k
        if (strchr(fm->argv[0], 'r') != NULL)
6337
198
          sc->reversed = 1;
6338
1.13k
        else
6339
1.13k
          sc->reversed = 0;
6340
1.32k
        break;
6341
241k
      case 'R':
6342
241k
        modifiers |= FORMAT_REPEAT;
6343
241k
        break;
6344
818k
      }
6345
818k
    } else if (fm->size == 2) {
6346
47.7k
      if (strcmp(fm->modifier, "||") == 0 ||
6347
21.8k
          strcmp(fm->modifier, "&&") == 0)
6348
28.6k
        bool_op_n = fm;
6349
19.0k
      else if (strcmp(fm->modifier, "!!") == 0)
6350
236
        modifiers |= FORMAT_NOT_NOT;
6351
18.8k
      else if (strcmp(fm->modifier, "==") == 0 ||
6352
9.36k
          strcmp(fm->modifier, "!=") == 0 ||
6353
1.49k
          strcmp(fm->modifier, ">=") == 0 ||
6354
782
          strcmp(fm->modifier, "<=") == 0)
6355
18.8k
        cmp = fm;
6356
47.7k
    }
6357
866k
  }
6358
6359
  /* Look up client capability, feature or environment. */
6360
3.04M
  if ((modifiers & FORMAT_CLIENT_TERMCAP) ||
6361
3.04M
      (modifiers & FORMAT_CLIENT_TERMFEAT) ||
6362
3.04M
      (modifiers & FORMAT_CLIENT_ENVIRON)) {
6363
803
    if (ft->c == NULL ||
6364
0
        ft->c->tty.term == NULL ||
6365
803
        ft->c->flags & CLIENT_UNATTACHEDFLAGS) {
6366
803
      value = xstrdup("");
6367
803
      goto done;
6368
803
    }
6369
0
    if (modifiers & FORMAT_CLIENT_TERMCAP) {
6370
0
      if (tty_term_has_name(ft->c->tty.term, copy))
6371
0
        value = xstrdup("1");
6372
0
      else
6373
0
        value = xstrdup("0");
6374
0
    }
6375
0
    if (modifiers & FORMAT_CLIENT_TERMFEAT) {
6376
0
      if (tty_feature_present(ft->c->tty.term, copy))
6377
0
        value = xstrdup("1");
6378
0
      else
6379
0
        value = xstrdup("0");
6380
0
    }
6381
0
    if (modifiers & FORMAT_CLIENT_ENVIRON) {
6382
0
      envent = environ_find(ft->c->environ, copy);
6383
0
      if (envent != NULL && envent->value != NULL)
6384
0
        value = xstrdup(envent->value);
6385
0
      else
6386
0
        value = xstrdup("");
6387
0
    }
6388
0
    goto done;
6389
803
  }
6390
6391
  /* Is this an animation cycle? */
6392
3.04M
  if (modifiers & FORMAT_CYCLE) {
6393
18.5k
    value = format_cycle(es, copy, cycle_count);
6394
18.5k
    format_log(es, "cycle '%s' is: %s", copy, value);
6395
18.5k
    goto done;
6396
18.5k
  }
6397
6398
  /* Is this a literal string? */
6399
3.02M
  if (modifiers & FORMAT_LITERAL) {
6400
1.80k
    format_log(es, "literal string is '%s'", copy);
6401
1.80k
    value = format_unescape(es, copy, strlen(copy));
6402
1.80k
    goto done;
6403
1.80k
  }
6404
6405
  /* Is this a character? */
6406
3.02M
  if (modifiers & FORMAT_CHARACTER) {
6407
3.77k
    new = format_expand1(es, copy);
6408
3.77k
    c = strtonum(new, 32, 126, &errstr);
6409
3.77k
    if (errstr != NULL)
6410
3.51k
      value = xstrdup("");
6411
254
    else
6412
254
      xasprintf(&value, "%c", c);
6413
3.77k
    free(new);
6414
3.77k
    goto done;
6415
3.77k
  }
6416
6417
  /* Is this a colour? */
6418
3.02M
  if (modifiers & FORMAT_COLOUR) {
6419
41.8k
    new = format_expand1(es, copy);
6420
41.8k
    if (modifiers & (FORMAT_COLOUR_ESC_FG|FORMAT_COLOUR_ESC_BG)) {
6421
3.46k
      if (strcasecmp(new, "none") == 0)
6422
198
        value = xstrdup("\033[0m");
6423
3.26k
      else if ((c = colour_fromstring(new)) == -1)
6424
958
        value = xstrdup("");
6425
2.30k
      else {
6426
2.30k
        if (modifiers & FORMAT_COLOUR_ESC_BG)
6427
1.51k
          cp = colour_toescape(ft->c, c, 1);
6428
791
        else
6429
791
          cp = colour_toescape(ft->c, c, 0);
6430
2.30k
        if (cp == NULL)
6431
0
          value = xstrdup("");
6432
2.30k
        else
6433
2.30k
          value = xstrdup(cp);
6434
2.30k
      }
6435
38.4k
    } else {
6436
38.4k
      c = colour_fromstring(new);
6437
38.4k
      if (c == -1 || (c = colour_force_rgb(c)) == -1)
6438
11.5k
        value = xstrdup("");
6439
26.8k
      else
6440
26.8k
        xasprintf(&value, "%06x", c & 0xffffff);
6441
38.4k
    }
6442
41.8k
    free(new);
6443
41.8k
    goto done;
6444
41.8k
  }
6445
6446
  /* Is this a loop, operator, comparison or condition? */
6447
2.97M
  if (modifiers & FORMAT_SESSIONS) {
6448
17.5k
    value = format_loop_sessions(es, copy);
6449
17.5k
    if (value == NULL)
6450
0
      goto fail;
6451
2.96M
  } else if (modifiers & FORMAT_WINDOWS) {
6452
1.21k
    value = format_loop_windows(es, copy);
6453
1.21k
    if (value == NULL)
6454
1.21k
      goto fail;
6455
2.95M
  } else if (modifiers & FORMAT_PANES) {
6456
1.37k
    value = format_loop_panes(es, copy);
6457
1.37k
    if (value == NULL)
6458
1.37k
      goto fail;
6459
2.95M
  } else if (modifiers & FORMAT_CLIENTS) {
6460
1.67k
    value = format_loop_clients(es, copy);
6461
1.67k
    if (value == NULL)
6462
0
      goto fail;
6463
2.95M
  } else if (modifiers & FORMAT_OPTIONS) {
6464
57.0k
    value = format_loop_options(es, copy, loop_flags);
6465
57.0k
    if (value == NULL)
6466
0
      goto fail;
6467
2.89M
  } else if (modifiers & FORMAT_ENVIRON) {
6468
1.19k
    value = format_loop_environ(es, copy, loop_flags);
6469
1.19k
    if (value == NULL)
6470
0
      goto fail;
6471
2.89M
  } else if (modifiers & FORMAT_WINDOW_NAME) {
6472
408
    value = format_window_name(es, copy);
6473
408
    if (value == NULL)
6474
408
      goto fail;
6475
2.89M
  } else if (modifiers & FORMAT_SESSION_NAME) {
6476
478
    value = format_session_name(es, copy);
6477
478
    if (value == NULL)
6478
0
      goto fail;
6479
2.89M
  } else if (search != NULL) {
6480
    /* Search in pane. */
6481
7.37k
    new = format_expand1(es, copy);
6482
7.37k
    if (wp == NULL) {
6483
7.37k
      format_log(es, "search '%s' but no pane", new);
6484
7.37k
      value = xstrdup("0");
6485
7.37k
    } else {
6486
0
      format_log(es, "search '%s' pane %%%u", new, wp->id);
6487
0
      value = format_search(search, wp, new);
6488
0
    }
6489
7.37k
    free(new);
6490
2.89M
  } else if (modifiers & FORMAT_REPEAT) {
6491
    /* Repeat multiple times. */
6492
241k
    if (format_choose(es, copy, &left, &right, 1) != 0) {
6493
20.5k
      format_log(es, "repeat syntax error: %s", copy);
6494
20.5k
      goto fail;
6495
20.5k
    }
6496
220k
    nrep = strtonum(right, 1, FORMAT_MAX_REPEAT, &errstr);
6497
220k
    if (errstr != NULL)
6498
18.8k
      value = xstrdup("");
6499
201k
    else {
6500
201k
      n = strlen(left);
6501
201k
      if (n != 0 && nrep > FORMAT_MAX_REPEAT_SIZE / n) {
6502
255
        format_log(es, "repeat is too long: %s", copy);
6503
255
        value = xstrdup("");
6504
201k
      } else {
6505
201k
        value = xmalloc((nrep * n) + 1);
6506
198M
        for (i = 0; i < nrep; i++)
6507
198M
          memcpy(value + (i * n), left, n);
6508
201k
        value[nrep * n] = '\0';
6509
201k
      }
6510
201k
    }
6511
220k
    free(right);
6512
220k
    free(left);
6513
2.64M
  } else if (modifiers & FORMAT_NOT) {
6514
937
    value = format_bool_op_1(es, copy, 1);
6515
2.64M
  } else if (modifiers & FORMAT_NOT_NOT) {
6516
236
    value = format_bool_op_1(es, copy, 0);
6517
2.64M
  } else if (bool_op_n != NULL) {
6518
    /* n-ary boolean operator. */
6519
28.6k
    if (strcmp(bool_op_n->modifier, "||") == 0)
6520
25.8k
      value = format_bool_op_n(es, copy, 0);
6521
2.80k
    else if (strcmp(bool_op_n->modifier, "&&") == 0)
6522
2.80k
      value = format_bool_op_n(es, copy, 1);
6523
2.61M
  } else if (cmp != NULL) {
6524
    /* Comparison of left and right. */
6525
116k
    if (format_choose(es, copy, &left, &right, 1) != 0) {
6526
10.7k
      format_log(es, "compare %s syntax error: %s",
6527
10.7k
          cmp->modifier, copy);
6528
10.7k
      goto fail;
6529
10.7k
    }
6530
105k
    format_log(es, "compare %s left is: %s", cmp->modifier, left);
6531
105k
    format_log(es, "compare %s right is: %s", cmp->modifier, right);
6532
6533
105k
    if (strcmp(cmp->modifier, "==") == 0) {
6534
8.49k
      if (strcmp(left, right) == 0)
6535
212
        value = xstrdup("1");
6536
8.28k
      else
6537
8.28k
        value = xstrdup("0");
6538
97.2k
    } else if (strcmp(cmp->modifier, "!=") == 0) {
6539
7.72k
      if (strcmp(left, right) != 0)
6540
7.12k
        value = xstrdup("1");
6541
609
      else
6542
609
        value = xstrdup("0");
6543
89.4k
    } else if (strcmp(cmp->modifier, "<") == 0) {
6544
529
      if (strcmp(left, right) < 0)
6545
268
        value = xstrdup("1");
6546
261
      else
6547
261
        value = xstrdup("0");
6548
88.9k
    } else if (strcmp(cmp->modifier, ">") == 0) {
6549
576
      if (strcmp(left, right) > 0)
6550
276
        value = xstrdup("1");
6551
300
      else
6552
300
        value = xstrdup("0");
6553
88.3k
    } else if (strcmp(cmp->modifier, "<=") == 0) {
6554
481
      if (strcmp(left, right) <= 0)
6555
243
        value = xstrdup("1");
6556
238
      else
6557
238
        value = xstrdup("0");
6558
87.8k
    } else if (strcmp(cmp->modifier, ">=") == 0) {
6559
658
      if (strcmp(left, right) >= 0)
6560
364
        value = xstrdup("1");
6561
294
      else
6562
294
        value = xstrdup("0");
6563
87.2k
    } else if (strcmp(cmp->modifier, "m") == 0)
6564
87.2k
      value = format_match(cmp, left, right);
6565
6566
105k
    free(right);
6567
105k
    free(left);
6568
2.50M
  } else if (*copy == '?') {
6569
    /*
6570
     * Conditional: For each pair of (condition, value), check the
6571
     * condition and return the value if true. If no condition
6572
     * matches, return the last unpaired arg if there is one, or the
6573
     * empty string if not.
6574
     */
6575
120k
    cp = copy + 1;
6576
126k
    while (1) {
6577
126k
      cp2 = format_skip1(es, cp, ",");
6578
126k
      if (cp2 == NULL) {
6579
91.2k
        format_log(es,
6580
91.2k
            "no condition matched in '%s'; using last "
6581
91.2k
            "arg", copy + 1);
6582
91.2k
        value = format_expand1(es, cp);
6583
91.2k
        break;
6584
91.2k
      }
6585
6586
34.9k
      condition = xstrndup(cp, cp2 - cp);
6587
34.9k
      format_log(es, "condition is: %s", condition);
6588
6589
34.9k
      found = format_find(ft, condition, modifiers,
6590
34.9k
          time_format);
6591
34.9k
      if (found == NULL) {
6592
        /*
6593
         * If the condition not found, try to expand it.
6594
         * If the expansion doesn't have any effect,
6595
         * then assume false.
6596
         */
6597
34.3k
        found = format_expand1(es, condition);
6598
34.3k
        if (strcmp(found, condition) == 0) {
6599
11.4k
          free(found);
6600
11.4k
          found = xstrdup("");
6601
11.4k
          format_log(es,
6602
11.4k
              "condition '%s' not found; "
6603
11.4k
              "assuming false",
6604
11.4k
              condition);
6605
11.4k
        }
6606
34.3k
      } else {
6607
558
        format_log(es, "condition '%s' found: %s",
6608
558
            condition, found);
6609
558
      }
6610
6611
34.9k
      cp = cp2 + 1;
6612
34.9k
      cp2 = format_skip1(es, cp, ",");
6613
34.9k
      if (format_true(found)) {
6614
20.3k
        format_log(es, "condition '%s' is true",
6615
20.3k
            condition);
6616
20.3k
        if (cp2 == NULL)
6617
19.3k
          value = format_expand1(es, cp);
6618
1.02k
        else {
6619
1.02k
          right = xstrndup(cp, cp2 - cp);
6620
1.02k
          value = format_expand1(es, right);
6621
1.02k
          free(right);
6622
1.02k
        }
6623
20.3k
        free(condition);
6624
20.3k
        free(found);
6625
20.3k
        break;
6626
20.3k
      } else {
6627
14.6k
        format_log(es, "condition '%s' is false",
6628
14.6k
            condition);
6629
14.6k
      }
6630
6631
14.6k
      free(condition);
6632
14.6k
      free(found);
6633
6634
14.6k
      if (cp2 == NULL) {
6635
9.36k
        format_log(es,
6636
9.36k
            "no condition matched in '%s'; using empty "
6637
9.36k
            "string", copy + 1);
6638
9.36k
        value = xstrdup("");
6639
9.36k
        break;
6640
9.36k
      }
6641
6642
5.24k
      cp = cp2 + 1;
6643
5.24k
    }
6644
2.38M
  } else if (mexp != NULL) {
6645
92.4k
    value = format_replace_expression(mexp, es, copy);
6646
92.4k
    if (value == NULL)
6647
76.0k
      value = xstrdup("");
6648
2.28M
  } else {
6649
2.28M
    if (strstr(copy, "#{") != 0) {
6650
363k
      format_log(es, "expanding inner format '%s'", copy);
6651
363k
      value = format_expand1(es, copy);
6652
1.92M
    } else {
6653
1.92M
      value = format_find(ft, copy, modifiers, time_format);
6654
1.92M
      if (value == NULL) {
6655
1.75M
        format_log(es, "format '%s' not found", copy);
6656
1.75M
        value = xstrdup("");
6657
1.75M
      } else {
6658
169k
        format_log(es, "format '%s' found: %s", copy,
6659
169k
            value);
6660
169k
      }
6661
1.92M
    }
6662
2.28M
  }
6663
6664
3.01M
done:
6665
  /* Expand again if required. */
6666
3.01M
  if (modifiers & FORMAT_EXPAND) {
6667
35.0k
    new = format_expand1(es, value);
6668
35.0k
    free(value);
6669
35.0k
    value = new;
6670
2.97M
  } else if (modifiers & FORMAT_EXPANDTIME) {
6671
5.04k
    format_copy_state(&next, es, FORMAT_EXPAND_TIME);
6672
5.04k
    new = format_expand1(&next, value);
6673
5.04k
    free(value);
6674
5.04k
    value = new;
6675
5.04k
  }
6676
6677
  /* Perform substitution if any. */
6678
3.01M
  for (i = 0; i < nsub; i++) {
6679
2.61k
    left = format_expand1(es, sub[i]->argv[0]);
6680
2.61k
    right = format_expand1(es, sub[i]->argv[1]);
6681
2.61k
    new = format_sub(sub[i], value, left, right);
6682
2.61k
    format_log(es, "substitute '%s' to '%s': %s", left, right, new);
6683
2.61k
    free(value);
6684
2.61k
    value = new;
6685
2.61k
    free(right);
6686
2.61k
    free(left);
6687
2.61k
  }
6688
6689
  /* Truncate the value if needed. */
6690
3.01M
  if (limit > 0) {
6691
3.46k
    new = format_trim_left(value, limit);
6692
3.46k
    if (marker != NULL && strcmp(new, value) != 0) {
6693
569
      free(value);
6694
569
      xasprintf(&value, "%s%s", new, marker);
6695
569
      free(new);
6696
2.89k
    } else {
6697
2.89k
      free(value);
6698
2.89k
      value = new;
6699
2.89k
    }
6700
3.46k
    format_log(es, "applied length limit %d: %s", limit, value);
6701
3.00M
  } else if (limit < 0) {
6702
3.21k
    new = format_trim_right(value, -limit);
6703
3.21k
    if (marker != NULL && strcmp(new, value) != 0) {
6704
1.04k
      free(value);
6705
1.04k
      xasprintf(&value, "%s%s", marker, new);
6706
1.04k
      free(new);
6707
2.16k
    } else {
6708
2.16k
      free(value);
6709
2.16k
      value = new;
6710
2.16k
    }
6711
3.21k
    format_log(es, "applied length limit %d: %s", limit, value);
6712
3.21k
  }
6713
6714
  /* Pad the value if needed. */
6715
3.01M
  if (width > 0) {
6716
15.0k
    new = utf8_padcstr(value, width);
6717
15.0k
    free(value);
6718
15.0k
    value = new;
6719
15.0k
    format_log(es, "applied padding width %d: %s", width, value);
6720
2.99M
  } else if (width < 0) {
6721
64.1k
    new = utf8_rpadcstr(value, -width);
6722
64.1k
    free(value);
6723
64.1k
    value = new;
6724
64.1k
    format_log(es, "applied padding width %d: %s", width, value);
6725
64.1k
  }
6726
6727
  /* Replace with the length or width if needed. */
6728
3.01M
  if (modifiers & FORMAT_LENGTH) {
6729
509
    xasprintf(&new, "%zu", strlen(value));
6730
509
    free(value);
6731
509
    value = new;
6732
509
    format_log(es, "replacing with length: %s", new);
6733
509
  }
6734
3.01M
  if (modifiers & FORMAT_WIDTH) {
6735
978
    xasprintf(&new, "%u", format_width(value));
6736
978
    free(value);
6737
978
    value = new;
6738
978
    format_log(es, "replacing with width: %s", new);
6739
978
  }
6740
6741
  /* Expand the buffer and copy in the value. */
6742
3.01M
  n = strlen(value);
6743
4.89M
  while (*len - *off < n + 1) {
6744
1.88M
    *buf = xreallocarray(*buf, 2, *len);
6745
1.88M
    *len *= 2;
6746
1.88M
  }
6747
3.01M
  memcpy(*buf + *off, value, n);
6748
3.01M
  *off += n;
6749
6750
3.01M
  format_log(es, "replaced '%s' with '%s'", copy0, value);
6751
3.01M
  free(value);
6752
6753
3.01M
  free(sub);
6754
3.01M
  format_free_modifiers(list, count);
6755
3.01M
  free(copy0);
6756
3.01M
  free(time_format);
6757
3.01M
  return (0);
6758
6759
34.2k
fail:
6760
34.2k
  format_log(es, "failed %s", copy0);
6761
6762
34.2k
  free(sub);
6763
34.2k
  format_free_modifiers(list, count);
6764
34.2k
  free(copy0);
6765
34.2k
  free(time_format);
6766
34.2k
  return (-1);
6767
2.97M
}
6768
6769
/* Expand keys in a template. */
6770
static char *
6771
format_expand1(struct format_expand_state *es, const char *fmt)
6772
4.03M
{
6773
4.03M
  struct format_tree  *ft = es->ft;
6774
4.03M
  char      *buf, *out, *name;
6775
4.03M
  const char    *ptr, *s, *style_end = NULL;
6776
4.03M
  size_t       off, len, n, outlen;
6777
4.03M
  int      ch, brackets;
6778
4.03M
  char       expanded[8192];
6779
6780
4.03M
  if (fmt == NULL || *fmt == '\0' || !format_check_time(es, NULL))
6781
612k
    return (xstrdup(""));
6782
6783
3.42M
  if (es->loop == FORMAT_LOOP_LIMIT) {
6784
21.9k
    format_log(es, "reached loop limit (%u)", FORMAT_LOOP_LIMIT);
6785
21.9k
    return (xstrdup(""));
6786
21.9k
  }
6787
3.39M
  es->loop++;
6788
6789
3.39M
  format_log(es, "expanding format: %s", fmt);
6790
6791
3.39M
  if ((es->flags & FORMAT_EXPAND_TIME) && strchr(fmt, '%') != NULL) {
6792
1.54k
    if (es->time == 0) {
6793
1.19k
      es->time = time(NULL);
6794
1.19k
      localtime_r(&es->time, &es->tm);
6795
1.19k
    }
6796
1.54k
    if (format_strftime(expanded, sizeof expanded, fmt,
6797
1.54k
        &es->tm) == 0) {
6798
199
      format_log(es, "format is too long");
6799
199
      return (xstrdup(""));
6800
199
    }
6801
1.34k
    if (format_logging(ft) && strcmp(expanded, fmt) != 0)
6802
0
      format_log(es, "after time expanded: %s", expanded);
6803
1.34k
    fmt = expanded;
6804
1.34k
  }
6805
6806
3.39M
  len = 64;
6807
3.39M
  buf = xmalloc(len);
6808
3.39M
  off = 0;
6809
6810
88.9M
  while (*fmt != '\0') {
6811
85.6M
    if (*fmt != '#') {
6812
77.5M
      while (len - off < 2) {
6813
171k
        buf = xreallocarray(buf, 2, len);
6814
171k
        len *= 2;
6815
171k
      }
6816
77.3M
      buf[off++] = *fmt++;
6817
77.3M
      continue;
6818
77.3M
    }
6819
8.32M
    if (*++fmt == '\0')
6820
10.8k
      break;
6821
6822
8.31M
    ch = (u_char)*fmt++;
6823
8.31M
    switch (ch) {
6824
27.4k
    case '(':
6825
27.4k
      brackets = 1;
6826
367k
      for (ptr = fmt; *ptr != '\0'; ptr++) {
6827
355k
        if (*ptr == '(')
6828
47.0k
          brackets++;
6829
355k
        if (*ptr == ')' && --brackets == 0)
6830
15.1k
          break;
6831
355k
      }
6832
27.4k
      if (*ptr != ')' || brackets != 0)
6833
12.2k
        break;
6834
15.1k
      n = ptr - fmt;
6835
6836
15.1k
      name = xstrndup(fmt, n);
6837
15.1k
      format_log(es, "found #(): %s", name);
6838
6839
15.1k
      if ((ft->flags & FORMAT_NOJOBS) ||
6840
15.1k
          (es->flags & FORMAT_EXPAND_NOJOBS)) {
6841
15.1k
        out = xstrdup("");
6842
15.1k
        format_log(es, "#() is disabled");
6843
15.1k
      } else {
6844
0
        out = format_job_get(es, name);
6845
0
        format_log(es, "#() result: %s", out);
6846
0
      }
6847
15.1k
      free(name);
6848
6849
15.1k
      outlen = strlen(out);
6850
15.1k
      while (len - off < outlen + 1) {
6851
0
        buf = xreallocarray(buf, 2, len);
6852
0
        len *= 2;
6853
0
      }
6854
15.1k
      memcpy(buf + off, out, outlen);
6855
15.1k
      off += outlen;
6856
6857
15.1k
      free(out);
6858
6859
15.1k
      fmt += n + 1;
6860
15.1k
      continue;
6861
1.78M
    case '{':
6862
1.78M
      ptr = format_skip1(es, (char *)fmt - 2, "}");
6863
1.78M
      if (ptr == NULL)
6864
952
        break;
6865
1.77M
      n = ptr - fmt;
6866
6867
1.77M
      format_log(es, "found #{}: %.*s", (int)n, fmt);
6868
1.77M
      if (format_replace(es, fmt, n, &buf, &len, &off) != 0)
6869
34.2k
        break;
6870
1.74M
      fmt += n + 1;
6871
1.74M
      continue;
6872
339k
    case '[':
6873
3.77M
    case '#':
6874
      /*
6875
       * If ##[ (with two or more #s), then it is a style and
6876
       * can be left for format_draw to handle.
6877
       */
6878
3.77M
      ptr = fmt - (ch == '[');
6879
3.77M
      n = 2 - (ch == '[');
6880
4.77M
      while (*ptr == '#') {
6881
996k
        ptr++;
6882
996k
        n++;
6883
996k
      }
6884
3.77M
      if (*ptr == '[') {
6885
1.33M
        style_end = format_skip1(es, fmt - 2, "]");
6886
1.33M
        format_log(es, "found #*%zu[", n);
6887
1.34M
        while (len - off < n + 2) {
6888
5.22k
          buf = xreallocarray(buf, 2, len);
6889
5.22k
          len *= 2;
6890
5.22k
        }
6891
1.33M
        memcpy(buf + off, fmt - 2, n + 1);
6892
1.33M
        off += n + 1;
6893
1.33M
        fmt = ptr + 1;
6894
1.33M
        continue;
6895
1.33M
      }
6896
2.43M
      if (ch == '#') {
6897
2.43M
        while (len - off < (n / 2) + 1) {
6898
1.76k
          buf = xreallocarray(buf, 2, len);
6899
1.76k
          len *= 2;
6900
1.76k
        }
6901
2.43M
        memset(buf + off, '#', n / 2);
6902
2.43M
        off += (n / 2);
6903
2.43M
        if (n % 2 != 0)
6904
47.3k
          fmt = ptr - 1;
6905
2.38M
        else
6906
2.38M
          fmt = ptr;
6907
2.43M
        continue;
6908
2.43M
      }
6909
      /* FALLTHROUGH */
6910
34.5k
    case '}':
6911
44.9k
    case ',':
6912
44.9k
      format_log(es, "found #%c", ch);
6913
44.9k
      while (len - off < 2) {
6914
0
        buf = xreallocarray(buf, 2, len);
6915
0
        len *= 2;
6916
0
      }
6917
44.9k
      buf[off++] = ch;
6918
44.9k
      continue;
6919
2.68M
    default:
6920
2.68M
      s = NULL;
6921
2.68M
      if (fmt > style_end) { /* skip inside #[] */
6922
2.64M
        if (ch >= 'A' && ch <= 'Z')
6923
1.31M
          s = format_upper[ch - 'A'];
6924
1.33M
        else if (ch >= 'a' && ch <= 'z')
6925
290k
          s = format_lower[ch - 'a'];
6926
2.64M
      }
6927
2.68M
      if (s == NULL) {
6928
1.42M
        while (len - off < 3) {
6929
3.39k
          buf = xreallocarray(buf, 2, len);
6930
3.39k
          len *= 2;
6931
3.39k
        }
6932
1.41M
        buf[off++] = '#';
6933
1.41M
        buf[off++] = ch;
6934
1.41M
        continue;
6935
1.41M
      }
6936
1.26M
      n = strlen(s);
6937
1.26M
      format_log(es, "found #%c: %s", ch, s);
6938
1.26M
      if (format_replace(es, s, n, &buf, &len, &off) != 0)
6939
0
        break;
6940
1.26M
      continue;
6941
8.31M
    }
6942
6943
47.4k
    break;
6944
8.31M
  }
6945
3.39M
  buf[off] = '\0';
6946
6947
3.39M
  format_log(es, "result is: %s", buf);
6948
3.39M
  es->loop--;
6949
6950
3.39M
  return (buf);
6951
3.39M
}
6952
6953
/* Expand keys in a template, passing through strftime first. */
6954
char *
6955
format_expand_time(struct format_tree *ft, const char *fmt)
6956
0
{
6957
0
  struct format_expand_state  es;
6958
6959
0
  memset(&es, 0, sizeof es);
6960
0
  es.ft = ft;
6961
0
  es.flags = FORMAT_EXPAND_TIME;
6962
0
  es.start_time = get_timer();
6963
0
  return (format_expand1(&es, fmt));
6964
0
}
6965
6966
/* Expand keys in a template. */
6967
char *
6968
format_expand(struct format_tree *ft, const char *fmt)
6969
11.5k
{
6970
11.5k
  struct format_expand_state  es;
6971
6972
11.5k
  memset(&es, 0, sizeof es);
6973
11.5k
  es.ft = ft;
6974
11.5k
  es.flags = 0;
6975
11.5k
  es.start_time = get_timer();
6976
11.5k
  return (format_expand1(&es, fmt));
6977
11.5k
}
6978
6979
/* Expand a single string. */
6980
char *
6981
format_single(struct cmdq_item *item, const char *fmt, struct client *c,
6982
    struct session *s, struct winlink *wl, struct window_pane *wp)
6983
0
{
6984
0
  struct format_tree  *ft;
6985
0
  char      *expanded;
6986
6987
0
  ft = format_create_defaults(item, c, s, wl, wp);
6988
0
  expanded = format_expand(ft, fmt);
6989
0
  format_free(ft);
6990
0
  return (expanded);
6991
0
}
6992
6993
/* Expand a single string using state. */
6994
char *
6995
format_single_from_state(struct cmdq_item *item, const char *fmt,
6996
    struct client *c, struct cmd_find_state *fs)
6997
0
{
6998
0
  return (format_single(item, fmt, c, fs->s, fs->wl, fs->wp));
6999
0
}
7000
7001
/* Expand a single string using target. */
7002
char *
7003
format_single_from_target(struct cmdq_item *item, const char *fmt)
7004
0
{
7005
0
  struct client *tc = cmdq_get_target_client(item);
7006
7007
0
  return (format_single_from_state(item, fmt, tc, cmdq_get_target(item)));
7008
0
}
7009
7010
/* Create and add defaults. */
7011
struct format_tree *
7012
format_create_defaults(struct cmdq_item *item, struct client *c,
7013
    struct session *s, struct winlink *wl, struct window_pane *wp)
7014
0
{
7015
0
  struct format_tree  *ft;
7016
7017
0
  if (item != NULL)
7018
0
    ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
7019
0
  else
7020
0
    ft = format_create(NULL, item, FORMAT_NONE, 0);
7021
0
  format_defaults(ft, c, s, wl, wp);
7022
0
  return (ft);
7023
0
}
7024
7025
/* Create and add defaults using state. */
7026
struct format_tree *
7027
format_create_from_state(struct cmdq_item *item, struct client *c,
7028
    struct cmd_find_state *fs)
7029
0
{
7030
0
  return (format_create_defaults(item, c, fs->s, fs->wl, fs->wp));
7031
0
}
7032
7033
/* Create and add defaults using target. */
7034
struct format_tree *
7035
format_create_from_target(struct cmdq_item *item)
7036
0
{
7037
0
  struct client *tc = cmdq_get_target_client(item);
7038
7039
0
  return (format_create_from_state(item, tc, cmdq_get_target(item)));
7040
0
}
7041
7042
/* Set defaults for any of arguments that are not NULL. */
7043
void
7044
format_defaults(struct format_tree *ft, struct client *c, struct session *s,
7045
    struct winlink *wl, struct window_pane *wp)
7046
1.83M
{
7047
1.83M
  struct paste_buffer *pb;
7048
7049
1.83M
  if (c != NULL && c->name != NULL)
7050
0
    log_debug("%s: c=%s", __func__, c->name);
7051
1.83M
  else
7052
1.83M
    log_debug("%s: c=none", __func__);
7053
1.83M
  if (s != NULL)
7054
0
    log_debug("%s: s=$%u", __func__, s->id);
7055
1.83M
  else
7056
1.83M
    log_debug("%s: s=none", __func__);
7057
1.83M
  if (wl != NULL)
7058
0
    log_debug("%s: wl=%u", __func__, wl->idx);
7059
1.83M
  else
7060
1.83M
    log_debug("%s: wl=none", __func__);
7061
1.83M
  if (wp != NULL)
7062
0
    log_debug("%s: wp=%%%u", __func__, wp->id);
7063
1.83M
  else
7064
1.83M
    log_debug("%s: wp=none", __func__);
7065
7066
1.83M
  if (c != NULL && s != NULL && c->session != s)
7067
0
    log_debug("%s: session does not match", __func__);
7068
7069
1.83M
  if (wp != NULL)
7070
0
    ft->type = FORMAT_TYPE_PANE;
7071
1.83M
  else if (wl != NULL)
7072
0
    ft->type = FORMAT_TYPE_WINDOW;
7073
1.83M
  else if (s != NULL)
7074
0
    ft->type = FORMAT_TYPE_SESSION;
7075
1.83M
  else
7076
1.83M
    ft->type = FORMAT_TYPE_UNKNOWN;
7077
7078
1.83M
  if (s == NULL && c != NULL)
7079
0
    s = c->session;
7080
1.83M
  if (wl == NULL && s != NULL)
7081
0
    wl = s->curw;
7082
1.83M
  if (wp == NULL && wl != NULL)
7083
0
    wp = wl->window->active;
7084
7085
1.83M
  if (c != NULL)
7086
0
    format_defaults_client(ft, c);
7087
1.83M
  if (s != NULL)
7088
0
    format_defaults_session(ft, s);
7089
1.83M
  if (wl != NULL)
7090
0
    format_defaults_winlink(ft, wl);
7091
1.83M
  if (wp != NULL)
7092
0
    format_defaults_pane(ft, wp);
7093
7094
1.83M
  pb = paste_get_top(NULL);
7095
1.83M
  if (pb != NULL)
7096
0
    format_defaults_paste_buffer(ft, pb);
7097
1.83M
}
7098
7099
/* Set default format keys for a session. */
7100
static void
7101
format_defaults_session(struct format_tree *ft, struct session *s)
7102
0
{
7103
0
  ft->s = s;
7104
0
}
7105
7106
/* Set default format keys for a client. */
7107
static void
7108
format_defaults_client(struct format_tree *ft, struct client *c)
7109
0
{
7110
0
  if (ft->s == NULL)
7111
0
    ft->s = c->session;
7112
0
  ft->c = c;
7113
0
}
7114
7115
/* Set default format keys for a window. */
7116
void
7117
format_defaults_window(struct format_tree *ft, struct window *w)
7118
0
{
7119
0
  ft->w = w;
7120
0
}
7121
7122
/* Set default format keys for a winlink. */
7123
static void
7124
format_defaults_winlink(struct format_tree *ft, struct winlink *wl)
7125
0
{
7126
0
  if (ft->w == NULL)
7127
0
    format_defaults_window(ft, wl->window);
7128
0
  ft->wl = wl;
7129
0
}
7130
7131
/* Set default format keys for a window pane. */
7132
void
7133
format_defaults_pane(struct format_tree *ft, struct window_pane *wp)
7134
0
{
7135
0
  struct window_mode_entry  *wme;
7136
7137
0
  if (ft->w == NULL)
7138
0
    format_defaults_window(ft, wp->window);
7139
0
  ft->wp = wp;
7140
7141
0
  wme = TAILQ_FIRST(&wp->modes);
7142
0
  if (wme != NULL && wme->mode->formats != NULL)
7143
0
    wme->mode->formats(wme, ft);
7144
0
}
7145
7146
/* Set default format keys for paste buffer. */
7147
void
7148
format_defaults_paste_buffer(struct format_tree *ft, struct paste_buffer *pb)
7149
0
{
7150
0
  ft->pb = pb;
7151
0
}
7152
7153
static int
7154
format_is_word_separator(const char *ws, const struct grid_cell *gc)
7155
0
{
7156
0
  if (utf8_cstrhas(ws, &gc->data))
7157
0
    return (1);
7158
0
  if (gc->flags & GRID_FLAG_TAB)
7159
0
    return (1);
7160
0
  return gc->data.size == 1 && *gc->data.data == ' ';
7161
0
}
7162
7163
/* Return word at given coordinates. Caller frees. */
7164
char *
7165
format_grid_word(struct grid *gd, u_int x, u_int y)
7166
0
{
7167
0
  const struct grid_line  *gl;
7168
0
  struct grid_cell   gc;
7169
0
  const char    *ws;
7170
0
  struct utf8_data  *ud = NULL;
7171
0
  u_int      end;
7172
0
  size_t       size = 0;
7173
0
  int      found = 0;
7174
0
  char      *s = NULL;
7175
7176
0
  ws = options_get_string(global_s_options, "word-separators");
7177
7178
0
  for (;;) {
7179
0
    grid_get_cell(gd, x, y, &gc);
7180
0
    if ((~gc.flags & GRID_FLAG_PADDING) &&
7181
0
        format_is_word_separator(ws, &gc)) {
7182
0
      found = 1;
7183
0
      break;
7184
0
    }
7185
7186
0
    if (x == 0) {
7187
0
      if (y == 0)
7188
0
        break;
7189
0
      gl = grid_peek_line(gd, y - 1);
7190
0
      if (~gl->flags & GRID_LINE_WRAPPED)
7191
0
        break;
7192
0
      y--;
7193
0
      x = grid_line_length(gd, y);
7194
0
      if (x == 0)
7195
0
        break;
7196
0
    }
7197
0
    x--;
7198
0
  }
7199
0
  for (;;) {
7200
0
    if (found) {
7201
0
      end = grid_line_length(gd, y);
7202
0
      if (end == 0 || x == end - 1) {
7203
0
        if (y == gd->hsize + gd->sy - 1)
7204
0
          break;
7205
0
        gl = grid_peek_line(gd, y);
7206
0
        if (~gl->flags & GRID_LINE_WRAPPED)
7207
0
          break;
7208
0
        y++;
7209
0
        x = 0;
7210
0
      } else
7211
0
        x++;
7212
0
    }
7213
0
    found = 1;
7214
7215
0
    grid_get_cell(gd, x, y, &gc);
7216
0
    if (gc.flags & GRID_FLAG_PADDING)
7217
0
      continue;
7218
0
    if (format_is_word_separator(ws, &gc))
7219
0
      break;
7220
7221
0
    ud = xreallocarray(ud, size + 2, sizeof *ud);
7222
0
    memcpy(&ud[size++], &gc.data, sizeof *ud);
7223
0
  }
7224
0
  if (size != 0) {
7225
0
    ud[size].size = 0;
7226
0
    s = utf8_tocstr(ud);
7227
0
    free(ud);
7228
0
  }
7229
0
  return (s);
7230
0
}
7231
7232
/* Return line at given coordinates. Caller frees. */
7233
char *
7234
format_grid_line(struct grid *gd, u_int y)
7235
0
{
7236
0
  struct grid_cell   gc;
7237
0
  struct utf8_data  *ud = NULL;
7238
0
  u_int      x;
7239
0
  size_t       size = 0;
7240
0
  char      *s = NULL;
7241
7242
0
  for (x = 0; x < grid_line_length(gd, y); x++) {
7243
0
    grid_get_cell(gd, x, y, &gc);
7244
0
    if (gc.flags & GRID_FLAG_PADDING)
7245
0
      continue;
7246
7247
0
    ud = xreallocarray(ud, size + 2, sizeof *ud);
7248
0
    if (gc.flags & GRID_FLAG_TAB)
7249
0
      utf8_set(&ud[size++], '\t');
7250
0
    else
7251
0
      memcpy(&ud[size++], &gc.data, sizeof *ud);
7252
0
  }
7253
0
  if (size != 0) {
7254
0
    ud[size].size = 0;
7255
0
    s = utf8_tocstr(ud);
7256
0
    free(ud);
7257
0
  }
7258
0
  return (s);
7259
0
}
7260
7261
/* Return hyperlink at given coordinates. Caller frees. */
7262
char *
7263
format_grid_hyperlink(struct grid *gd, u_int x, u_int y, struct screen* s)
7264
0
{
7265
0
  const char    *uri;
7266
0
  struct grid_cell   gc;
7267
7268
0
  for (;;) {
7269
0
    grid_get_cell(gd, x, y, &gc);
7270
0
    if (~gc.flags & GRID_FLAG_PADDING)
7271
0
      break;
7272
0
    if (x == 0)
7273
0
      return (NULL);
7274
0
    x--;
7275
0
  }
7276
0
  if (s->hyperlinks == NULL || gc.link == 0)
7277
0
    return (NULL);
7278
0
  if (!hyperlinks_get(s->hyperlinks, gc.link, &uri, NULL, NULL))
7279
0
    return (NULL);
7280
0
  return (xstrdup(uri));
7281
0
}