Coverage Report

Created: 2026-06-10 06:31

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