Coverage Report

Created: 2026-07-30 07:06

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