Coverage Report

Created: 2025-11-20 06:28

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