Coverage Report

Created: 2025-08-09 06:27

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