Coverage Report

Created: 2026-05-30 06:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tmux/input.c
Line
Count
Source
1
/* $OpenBSD$ */
2
3
/*
4
 * Copyright (c) 2007 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
21
#include <netinet/in.h>
22
23
#include <ctype.h>
24
#include <resolv.h>
25
#include <stdlib.h>
26
#include <string.h>
27
#include <time.h>
28
29
#include "tmux.h"
30
31
/*
32
 * Based on the description by Paul Williams at:
33
 *
34
 * https://vt100.net/emu/dec_ansi_parser
35
 *
36
 * With the following changes:
37
 *
38
 * - 7-bit only.
39
 *
40
 * - Support for UTF-8.
41
 *
42
 * - OSC (but not APC) may be terminated by \007 as well as ST.
43
 *
44
 * - A state for APC similar to OSC. Some terminals appear to use this to set
45
 *   the title.
46
 *
47
 * - A state for the screen \033k...\033\\ sequence to rename a window. This is
48
 *   pretty stupid but not supporting it is more trouble than it is worth.
49
 *
50
 * - Special handling for ESC inside a DCS to allow arbitrary byte sequences to
51
 *   be passed to the underlying terminals.
52
 */
53
54
/* Type of terminator. */
55
enum input_end_type {
56
  INPUT_END_ST,
57
  INPUT_END_BEL
58
};
59
60
/* Request sent by a pane. */
61
struct input_request {
62
  struct client     *c;
63
  struct input_ctx    *ictx;
64
65
  enum input_request_type    type;
66
  uint64_t       t;
67
  enum input_end_type              end;
68
69
  int        idx;
70
  void        *data;
71
72
  TAILQ_ENTRY(input_request)   entry;
73
  TAILQ_ENTRY(input_request)   centry;
74
};
75
0
#define INPUT_REQUEST_TIMEOUT 500
76
77
/* Input parser cell. */
78
struct input_cell {
79
  struct grid_cell  cell;
80
  int     set;
81
  int     g0set;  /* 1 if ACS */
82
  int     g1set;  /* 1 if ACS */
83
};
84
85
/* Input parser argument. */
86
struct input_param {
87
  enum {
88
    INPUT_MISSING,
89
    INPUT_NUMBER,
90
    INPUT_STRING
91
  }     type;
92
  union {
93
    int   num;
94
    char         *str;
95
  };
96
};
97
98
/* Input parser context. */
99
struct input_ctx {
100
  struct window_pane         *wp;
101
  struct bufferevent         *event;
102
  struct screen_write_ctx   ctx;
103
  struct colour_palette        *palette;
104
  struct client          *c;
105
106
  struct input_cell   cell;
107
  struct input_cell   old_cell;
108
  u_int       old_cx;
109
  u_int       old_cy;
110
  int       old_mode;
111
112
  u_char        interm_buf[4];
113
  size_t        interm_len;
114
115
  u_char        param_buf[64];
116
  size_t        param_len;
117
118
78.0k
#define INPUT_BUF_START 32
119
  u_char             *input_buf;
120
  size_t        input_len;
121
  size_t        input_space;
122
  enum input_end_type   input_end;
123
124
  struct input_param    param_list[24];
125
  u_int       param_list_len;
126
127
  struct utf8_data    utf8data;
128
  int       utf8started;
129
130
  int       ch;
131
  struct utf8_data    last;
132
133
  const struct input_state       *state;
134
  int       flags;
135
232k
#define INPUT_DISCARD 0x1
136
125k
#define INPUT_LAST 0x2
137
138
  struct input_requests    requests;
139
  u_int        request_count;
140
  struct event       request_timer;
141
142
  /*
143
   * All input received since we were last in the ground state. Sent to
144
   * control clients on connection.
145
   */
146
  struct evbuffer     *since_ground;
147
  struct event       ground_timer;
148
};
149
150
/* Helper functions. */
151
struct input_transition;
152
static void   input_request_timer_callback(int, short, void *);
153
static void input_start_request_timer(struct input_ctx *);
154
static struct input_request *input_make_request(struct input_ctx *,
155
        enum input_request_type);
156
static void input_free_request(struct input_request *);
157
static int  input_add_request(struct input_ctx *, enum input_request_type,
158
        int);
159
static int  input_split(struct input_ctx *);
160
static int  input_get(struct input_ctx *, u_int, int, int);
161
static void input_set_state(struct input_ctx *,
162
        const struct input_transition *);
163
static void input_reset_cell(struct input_ctx *);
164
static void input_report_current_theme(struct input_ctx *);
165
static void input_osc_4(struct input_ctx *, const char *);
166
static void input_osc_8(struct input_ctx *, const char *);
167
static void input_osc_9(struct input_ctx *, const char *);
168
static void input_osc_10(struct input_ctx *, const char *);
169
static void input_osc_11(struct input_ctx *, const char *);
170
static void input_osc_12(struct input_ctx *, const char *);
171
static void input_osc_52(struct input_ctx *, const char *);
172
static void input_osc_104(struct input_ctx *, const char *);
173
static void input_osc_110(struct input_ctx *, const char *);
174
static void input_osc_111(struct input_ctx *, const char *);
175
static void input_osc_112(struct input_ctx *, const char *);
176
static void input_osc_133(struct input_ctx *, const char *);
177
178
/* Transition entry/exit handlers. */
179
static void input_clear(struct input_ctx *);
180
static void input_ground(struct input_ctx *);
181
static void input_enter_dcs(struct input_ctx *);
182
static void input_enter_osc(struct input_ctx *);
183
static void input_exit_osc(struct input_ctx *);
184
static void input_enter_apc(struct input_ctx *);
185
static void input_exit_apc(struct input_ctx *);
186
static void input_enter_rename(struct input_ctx *);
187
static void input_exit_rename(struct input_ctx *);
188
189
/* Input state handlers. */
190
static int  input_print(struct input_ctx *);
191
static int  input_intermediate(struct input_ctx *);
192
static int  input_parameter(struct input_ctx *);
193
static int  input_input(struct input_ctx *);
194
static int  input_c0_dispatch(struct input_ctx *);
195
static int  input_esc_dispatch(struct input_ctx *);
196
static int  input_csi_dispatch(struct input_ctx *);
197
static void input_csi_dispatch_rm(struct input_ctx *);
198
static void input_csi_dispatch_rm_private(struct input_ctx *);
199
static void input_csi_dispatch_sm(struct input_ctx *);
200
static void input_csi_dispatch_sm_private(struct input_ctx *);
201
static void input_csi_dispatch_sm_graphics(struct input_ctx *);
202
static void input_csi_dispatch_winops(struct input_ctx *);
203
static void input_csi_dispatch_sgr_256(struct input_ctx *, int, u_int *);
204
static void input_csi_dispatch_sgr_rgb(struct input_ctx *, int, u_int *);
205
static void input_csi_dispatch_sgr(struct input_ctx *);
206
static int  input_dcs_dispatch(struct input_ctx *);
207
static int  input_top_bit_set(struct input_ctx *);
208
static int  input_end_bel(struct input_ctx *);
209
210
/* Command table comparison function. */
211
static int  input_table_compare(const void *, const void *);
212
213
/* Command table entry. */
214
struct input_table_entry {
215
  int   ch;
216
  const char     *interm;
217
  int   type;
218
};
219
220
/* Escape commands. */
221
enum input_esc_type {
222
  INPUT_ESC_DECALN,
223
  INPUT_ESC_DECKPAM,
224
  INPUT_ESC_DECKPNM,
225
  INPUT_ESC_DECRC,
226
  INPUT_ESC_DECSC,
227
  INPUT_ESC_HTS,
228
  INPUT_ESC_IND,
229
  INPUT_ESC_NEL,
230
  INPUT_ESC_RI,
231
  INPUT_ESC_RIS,
232
  INPUT_ESC_SCSG0_OFF,
233
  INPUT_ESC_SCSG0_ON,
234
  INPUT_ESC_SCSG1_OFF,
235
  INPUT_ESC_SCSG1_ON,
236
  INPUT_ESC_ST
237
};
238
239
/* Escape command table. */
240
static const struct input_table_entry input_esc_table[] = {
241
  { '0', "(", INPUT_ESC_SCSG0_ON },
242
  { '0', ")", INPUT_ESC_SCSG1_ON },
243
  { '7', "",  INPUT_ESC_DECSC },
244
  { '8', "",  INPUT_ESC_DECRC },
245
  { '8', "#", INPUT_ESC_DECALN },
246
  { '=', "",  INPUT_ESC_DECKPAM },
247
  { '>', "",  INPUT_ESC_DECKPNM },
248
  { 'B', "(", INPUT_ESC_SCSG0_OFF },
249
  { 'B', ")", INPUT_ESC_SCSG1_OFF },
250
  { 'D', "",  INPUT_ESC_IND },
251
  { 'E', "",  INPUT_ESC_NEL },
252
  { 'H', "",  INPUT_ESC_HTS },
253
  { 'M', "",  INPUT_ESC_RI },
254
  { '\\', "", INPUT_ESC_ST },
255
  { 'c', "",  INPUT_ESC_RIS },
256
};
257
258
/* Control (CSI) commands. */
259
enum input_csi_type {
260
  INPUT_CSI_CBT,
261
  INPUT_CSI_CNL,
262
  INPUT_CSI_CPL,
263
  INPUT_CSI_CUB,
264
  INPUT_CSI_CUD,
265
  INPUT_CSI_CUF,
266
  INPUT_CSI_CUP,
267
  INPUT_CSI_CUU,
268
  INPUT_CSI_DA,
269
  INPUT_CSI_DA_TWO,
270
  INPUT_CSI_DCH,
271
  INPUT_CSI_DECSCUSR,
272
  INPUT_CSI_DECSTBM,
273
  INPUT_CSI_DL,
274
  INPUT_CSI_DSR,
275
  INPUT_CSI_DSR_PRIVATE,
276
  INPUT_CSI_ECH,
277
  INPUT_CSI_ED,
278
  INPUT_CSI_EL,
279
  INPUT_CSI_HPA,
280
  INPUT_CSI_ICH,
281
  INPUT_CSI_IL,
282
  INPUT_CSI_MODOFF,
283
  INPUT_CSI_MODSET,
284
  INPUT_CSI_QUERY_PRIVATE,
285
  INPUT_CSI_RCP,
286
  INPUT_CSI_REP,
287
  INPUT_CSI_RM,
288
  INPUT_CSI_RM_PRIVATE,
289
  INPUT_CSI_SCP,
290
  INPUT_CSI_SD,
291
  INPUT_CSI_SGR,
292
  INPUT_CSI_SM,
293
  INPUT_CSI_SM_GRAPHICS,
294
  INPUT_CSI_SM_PRIVATE,
295
  INPUT_CSI_SU,
296
  INPUT_CSI_TBC,
297
  INPUT_CSI_VPA,
298
  INPUT_CSI_WINOPS,
299
  INPUT_CSI_XDA
300
};
301
302
/* Control (CSI) command table. */
303
static const struct input_table_entry input_csi_table[] = {
304
  { '@', "",  INPUT_CSI_ICH },
305
  { 'A', "",  INPUT_CSI_CUU },
306
  { 'B', "",  INPUT_CSI_CUD },
307
  { 'C', "",  INPUT_CSI_CUF },
308
  { 'D', "",  INPUT_CSI_CUB },
309
  { 'E', "",  INPUT_CSI_CNL },
310
  { 'F', "",  INPUT_CSI_CPL },
311
  { 'G', "",  INPUT_CSI_HPA },
312
  { 'H', "",  INPUT_CSI_CUP },
313
  { 'J', "",  INPUT_CSI_ED },
314
  { 'K', "",  INPUT_CSI_EL },
315
  { 'L', "",  INPUT_CSI_IL },
316
  { 'M', "",  INPUT_CSI_DL },
317
  { 'P', "",  INPUT_CSI_DCH },
318
  { 'S', "",  INPUT_CSI_SU },
319
  { 'S', "?", INPUT_CSI_SM_GRAPHICS },
320
  { 'T', "",  INPUT_CSI_SD },
321
  { 'X', "",  INPUT_CSI_ECH },
322
  { 'Z', "",  INPUT_CSI_CBT },
323
  { '`', "",  INPUT_CSI_HPA },
324
  { 'b', "",  INPUT_CSI_REP },
325
  { 'c', "",  INPUT_CSI_DA },
326
  { 'c', ">", INPUT_CSI_DA_TWO },
327
  { 'd', "",  INPUT_CSI_VPA },
328
  { 'f', "",  INPUT_CSI_CUP },
329
  { 'g', "",  INPUT_CSI_TBC },
330
  { 'h', "",  INPUT_CSI_SM },
331
  { 'h', "?", INPUT_CSI_SM_PRIVATE },
332
  { 'l', "",  INPUT_CSI_RM },
333
  { 'l', "?", INPUT_CSI_RM_PRIVATE },
334
  { 'm', "",  INPUT_CSI_SGR },
335
  { 'm', ">", INPUT_CSI_MODSET },
336
  { 'n', "",  INPUT_CSI_DSR },
337
  { 'n', ">", INPUT_CSI_MODOFF },
338
  { 'n', "?", INPUT_CSI_DSR_PRIVATE },
339
  { 'p', "?$", INPUT_CSI_QUERY_PRIVATE },
340
  { 'q', " ", INPUT_CSI_DECSCUSR },
341
  { 'q', ">", INPUT_CSI_XDA },
342
  { 'r', "",  INPUT_CSI_DECSTBM },
343
  { 's', "",  INPUT_CSI_SCP },
344
  { 't', "",  INPUT_CSI_WINOPS },
345
  { 'u', "",  INPUT_CSI_RCP }
346
};
347
348
/* Input transition. */
349
struct input_transition {
350
  int       first;
351
  int       last;
352
353
  int       (*handler)(struct input_ctx *);
354
  const struct input_state       *state;
355
};
356
357
/* Input state. */
358
struct input_state {
359
  const char      *name;
360
  void        (*enter)(struct input_ctx *);
361
  void        (*exit)(struct input_ctx *);
362
  const struct input_transition *transitions;
363
};
364
365
/* State transitions available from all states. */
366
#define INPUT_STATE_ANYWHERE \
367
  { 0x18, 0x18, input_c0_dispatch, &input_state_ground }, \
368
  { 0x1a, 0x1a, input_c0_dispatch, &input_state_ground }, \
369
  { 0x1b, 0x1b, NULL,    &input_state_esc_enter }
370
371
/* Forward declarations of state tables. */
372
static const struct input_transition input_state_ground_table[];
373
static const struct input_transition input_state_esc_enter_table[];
374
static const struct input_transition input_state_esc_intermediate_table[];
375
static const struct input_transition input_state_csi_enter_table[];
376
static const struct input_transition input_state_csi_parameter_table[];
377
static const struct input_transition input_state_csi_intermediate_table[];
378
static const struct input_transition input_state_csi_ignore_table[];
379
static const struct input_transition input_state_dcs_enter_table[];
380
static const struct input_transition input_state_dcs_parameter_table[];
381
static const struct input_transition input_state_dcs_intermediate_table[];
382
static const struct input_transition input_state_dcs_handler_table[];
383
static const struct input_transition input_state_dcs_escape_table[];
384
static const struct input_transition input_state_dcs_ignore_table[];
385
static const struct input_transition input_state_osc_string_table[];
386
static const struct input_transition input_state_apc_string_table[];
387
static const struct input_transition input_state_rename_string_table[];
388
static const struct input_transition input_state_consume_st_table[];
389
390
/* ground state definition. */
391
static const struct input_state input_state_ground = {
392
  "ground",
393
  input_ground, NULL,
394
  input_state_ground_table
395
};
396
397
/* esc_enter state definition. */
398
static const struct input_state input_state_esc_enter = {
399
  "esc_enter",
400
  input_clear, NULL,
401
  input_state_esc_enter_table
402
};
403
404
/* esc_intermediate state definition. */
405
static const struct input_state input_state_esc_intermediate = {
406
  "esc_intermediate",
407
  NULL, NULL,
408
  input_state_esc_intermediate_table
409
};
410
411
/* csi_enter state definition. */
412
static const struct input_state input_state_csi_enter = {
413
  "csi_enter",
414
  input_clear, NULL,
415
  input_state_csi_enter_table
416
};
417
418
/* csi_parameter state definition. */
419
static const struct input_state input_state_csi_parameter = {
420
  "csi_parameter",
421
  NULL, NULL,
422
  input_state_csi_parameter_table
423
};
424
425
/* csi_intermediate state definition. */
426
static const struct input_state input_state_csi_intermediate = {
427
  "csi_intermediate",
428
  NULL, NULL,
429
  input_state_csi_intermediate_table
430
};
431
432
/* csi_ignore state definition. */
433
static const struct input_state input_state_csi_ignore = {
434
  "csi_ignore",
435
  NULL, NULL,
436
  input_state_csi_ignore_table
437
};
438
439
/* dcs_enter state definition. */
440
static const struct input_state input_state_dcs_enter = {
441
  "dcs_enter",
442
  input_enter_dcs, NULL,
443
  input_state_dcs_enter_table
444
};
445
446
/* dcs_parameter state definition. */
447
static const struct input_state input_state_dcs_parameter = {
448
  "dcs_parameter",
449
  NULL, NULL,
450
  input_state_dcs_parameter_table
451
};
452
453
/* dcs_intermediate state definition. */
454
static const struct input_state input_state_dcs_intermediate = {
455
  "dcs_intermediate",
456
  NULL, NULL,
457
  input_state_dcs_intermediate_table
458
};
459
460
/* dcs_handler state definition. */
461
static const struct input_state input_state_dcs_handler = {
462
  "dcs_handler",
463
  NULL, NULL,
464
  input_state_dcs_handler_table
465
};
466
467
/* dcs_escape state definition. */
468
static const struct input_state input_state_dcs_escape = {
469
  "dcs_escape",
470
  NULL, NULL,
471
  input_state_dcs_escape_table
472
};
473
474
/* dcs_ignore state definition. */
475
static const struct input_state input_state_dcs_ignore = {
476
  "dcs_ignore",
477
  NULL, NULL,
478
  input_state_dcs_ignore_table
479
};
480
481
/* osc_string state definition. */
482
static const struct input_state input_state_osc_string = {
483
  "osc_string",
484
  input_enter_osc, input_exit_osc,
485
  input_state_osc_string_table
486
};
487
488
/* apc_string state definition. */
489
static const struct input_state input_state_apc_string = {
490
  "apc_string",
491
  input_enter_apc, input_exit_apc,
492
  input_state_apc_string_table
493
};
494
495
/* rename_string state definition. */
496
static const struct input_state input_state_rename_string = {
497
  "rename_string",
498
  input_enter_rename, input_exit_rename,
499
  input_state_rename_string_table
500
};
501
502
/* consume_st state definition. */
503
static const struct input_state input_state_consume_st = {
504
  "consume_st",
505
  input_enter_rename, NULL, /* rename also waits for ST */
506
  input_state_consume_st_table
507
};
508
509
/* ground state table. */
510
static const struct input_transition input_state_ground_table[] = {
511
  INPUT_STATE_ANYWHERE,
512
513
  { 0x00, 0x17, input_c0_dispatch, NULL },
514
  { 0x19, 0x19, input_c0_dispatch, NULL },
515
  { 0x1c, 0x1f, input_c0_dispatch, NULL },
516
  { 0x20, 0x7e, input_print,   NULL },
517
  { 0x7f, 0x7f, NULL,    NULL },
518
  { 0x80, 0xff, input_top_bit_set, NULL },
519
520
  { -1, -1, NULL, NULL }
521
};
522
523
/* esc_enter state table. */
524
static const struct input_transition input_state_esc_enter_table[] = {
525
  INPUT_STATE_ANYWHERE,
526
527
  { 0x00, 0x17, input_c0_dispatch,  NULL },
528
  { 0x19, 0x19, input_c0_dispatch,  NULL },
529
  { 0x1c, 0x1f, input_c0_dispatch,  NULL },
530
  { 0x20, 0x2f, input_intermediate, &input_state_esc_intermediate },
531
  { 0x30, 0x4f, input_esc_dispatch, &input_state_ground },
532
  { 0x50, 0x50, NULL,     &input_state_dcs_enter },
533
  { 0x51, 0x57, input_esc_dispatch, &input_state_ground },
534
  { 0x58, 0x58, NULL,     &input_state_consume_st },
535
  { 0x59, 0x59, input_esc_dispatch, &input_state_ground },
536
  { 0x5a, 0x5a, input_esc_dispatch, &input_state_ground },
537
  { 0x5b, 0x5b, NULL,     &input_state_csi_enter },
538
  { 0x5c, 0x5c, input_esc_dispatch, &input_state_ground },
539
  { 0x5d, 0x5d, NULL,     &input_state_osc_string },
540
  { 0x5e, 0x5e, NULL,     &input_state_consume_st },
541
  { 0x5f, 0x5f, NULL,     &input_state_apc_string },
542
  { 0x60, 0x6a, input_esc_dispatch, &input_state_ground },
543
  { 0x6b, 0x6b, NULL,     &input_state_rename_string },
544
  { 0x6c, 0x7e, input_esc_dispatch, &input_state_ground },
545
  { 0x7f, 0xff, NULL,     NULL },
546
547
  { -1, -1, NULL, NULL }
548
};
549
550
/* esc_intermediate state table. */
551
static const struct input_transition input_state_esc_intermediate_table[] = {
552
  INPUT_STATE_ANYWHERE,
553
554
  { 0x00, 0x17, input_c0_dispatch,  NULL },
555
  { 0x19, 0x19, input_c0_dispatch,  NULL },
556
  { 0x1c, 0x1f, input_c0_dispatch,  NULL },
557
  { 0x20, 0x2f, input_intermediate, NULL },
558
  { 0x30, 0x7e, input_esc_dispatch, &input_state_ground },
559
  { 0x7f, 0xff, NULL,     NULL },
560
561
  { -1, -1, NULL, NULL }
562
};
563
564
/* csi_enter state table. */
565
static const struct input_transition input_state_csi_enter_table[] = {
566
  INPUT_STATE_ANYWHERE,
567
568
  { 0x00, 0x17, input_c0_dispatch,  NULL },
569
  { 0x19, 0x19, input_c0_dispatch,  NULL },
570
  { 0x1c, 0x1f, input_c0_dispatch,  NULL },
571
  { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
572
  { 0x30, 0x39, input_parameter,    &input_state_csi_parameter },
573
  { 0x3a, 0x3a, input_parameter,    &input_state_csi_parameter },
574
  { 0x3b, 0x3b, input_parameter,    &input_state_csi_parameter },
575
  { 0x3c, 0x3f, input_intermediate, &input_state_csi_parameter },
576
  { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
577
  { 0x7f, 0xff, NULL,     NULL },
578
579
  { -1, -1, NULL, NULL }
580
};
581
582
/* csi_parameter state table. */
583
static const struct input_transition input_state_csi_parameter_table[] = {
584
  INPUT_STATE_ANYWHERE,
585
586
  { 0x00, 0x17, input_c0_dispatch,  NULL },
587
  { 0x19, 0x19, input_c0_dispatch,  NULL },
588
  { 0x1c, 0x1f, input_c0_dispatch,  NULL },
589
  { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
590
  { 0x30, 0x39, input_parameter,    NULL },
591
  { 0x3a, 0x3a, input_parameter,    NULL },
592
  { 0x3b, 0x3b, input_parameter,    NULL },
593
  { 0x3c, 0x3f, NULL,     &input_state_csi_ignore },
594
  { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
595
  { 0x7f, 0xff, NULL,     NULL },
596
597
  { -1, -1, NULL, NULL }
598
};
599
600
/* csi_intermediate state table. */
601
static const struct input_transition input_state_csi_intermediate_table[] = {
602
  INPUT_STATE_ANYWHERE,
603
604
  { 0x00, 0x17, input_c0_dispatch,  NULL },
605
  { 0x19, 0x19, input_c0_dispatch,  NULL },
606
  { 0x1c, 0x1f, input_c0_dispatch,  NULL },
607
  { 0x20, 0x2f, input_intermediate, NULL },
608
  { 0x30, 0x3f, NULL,     &input_state_csi_ignore },
609
  { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
610
  { 0x7f, 0xff, NULL,     NULL },
611
612
  { -1, -1, NULL, NULL }
613
};
614
615
/* csi_ignore state table. */
616
static const struct input_transition input_state_csi_ignore_table[] = {
617
  INPUT_STATE_ANYWHERE,
618
619
  { 0x00, 0x17, input_c0_dispatch, NULL },
620
  { 0x19, 0x19, input_c0_dispatch, NULL },
621
  { 0x1c, 0x1f, input_c0_dispatch, NULL },
622
  { 0x20, 0x3f, NULL,    NULL },
623
  { 0x40, 0x7e, NULL,    &input_state_ground },
624
  { 0x7f, 0xff, NULL,    NULL },
625
626
  { -1, -1, NULL, NULL }
627
};
628
629
/* dcs_enter state table. */
630
static const struct input_transition input_state_dcs_enter_table[] = {
631
  INPUT_STATE_ANYWHERE,
632
633
  { 0x00, 0x17, NULL,     NULL },
634
  { 0x19, 0x19, NULL,     NULL },
635
  { 0x1c, 0x1f, NULL,     NULL },
636
  { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
637
  { 0x30, 0x39, input_parameter,    &input_state_dcs_parameter },
638
  { 0x3a, 0x3a, NULL,     &input_state_dcs_ignore },
639
  { 0x3b, 0x3b, input_parameter,    &input_state_dcs_parameter },
640
  { 0x3c, 0x3f, input_intermediate, &input_state_dcs_parameter },
641
  { 0x40, 0x7e, input_input,    &input_state_dcs_handler },
642
  { 0x7f, 0xff, NULL,     NULL },
643
644
  { -1, -1, NULL, NULL }
645
};
646
647
/* dcs_parameter state table. */
648
static const struct input_transition input_state_dcs_parameter_table[] = {
649
  INPUT_STATE_ANYWHERE,
650
651
  { 0x00, 0x17, NULL,     NULL },
652
  { 0x19, 0x19, NULL,     NULL },
653
  { 0x1c, 0x1f, NULL,     NULL },
654
  { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
655
  { 0x30, 0x39, input_parameter,    NULL },
656
  { 0x3a, 0x3a, NULL,     &input_state_dcs_ignore },
657
  { 0x3b, 0x3b, input_parameter,    NULL },
658
  { 0x3c, 0x3f, NULL,     &input_state_dcs_ignore },
659
  { 0x40, 0x7e, input_input,    &input_state_dcs_handler },
660
  { 0x7f, 0xff, NULL,     NULL },
661
662
  { -1, -1, NULL, NULL }
663
};
664
665
/* dcs_intermediate state table. */
666
static const struct input_transition input_state_dcs_intermediate_table[] = {
667
  INPUT_STATE_ANYWHERE,
668
669
  { 0x00, 0x17, NULL,     NULL },
670
  { 0x19, 0x19, NULL,     NULL },
671
  { 0x1c, 0x1f, NULL,     NULL },
672
  { 0x20, 0x2f, input_intermediate, NULL },
673
  { 0x30, 0x3f, NULL,     &input_state_dcs_ignore },
674
  { 0x40, 0x7e, input_input,    &input_state_dcs_handler },
675
  { 0x7f, 0xff, NULL,     NULL },
676
677
  { -1, -1, NULL, NULL }
678
};
679
680
/* dcs_handler state table. */
681
static const struct input_transition input_state_dcs_handler_table[] = {
682
  /* No INPUT_STATE_ANYWHERE */
683
684
  { 0x00, 0x1a, input_input,  NULL },
685
  { 0x1b, 0x1b, NULL,     &input_state_dcs_escape },
686
  { 0x1c, 0xff, input_input,  NULL },
687
688
  { -1, -1, NULL, NULL }
689
};
690
691
/* dcs_escape state table. */
692
static const struct input_transition input_state_dcs_escape_table[] = {
693
  /* No INPUT_STATE_ANYWHERE */
694
695
  { 0x00, 0x5b, input_input,    &input_state_dcs_handler },
696
  { 0x5c, 0x5c, input_dcs_dispatch, &input_state_ground },
697
  { 0x5d, 0xff, input_input,    &input_state_dcs_handler },
698
699
  { -1, -1, NULL, NULL }
700
};
701
702
/* dcs_ignore state table. */
703
static const struct input_transition input_state_dcs_ignore_table[] = {
704
  INPUT_STATE_ANYWHERE,
705
706
  { 0x00, 0x17, NULL,     NULL },
707
  { 0x19, 0x19, NULL,     NULL },
708
  { 0x1c, 0x1f, NULL,     NULL },
709
  { 0x20, 0xff, NULL,     NULL },
710
711
  { -1, -1, NULL, NULL }
712
};
713
714
/* osc_string state table. */
715
static const struct input_transition input_state_osc_string_table[] = {
716
  INPUT_STATE_ANYWHERE,
717
718
  { 0x00, 0x06, NULL,      NULL },
719
  { 0x07, 0x07, input_end_bel, &input_state_ground },
720
  { 0x08, 0x17, NULL,      NULL },
721
  { 0x19, 0x19, NULL,      NULL },
722
  { 0x1c, 0x1f, NULL,      NULL },
723
  { 0x20, 0xff, input_input,   NULL },
724
725
  { -1, -1, NULL, NULL }
726
};
727
728
/* apc_string state table. */
729
static const struct input_transition input_state_apc_string_table[] = {
730
  INPUT_STATE_ANYWHERE,
731
732
  { 0x00, 0x17, NULL,     NULL },
733
  { 0x19, 0x19, NULL,     NULL },
734
  { 0x1c, 0x1f, NULL,     NULL },
735
  { 0x20, 0xff, input_input,  NULL },
736
737
  { -1, -1, NULL, NULL }
738
};
739
740
/* rename_string state table. */
741
static const struct input_transition input_state_rename_string_table[] = {
742
  INPUT_STATE_ANYWHERE,
743
744
  { 0x00, 0x17, NULL,     NULL },
745
  { 0x19, 0x19, NULL,     NULL },
746
  { 0x1c, 0x1f, NULL,     NULL },
747
  { 0x20, 0xff, input_input,  NULL },
748
749
  { -1, -1, NULL, NULL }
750
};
751
752
/* consume_st state table. */
753
static const struct input_transition input_state_consume_st_table[] = {
754
  INPUT_STATE_ANYWHERE,
755
756
  { 0x00, 0x17, NULL,     NULL },
757
  { 0x19, 0x19, NULL,     NULL },
758
  { 0x1c, 0x1f, NULL,     NULL },
759
  { 0x20, 0xff, NULL,     NULL },
760
761
  { -1, -1, NULL, NULL }
762
};
763
764
/* Maximum of bytes allowed to read in a single input. */
765
static size_t input_buffer_size = INPUT_BUF_DEFAULT_SIZE;
766
767
/* Input table compare. */
768
static int
769
input_table_compare(const void *key, const void *value)
770
236k
{
771
236k
  const struct input_ctx    *ictx = key;
772
236k
  const struct input_table_entry  *entry = value;
773
774
236k
  if (ictx->ch != entry->ch)
775
177k
    return (ictx->ch - entry->ch);
776
59.1k
  return (strcmp(ictx->interm_buf, entry->interm));
777
236k
}
778
779
/* Stop UTF-8 and enter an invalid character. */
780
static void
781
input_stop_utf8(struct input_ctx *ictx)
782
48.0k
{
783
48.0k
  struct screen_write_ctx *sctx = &ictx->ctx;
784
48.0k
  static struct utf8_data  rc = { "\357\277\275", 3, 3, 1 };
785
786
48.0k
  if (ictx->utf8started) {
787
6.49k
    utf8_copy(&ictx->cell.cell.data, &rc);
788
6.49k
    screen_write_collect_add(sctx, &ictx->cell.cell);
789
6.49k
  }
790
48.0k
  ictx->utf8started = 0;
791
48.0k
}
792
793
/*
794
 * Timer - if this expires then have been waiting for a terminator for too
795
 * long, so reset to ground.
796
 */
797
static void
798
input_ground_timer_callback(__unused int fd, __unused short events, void *arg)
799
0
{
800
0
  struct input_ctx  *ictx = arg;
801
802
0
  log_debug("%s: %s expired" , __func__, ictx->state->name);
803
0
  input_reset(ictx, 0);
804
0
}
805
806
/* Start the timer. */
807
static void
808
input_start_ground_timer(struct input_ctx *ictx)
809
21.4k
{
810
21.4k
  struct timeval  tv = { .tv_sec = 5, .tv_usec = 0 };
811
812
21.4k
  event_del(&ictx->ground_timer);
813
21.4k
  event_add(&ictx->ground_timer, &tv);
814
21.4k
}
815
816
/* Reset cell state to default. */
817
static void
818
input_reset_cell(struct input_ctx *ictx)
819
12.5k
{
820
12.5k
  memcpy(&ictx->cell.cell, &grid_default_cell, sizeof ictx->cell.cell);
821
12.5k
  ictx->cell.set = 0;
822
12.5k
  ictx->cell.g0set = ictx->cell.g1set = 0;
823
824
12.5k
  memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
825
12.5k
  ictx->old_cx = 0;
826
12.5k
  ictx->old_cy = 0;
827
12.5k
}
828
829
/* Save screen state. */
830
static void
831
input_save_state(struct input_ctx *ictx)
832
436
{
833
436
  struct screen_write_ctx *sctx = &ictx->ctx;
834
436
  struct screen   *s = sctx->s;
835
836
436
  memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
837
436
  ictx->old_cx = s->cx;
838
436
  ictx->old_cy = s->cy;
839
436
  ictx->old_mode = s->mode;
840
436
}
841
842
/* Restore screen state. */
843
static void
844
input_restore_state(struct input_ctx *ictx)
845
1.04k
{
846
1.04k
  struct screen_write_ctx *sctx = &ictx->ctx;
847
848
1.04k
  memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell);
849
1.04k
  if (ictx->old_mode & MODE_ORIGIN)
850
388
    screen_write_mode_set(sctx, MODE_ORIGIN);
851
654
  else
852
654
    screen_write_mode_clear(sctx, MODE_ORIGIN);
853
1.04k
  screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy, 0);
854
1.04k
}
855
856
/* Initialise input parser. */
857
struct input_ctx *
858
input_init(struct window_pane *wp, struct bufferevent *bev,
859
    struct colour_palette *palette, struct client *c)
860
11.5k
{
861
11.5k
  struct input_ctx  *ictx;
862
863
11.5k
  ictx = xcalloc(1, sizeof *ictx);
864
11.5k
  ictx->wp = wp;
865
11.5k
  ictx->event = bev;
866
11.5k
  ictx->palette = palette;
867
11.5k
  ictx->c = c;
868
869
11.5k
  ictx->input_space = INPUT_BUF_START;
870
11.5k
  ictx->input_buf = xmalloc(INPUT_BUF_START);
871
872
11.5k
  ictx->since_ground = evbuffer_new();
873
11.5k
  if (ictx->since_ground == NULL)
874
0
    fatalx("out of memory");
875
11.5k
  evtimer_set(&ictx->ground_timer, input_ground_timer_callback, ictx);
876
877
11.5k
  TAILQ_INIT(&ictx->requests);
878
11.5k
  evtimer_set(&ictx->request_timer, input_request_timer_callback, ictx);
879
880
11.5k
  input_reset(ictx, 0);
881
11.5k
  return (ictx);
882
11.5k
}
883
884
/* Destroy input parser. */
885
void
886
input_free(struct input_ctx *ictx)
887
11.5k
{
888
11.5k
  struct input_request  *ir, *ir1;
889
11.5k
  u_int      i;
890
891
31.1k
  for (i = 0; i < ictx->param_list_len; i++) {
892
19.6k
    if (ictx->param_list[i].type == INPUT_STRING)
893
2.16k
      free(ictx->param_list[i].str);
894
19.6k
  }
895
896
11.5k
  TAILQ_FOREACH_SAFE(ir, &ictx->requests, entry, ir1)
897
0
    input_free_request(ir);
898
11.5k
  event_del(&ictx->request_timer);
899
900
11.5k
  free(ictx->input_buf);
901
11.5k
  evbuffer_free(ictx->since_ground);
902
11.5k
  event_del(&ictx->ground_timer);
903
904
11.5k
  screen_write_stop_sync(ictx->wp);
905
906
11.5k
  free(ictx);
907
11.5k
}
908
909
/* Reset input state and clear screen. */
910
void
911
input_reset(struct input_ctx *ictx, int clear)
912
11.5k
{
913
11.5k
  struct screen_write_ctx *sctx = &ictx->ctx;
914
11.5k
  struct window_pane  *wp = ictx->wp;
915
916
11.5k
  input_reset_cell(ictx);
917
918
11.5k
  if (clear && wp != NULL) {
919
0
    if (TAILQ_EMPTY(&wp->modes))
920
0
      screen_write_start_pane(sctx, wp, &wp->base);
921
0
    else
922
0
      screen_write_start(sctx, &wp->base);
923
0
    screen_write_reset(sctx);
924
0
    screen_write_stop(sctx);
925
0
  }
926
927
11.5k
  input_clear(ictx);
928
929
11.5k
  ictx->state = &input_state_ground;
930
11.5k
  ictx->flags = 0;
931
11.5k
}
932
933
/* Return pending data. */
934
struct evbuffer *
935
input_pending(struct input_ctx *ictx)
936
0
{
937
0
  return (ictx->since_ground);
938
0
}
939
940
/* Change input state. */
941
static void
942
input_set_state(struct input_ctx *ictx, const struct input_transition *itr)
943
238k
{
944
238k
  if (ictx->state->exit != NULL)
945
20.3k
    ictx->state->exit(ictx);
946
238k
  ictx->state = itr->state;
947
238k
  if (ictx->state->enter != NULL)
948
200k
    ictx->state->enter(ictx);
949
238k
}
950
951
/* Parse data. */
952
static void
953
input_parse(struct input_ctx *ictx, const u_char *buf, size_t len)
954
11.5k
{
955
11.5k
  struct screen_write_ctx   *sctx = &ictx->ctx;
956
11.5k
  const struct input_state  *state = NULL;
957
11.5k
  const struct input_transition *itr = NULL;
958
11.5k
  size_t         off = 0;
959
960
  /* Parse the input. */
961
551k
  while (off < len) {
962
540k
    ictx->ch = buf[off++];
963
964
    /* Find the transition. */
965
540k
    if (ictx->state != state ||
966
301k
        itr == NULL ||
967
301k
        ictx->ch < itr->first ||
968
367k
        ictx->ch > itr->last) {
969
367k
      itr = ictx->state->transitions;
970
3.24M
      while (itr->first != -1 && itr->last != -1) {
971
3.24M
        if (ictx->ch >= itr->first &&
972
3.21M
            ictx->ch <= itr->last)
973
367k
          break;
974
2.88M
        itr++;
975
2.88M
      }
976
367k
      if (itr->first == -1 || itr->last == -1) {
977
        /* No transition? Eh? */
978
0
        fatalx("no transition from state");
979
0
      }
980
367k
    }
981
540k
    state = ictx->state;
982
983
    /*
984
     * Any state except print stops the current collection. This is
985
     * an optimization to avoid checking if the attributes have
986
     * changed for every character. It will stop unnecessarily for
987
     * sequences that don't make a terminal change, but they should
988
     * be the minority.
989
     */
990
540k
    if (itr->handler != input_print)
991
521k
      screen_write_collect_end(sctx);
992
993
    /*
994
     * Execute the handler, if any. Don't switch state if it
995
     * returns non-zero.
996
     */
997
540k
    if (itr->handler != NULL && itr->handler(ictx) != 0)
998
0
      continue;
999
1000
    /* And switch state, if necessary. */
1001
540k
    if (itr->state != NULL)
1002
238k
      input_set_state(ictx, itr);
1003
1004
    /* If not in ground state, save input. */
1005
540k
    if (ictx->state != &input_state_ground)
1006
438k
      evbuffer_add(ictx->since_ground, &ictx->ch, 1);
1007
540k
  }
1008
11.5k
}
1009
1010
/* Parse input from pane. */
1011
void
1012
input_parse_pane(struct window_pane *wp)
1013
0
{
1014
0
  void  *new_data;
1015
0
  size_t   new_size;
1016
1017
0
  new_data = window_pane_get_new_data(wp, &wp->offset, &new_size);
1018
0
  input_parse_buffer(wp, new_data, new_size);
1019
0
  window_pane_update_used_data(wp, &wp->offset, new_size);
1020
0
}
1021
1022
/* Parse given input. */
1023
void
1024
input_parse_buffer(struct window_pane *wp, const u_char *buf, size_t len)
1025
11.5k
{
1026
11.5k
  struct input_ctx  *ictx = wp->ictx;
1027
11.5k
  struct screen_write_ctx *sctx = &ictx->ctx;
1028
1029
11.5k
  if (len == 0)
1030
0
    return;
1031
1032
11.5k
  window_update_activity(wp->window);
1033
11.5k
  wp->flags |= PANE_CHANGED;
1034
1035
  /* Flag new input while in a mode. */
1036
11.5k
  if (!TAILQ_EMPTY(&wp->modes))
1037
0
    wp->flags |= PANE_UNSEENCHANGES;
1038
1039
  /* NULL wp if there is a mode set as don't want to update the tty. */
1040
11.5k
  if (TAILQ_EMPTY(&wp->modes))
1041
11.5k
    screen_write_start_pane(sctx, wp, &wp->base);
1042
0
  else
1043
0
    screen_write_start(sctx, &wp->base);
1044
1045
11.5k
  log_debug("%s: %%%u %s, %zu bytes: %.*s", __func__, wp->id,
1046
11.5k
      ictx->state->name, len, (int)len, buf);
1047
1048
11.5k
  input_parse(ictx, buf, len);
1049
11.5k
  screen_write_stop(sctx);
1050
11.5k
}
1051
1052
/* Parse given input for screen. */
1053
void
1054
input_parse_screen(struct input_ctx *ictx, struct screen *s,
1055
    screen_write_init_ctx_cb cb, void *arg, const u_char *buf, size_t len)
1056
0
{
1057
0
  struct screen_write_ctx *sctx = &ictx->ctx;
1058
1059
0
  if (len == 0)
1060
0
    return;
1061
1062
0
  screen_write_start_callback(sctx, s, cb, arg);
1063
0
  input_parse(ictx, buf, len);
1064
0
  screen_write_stop(sctx);
1065
0
}
1066
1067
/* Split the parameter list (if any). */
1068
static int
1069
input_split(struct input_ctx *ictx)
1070
46.0k
{
1071
46.0k
  const char    *errstr;
1072
46.0k
  char      *ptr, *out;
1073
46.0k
  struct input_param  *ip;
1074
46.0k
  u_int      i;
1075
1076
95.9k
  for (i = 0; i < ictx->param_list_len; i++) {
1077
49.9k
    if (ictx->param_list[i].type == INPUT_STRING)
1078
6.76k
      free(ictx->param_list[i].str);
1079
49.9k
  }
1080
46.0k
  ictx->param_list_len = 0;
1081
1082
46.0k
  if (ictx->param_len == 0)
1083
15.9k
    return (0);
1084
30.0k
  ip = &ictx->param_list[0];
1085
1086
30.0k
  ptr = ictx->param_buf;
1087
99.6k
  while ((out = strsep(&ptr, ";")) != NULL) {
1088
69.8k
    if (*out == '\0')
1089
14.7k
      ip->type = INPUT_MISSING;
1090
55.1k
    else {
1091
55.1k
      if (strchr(out, ':') != NULL) {
1092
8.92k
        ip->type = INPUT_STRING;
1093
8.92k
        ip->str = xstrdup(out);
1094
46.2k
      } else {
1095
46.2k
        ip->type = INPUT_NUMBER;
1096
46.2k
        ip->num = strtonum(out, 0, INT_MAX, &errstr);
1097
46.2k
        if (errstr != NULL)
1098
272
          return (-1);
1099
46.2k
      }
1100
55.1k
    }
1101
69.5k
    ip = &ictx->param_list[++ictx->param_list_len];
1102
69.5k
    if (ictx->param_list_len == nitems(ictx->param_list))
1103
40
      return (-1);
1104
69.5k
  }
1105
1106
98.4k
  for (i = 0; i < ictx->param_list_len; i++) {
1107
68.6k
    ip = &ictx->param_list[i];
1108
68.6k
    if (ip->type == INPUT_MISSING)
1109
13.7k
      log_debug("parameter %u: missing", i);
1110
54.8k
    else if (ip->type == INPUT_STRING)
1111
8.92k
      log_debug("parameter %u: string %s", i, ip->str);
1112
45.9k
    else if (ip->type == INPUT_NUMBER)
1113
45.9k
      log_debug("parameter %u: number %d", i, ip->num);
1114
68.6k
  }
1115
1116
29.7k
  return (0);
1117
30.0k
}
1118
1119
/* Get an argument or return default value. */
1120
static int
1121
input_get(struct input_ctx *ictx, u_int validx, int minval, int defval)
1122
82.1k
{
1123
82.1k
  struct input_param  *ip;
1124
82.1k
  int      retval;
1125
1126
82.1k
  if (validx >= ictx->param_list_len)
1127
18.2k
      return (defval);
1128
63.8k
  ip = &ictx->param_list[validx];
1129
63.8k
  if (ip->type == INPUT_MISSING)
1130
10.4k
    return (defval);
1131
53.4k
  if (ip->type == INPUT_STRING)
1132
5.85k
    return (-1);
1133
47.5k
  retval = ip->num;
1134
47.5k
  if (retval < minval)
1135
2.30k
    return (minval);
1136
45.2k
  return (retval);
1137
47.5k
}
1138
1139
/* Send reply. */
1140
static void
1141
input_send_reply(struct input_ctx *ictx, const char *reply)
1142
3.10k
{
1143
3.10k
  if (ictx->event != NULL) {
1144
3.10k
    log_debug("%s: %s", __func__, reply);
1145
3.10k
    bufferevent_write(ictx->event, reply, strlen(reply));
1146
3.10k
  }
1147
3.10k
}
1148
1149
/* Reply to terminal query. */
1150
static void printflike(3, 4)
1151
input_reply(struct input_ctx *ictx, int add, const char *fmt, ...)
1152
3.10k
{
1153
3.10k
  struct input_request  *ir;
1154
3.10k
  va_list      ap;
1155
3.10k
  char      *reply;
1156
1157
3.10k
  va_start(ap, fmt);
1158
3.10k
  xvasprintf(&reply, fmt, ap);
1159
3.10k
  va_end(ap);
1160
1161
3.10k
  if (add && !TAILQ_EMPTY(&ictx->requests)) {
1162
0
    ir = input_make_request(ictx, INPUT_REQUEST_QUEUE);
1163
0
    ir->data = reply;
1164
3.10k
  } else {
1165
3.10k
    input_send_reply(ictx, reply);
1166
3.10k
    free(reply);
1167
3.10k
  }
1168
3.10k
}
1169
1170
/* Clear saved state. */
1171
static void
1172
input_clear(struct input_ctx *ictx)
1173
157k
{
1174
157k
  event_del(&ictx->ground_timer);
1175
1176
157k
  *ictx->interm_buf = '\0';
1177
157k
  ictx->interm_len = 0;
1178
1179
157k
  *ictx->param_buf = '\0';
1180
157k
  ictx->param_len = 0;
1181
1182
157k
  *ictx->input_buf = '\0';
1183
157k
  ictx->input_len = 0;
1184
1185
157k
  ictx->input_end = INPUT_END_ST;
1186
1187
157k
  ictx->flags &= ~INPUT_DISCARD;
1188
157k
}
1189
1190
/* Reset for ground state. */
1191
static void
1192
input_ground(struct input_ctx *ictx)
1193
54.7k
{
1194
54.7k
  event_del(&ictx->ground_timer);
1195
54.7k
  evbuffer_drain(ictx->since_ground, EVBUFFER_LENGTH(ictx->since_ground));
1196
1197
54.7k
  if (ictx->input_space > INPUT_BUF_START) {
1198
79
    ictx->input_space = INPUT_BUF_START;
1199
79
    ictx->input_buf = xrealloc(ictx->input_buf, INPUT_BUF_START);
1200
79
  }
1201
54.7k
}
1202
1203
/* Output this character to the screen. */
1204
static int
1205
input_print(struct input_ctx *ictx)
1206
18.4k
{
1207
18.4k
  struct screen_write_ctx *sctx = &ictx->ctx;
1208
18.4k
  int      set;
1209
1210
18.4k
  input_stop_utf8(ictx); /* can't be valid UTF-8 */
1211
1212
18.4k
  set = ictx->cell.set == 0 ? ictx->cell.g0set : ictx->cell.g1set;
1213
18.4k
  if (set == 1)
1214
1.84k
    ictx->cell.cell.attr |= GRID_ATTR_CHARSET;
1215
16.5k
  else
1216
16.5k
    ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET;
1217
18.4k
  utf8_set(&ictx->cell.cell.data, ictx->ch);
1218
18.4k
  screen_write_collect_add(sctx, &ictx->cell.cell);
1219
1220
18.4k
  utf8_copy(&ictx->last, &ictx->cell.cell.data);
1221
18.4k
  ictx->flags |= INPUT_LAST;
1222
1223
18.4k
  ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET;
1224
1225
18.4k
  return (0);
1226
18.4k
}
1227
1228
/* Collect intermediate string. */
1229
static int
1230
input_intermediate(struct input_ctx *ictx)
1231
11.3k
{
1232
11.3k
  if (ictx->interm_len == (sizeof ictx->interm_buf) - 1)
1233
568
    ictx->flags |= INPUT_DISCARD;
1234
10.8k
  else {
1235
10.8k
    ictx->interm_buf[ictx->interm_len++] = ictx->ch;
1236
10.8k
    ictx->interm_buf[ictx->interm_len] = '\0';
1237
10.8k
  }
1238
1239
11.3k
  return (0);
1240
11.3k
}
1241
1242
/* Collect parameter string. */
1243
static int
1244
input_parameter(struct input_ctx *ictx)
1245
155k
{
1246
155k
  if (ictx->param_len == (sizeof ictx->param_buf) - 1)
1247
392
    ictx->flags |= INPUT_DISCARD;
1248
155k
  else {
1249
155k
    ictx->param_buf[ictx->param_len++] = ictx->ch;
1250
155k
    ictx->param_buf[ictx->param_len] = '\0';
1251
155k
  }
1252
1253
155k
  return (0);
1254
155k
}
1255
1256
/* Collect input string. */
1257
static int
1258
input_input(struct input_ctx *ictx)
1259
119k
{
1260
119k
  size_t available;
1261
1262
119k
  available = ictx->input_space;
1263
119k
  while (ictx->input_len + 1 >= available) {
1264
594
    available *= 2;
1265
594
    if (available > input_buffer_size) {
1266
0
      ictx->flags |= INPUT_DISCARD;
1267
0
      return (0);
1268
0
    }
1269
594
    ictx->input_buf = xrealloc(ictx->input_buf, available);
1270
594
    ictx->input_space = available;
1271
594
  }
1272
119k
  ictx->input_buf[ictx->input_len++] = ictx->ch;
1273
119k
  ictx->input_buf[ictx->input_len] = '\0';
1274
1275
119k
  return (0);
1276
119k
}
1277
1278
/* Execute C0 control sequence. */
1279
static int
1280
input_c0_dispatch(struct input_ctx *ictx)
1281
24.3k
{
1282
24.3k
  struct screen_write_ctx *sctx = &ictx->ctx;
1283
24.3k
  struct window_pane  *wp = ictx->wp;
1284
24.3k
  struct screen   *s = sctx->s;
1285
24.3k
  struct grid_cell   gc, first_gc;
1286
24.3k
  u_int      cx, line;
1287
24.3k
  u_int      width;
1288
24.3k
  int      has_content = 0;
1289
1290
24.3k
  input_stop_utf8(ictx); /* can't be valid UTF-8 */
1291
1292
24.3k
  log_debug("%s: '%c'", __func__, ictx->ch);
1293
1294
24.3k
  switch (ictx->ch) {
1295
1.56k
  case '\000':  /* NUL */
1296
1.56k
    break;
1297
1.62k
  case '\007':  /* BEL */
1298
1.62k
    if (wp != NULL)
1299
1.62k
      alerts_queue(wp->window, WINDOW_BELL);
1300
1.62k
    break;
1301
4.25k
  case '\010':  /* BS */
1302
4.25k
    screen_write_backspace(sctx);
1303
4.25k
    break;
1304
7.56k
  case '\011':  /* HT */
1305
    /* Don't tab beyond the end of the line. */
1306
7.56k
    cx = s->cx;
1307
7.56k
    if (cx >= screen_size_x(s) - 1)
1308
275
      break;
1309
1310
    /* Find the next tab point, or use the last column if none. */
1311
7.29k
    line = s->cy + s->grid->hsize;
1312
7.29k
    grid_get_cell(s->grid, cx, line, &first_gc);
1313
172k
    do {
1314
172k
      if (!has_content) {
1315
160k
        grid_get_cell(s->grid, cx, line, &gc);
1316
160k
        if (gc.data.size != 1 ||
1317
160k
            *gc.data.data != ' ' ||
1318
160k
            !grid_cells_look_equal(&gc, &first_gc))
1319
1.85k
          has_content = 1;
1320
160k
      }
1321
172k
      cx++;
1322
172k
      if (bit_test(s->tabs, cx))
1323
5.18k
        break;
1324
172k
    } while (cx < screen_size_x(s) - 1);
1325
1326
7.29k
    width = cx - s->cx;
1327
7.29k
    if (has_content || width > sizeof gc.data.data)
1328
3.40k
      s->cx = cx;
1329
3.88k
    else {
1330
3.88k
      grid_get_cell(s->grid, s->cx, line, &gc);
1331
3.88k
      grid_set_tab(&gc, width);
1332
3.88k
      screen_write_collect_add(sctx, &gc);
1333
3.88k
    }
1334
7.29k
    break;
1335
1.90k
  case '\012':  /* LF */
1336
2.80k
  case '\013':  /* VT */
1337
5.72k
  case '\014':  /* FF */
1338
5.72k
    screen_write_linefeed(sctx, 0, ictx->cell.cell.bg);
1339
5.72k
    if (s->mode & MODE_CRLF)
1340
0
      screen_write_carriagereturn(sctx);
1341
5.72k
    break;
1342
2.22k
  case '\015':  /* CR */
1343
2.22k
    screen_write_carriagereturn(sctx);
1344
2.22k
    break;
1345
221
  case '\016':  /* SO */
1346
221
    ictx->cell.set = 1;
1347
221
    break;
1348
208
  case '\017':  /* SI */
1349
208
    ictx->cell.set = 0;
1350
208
    break;
1351
924
  default:
1352
924
    log_debug("%s: unknown '%c'", __func__, ictx->ch);
1353
924
    break;
1354
24.3k
  }
1355
1356
24.3k
  ictx->flags &= ~INPUT_LAST;
1357
24.3k
  return (0);
1358
24.3k
}
1359
1360
/* Execute escape sequence. */
1361
static int
1362
input_esc_dispatch(struct input_ctx *ictx)
1363
7.13k
{
1364
7.13k
  struct screen_write_ctx   *sctx = &ictx->ctx;
1365
7.13k
  struct screen     *s = sctx->s;
1366
7.13k
  struct input_table_entry  *entry;
1367
1368
7.13k
  if (ictx->flags & INPUT_DISCARD)
1369
66
    return (0);
1370
7.07k
  log_debug("%s: '%c', %s", __func__, ictx->ch, ictx->interm_buf);
1371
1372
7.07k
  entry = bsearch(ictx, input_esc_table, nitems(input_esc_table),
1373
7.07k
      sizeof input_esc_table[0], input_table_compare);
1374
7.07k
  if (entry == NULL) {
1375
718
    log_debug("%s: unknown '%c'", __func__, ictx->ch);
1376
718
    return (0);
1377
718
  }
1378
1379
6.35k
  switch (entry->type) {
1380
988
  case INPUT_ESC_RIS:
1381
988
    colour_palette_clear(ictx->palette);
1382
988
    input_reset_cell(ictx);
1383
988
    screen_write_reset(sctx);
1384
988
    screen_write_fullredraw(sctx);
1385
988
    break;
1386
224
  case INPUT_ESC_IND:
1387
224
    screen_write_linefeed(sctx, 0, ictx->cell.cell.bg);
1388
224
    break;
1389
493
  case INPUT_ESC_NEL:
1390
493
    screen_write_carriagereturn(sctx);
1391
493
    screen_write_linefeed(sctx, 0, ictx->cell.cell.bg);
1392
493
    break;
1393
408
  case INPUT_ESC_HTS:
1394
408
    if (s->cx < screen_size_x(s))
1395
214
      bit_set(s->tabs, s->cx);
1396
408
    break;
1397
641
  case INPUT_ESC_RI:
1398
641
    screen_write_reverseindex(sctx, ictx->cell.cell.bg);
1399
641
    break;
1400
195
  case INPUT_ESC_DECKPAM:
1401
195
    screen_write_mode_set(sctx, MODE_KKEYPAD);
1402
195
    break;
1403
194
  case INPUT_ESC_DECKPNM:
1404
194
    screen_write_mode_clear(sctx, MODE_KKEYPAD);
1405
194
    break;
1406
233
  case INPUT_ESC_DECSC:
1407
233
    input_save_state(ictx);
1408
233
    break;
1409
650
  case INPUT_ESC_DECRC:
1410
650
    input_restore_state(ictx);
1411
650
    break;
1412
1.15k
  case INPUT_ESC_DECALN:
1413
1.15k
    screen_write_alignmenttest(sctx);
1414
1.15k
    break;
1415
360
  case INPUT_ESC_SCSG0_ON:
1416
360
    ictx->cell.g0set = 1;
1417
360
    break;
1418
194
  case INPUT_ESC_SCSG0_OFF:
1419
194
    ictx->cell.g0set = 0;
1420
194
    break;
1421
194
  case INPUT_ESC_SCSG1_ON:
1422
194
    ictx->cell.g1set = 1;
1423
194
    break;
1424
194
  case INPUT_ESC_SCSG1_OFF:
1425
194
    ictx->cell.g1set = 0;
1426
194
    break;
1427
225
  case INPUT_ESC_ST:
1428
    /* ST terminates OSC but the state transition already did it. */
1429
225
    break;
1430
6.35k
  }
1431
1432
6.35k
  ictx->flags &= ~INPUT_LAST;
1433
6.35k
  return (0);
1434
6.35k
}
1435
1436
/* Execute control sequence. */
1437
static int
1438
input_csi_dispatch(struct input_ctx *ictx)
1439
46.0k
{
1440
46.0k
  struct screen_write_ctx        *sctx = &ictx->ctx;
1441
46.0k
  struct screen          *s = sctx->s;
1442
46.0k
  struct input_table_entry       *entry;
1443
46.0k
  struct options           *oo;
1444
46.0k
  int       i, n, m, ek, set, p;
1445
46.0k
  u_int       cx, bg = ictx->cell.cell.bg;
1446
1447
46.0k
  if (ictx->flags & INPUT_DISCARD)
1448
67
    return (0);
1449
1450
46.0k
  log_debug("%s: '%c' \"%s\" \"%s\"", __func__, ictx->ch,
1451
46.0k
      ictx->interm_buf, ictx->param_buf);
1452
1453
46.0k
  if (input_split(ictx) != 0)
1454
312
    return (0);
1455
1456
45.6k
  entry = bsearch(ictx, input_csi_table, nitems(input_csi_table),
1457
45.6k
      sizeof input_csi_table[0], input_table_compare);
1458
45.6k
  if (entry == NULL) {
1459
364
    log_debug("%s: unknown '%c'", __func__, ictx->ch);
1460
364
    return (0);
1461
364
  }
1462
1463
45.3k
  switch (entry->type) {
1464
824
  case INPUT_CSI_CBT:
1465
    /* Find the previous tab point, n times. */
1466
824
    cx = s->cx;
1467
824
    if (cx > screen_size_x(s) - 1)
1468
66
      cx = screen_size_x(s) - 1;
1469
824
    n = input_get(ictx, 0, 1, 1);
1470
824
    if (n == -1)
1471
128
      break;
1472
1.02k
    while (cx > 0 && n-- > 0) {
1473
330
      do
1474
2.22k
        cx--;
1475
2.22k
      while (cx > 0 && !bit_test(s->tabs, cx));
1476
330
    }
1477
696
    s->cx = cx;
1478
696
    break;
1479
977
  case INPUT_CSI_CUB:
1480
977
    n = input_get(ictx, 0, 1, 1);
1481
977
    if (n != -1)
1482
782
      screen_write_cursorleft(sctx, n);
1483
977
    break;
1484
1.01k
  case INPUT_CSI_CUD:
1485
1.01k
    n = input_get(ictx, 0, 1, 1);
1486
1.01k
    if (n != -1)
1487
949
      screen_write_cursordown(sctx, n);
1488
1.01k
    break;
1489
1.70k
  case INPUT_CSI_CUF:
1490
1.70k
    n = input_get(ictx, 0, 1, 1);
1491
1.70k
    if (n != -1)
1492
1.60k
      screen_write_cursorright(sctx, n);
1493
1.70k
    break;
1494
1.18k
  case INPUT_CSI_CUP:
1495
1.18k
    n = input_get(ictx, 0, 1, 1);
1496
1.18k
    m = input_get(ictx, 1, 1, 1);
1497
1.18k
    if (n != -1 && m != -1)
1498
928
      screen_write_cursormove(sctx, m - 1, n - 1, 1);
1499
1.18k
    break;
1500
670
  case INPUT_CSI_MODSET:
1501
670
    n = input_get(ictx, 0, 0, 0);
1502
670
    if (n != 4)
1503
378
      break;
1504
292
    m = input_get(ictx, 1, 0, 0);
1505
1506
    /*
1507
     * Set the extended key reporting mode as per the client
1508
     * request, unless "extended-keys" is set to "off".
1509
     */
1510
292
    ek = options_get_number(global_options, "extended-keys");
1511
292
    if (ek == 0)
1512
292
      break;
1513
0
    screen_write_mode_clear(sctx, EXTENDED_KEY_MODES);
1514
0
    if (m == 2)
1515
0
      screen_write_mode_set(sctx, MODE_KEYS_EXTENDED_2);
1516
0
    else if (m == 1 || ek == 2)
1517
0
      screen_write_mode_set(sctx, MODE_KEYS_EXTENDED);
1518
0
    break;
1519
365
  case INPUT_CSI_MODOFF:
1520
365
    n = input_get(ictx, 0, 0, 0);
1521
365
    if (n != 4)
1522
299
      break;
1523
1524
    /*
1525
     * Clear the extended key reporting mode as per the client
1526
     * request, unless "extended-keys always" forces into mode 1.
1527
     */
1528
66
    screen_write_mode_clear(sctx,
1529
66
        MODE_KEYS_EXTENDED|MODE_KEYS_EXTENDED_2);
1530
66
    if (options_get_number(global_options, "extended-keys") == 2)
1531
0
      screen_write_mode_set(sctx, MODE_KEYS_EXTENDED);
1532
66
    break;
1533
2.54k
  case INPUT_CSI_WINOPS:
1534
2.54k
    input_csi_dispatch_winops(ictx);
1535
2.54k
    break;
1536
1.26k
  case INPUT_CSI_CUU:
1537
1.26k
    n = input_get(ictx, 0, 1, 1);
1538
1.26k
    if (n != -1)
1539
1.19k
      screen_write_cursorup(sctx, n);
1540
1.26k
    break;
1541
960
  case INPUT_CSI_CNL:
1542
960
    n = input_get(ictx, 0, 1, 1);
1543
960
    if (n != -1) {
1544
734
      screen_write_carriagereturn(sctx);
1545
734
      screen_write_cursordown(sctx, n);
1546
734
    }
1547
960
    break;
1548
915
  case INPUT_CSI_CPL:
1549
915
    n = input_get(ictx, 0, 1, 1);
1550
915
    if (n != -1) {
1551
721
      screen_write_carriagereturn(sctx);
1552
721
      screen_write_cursorup(sctx, n);
1553
721
    }
1554
915
    break;
1555
706
  case INPUT_CSI_DA:
1556
706
    switch (input_get(ictx, 0, 0, 0)) {
1557
194
    case -1:
1558
194
      break;
1559
394
    case 0:
1560
#ifdef ENABLE_SIXEL
1561
      input_reply(ictx, 1, "\033[?1;2;4c");
1562
#else
1563
394
      input_reply(ictx, 1, "\033[?1;2c");
1564
394
#endif
1565
394
      break;
1566
118
    default:
1567
118
      log_debug("%s: unknown '%c'", __func__, ictx->ch);
1568
118
      break;
1569
706
    }
1570
706
    break;
1571
706
  case INPUT_CSI_DA_TWO:
1572
315
    switch (input_get(ictx, 0, 0, 0)) {
1573
66
    case -1:
1574
66
      break;
1575
137
    case 0:
1576
137
      input_reply(ictx, 1, "\033[>84;0;0c");
1577
137
      break;
1578
112
    default:
1579
112
      log_debug("%s: unknown '%c'", __func__, ictx->ch);
1580
112
      break;
1581
315
    }
1582
315
    break;
1583
1.22k
  case INPUT_CSI_ECH:
1584
1.22k
    n = input_get(ictx, 0, 1, 1);
1585
1.22k
    if (n != -1)
1586
1.16k
      screen_write_clearcharacter(sctx, n, bg);
1587
1.22k
    break;
1588
1.19k
  case INPUT_CSI_DCH:
1589
1.19k
    n = input_get(ictx, 0, 1, 1);
1590
1.19k
    if (n != -1)
1591
1.00k
      screen_write_deletecharacter(sctx, n, bg);
1592
1.19k
    break;
1593
1.48k
  case INPUT_CSI_DECSTBM:
1594
1.48k
    n = input_get(ictx, 0, 1, 1);
1595
1.48k
    m = input_get(ictx, 1, 1, screen_size_y(s));
1596
1.48k
    if (n != -1 && m != -1)
1597
1.35k
      screen_write_scrollregion(sctx, n - 1, m - 1);
1598
1.48k
    break;
1599
1.41k
  case INPUT_CSI_DL:
1600
1.41k
    n = input_get(ictx, 0, 1, 1);
1601
1.41k
    if (n != -1)
1602
1.22k
      screen_write_deleteline(sctx, n, bg);
1603
1.41k
    break;
1604
383
  case INPUT_CSI_DSR_PRIVATE:
1605
383
    switch (input_get(ictx, 0, 0, 0)) {
1606
66
    case 996:
1607
66
      input_report_current_theme(ictx);
1608
66
      break;
1609
383
    }
1610
383
    break;
1611
914
  case INPUT_CSI_QUERY_PRIVATE:
1612
914
    switch (input_get(ictx, 0, 0, 0)) {
1613
198
    case 12: /* cursor blink: 1 = blink, 2 = steady */
1614
198
      if (s->cstyle != SCREEN_CURSOR_DEFAULT ||
1615
132
          s->mode & MODE_CURSOR_BLINKING_SET)
1616
132
        n = (s->mode & MODE_CURSOR_BLINKING) ? 1 : 2;
1617
66
      else {
1618
66
        if (ictx->wp != NULL)
1619
66
          oo = ictx->wp->options;
1620
0
        else
1621
0
          oo = global_w_options;
1622
66
        p = options_get_number(oo, "cursor-style");
1623
1624
        /* blink for 1,3,5; steady for 0,2,4,6 */
1625
66
        n = (p == 1 || p == 3 || p == 5) ? 1 : 2;
1626
66
      }
1627
198
      input_reply(ictx, 1, "\033[?12;%d$y", n);
1628
198
      break;
1629
66
    case 1004: /* focus reporting */
1630
66
      n = (s->mode & MODE_FOCUSON) ? 1 : 2;
1631
66
      input_reply(ictx, 1, "\033[?1004;%d$y", n);
1632
66
      break;
1633
82
    case 1006: /* SGR mouse */
1634
82
      n = (s->mode & MODE_MOUSE_SGR) ? 1 : 2;
1635
82
      input_reply(ictx, 1, "\033[?1006;%d$y", n);
1636
82
      break;
1637
77
    case 2004: /* bracketed paste */
1638
77
      n = (s->mode & MODE_BRACKETPASTE) ? 1 : 2;
1639
77
      input_reply(ictx, 1, "\033[?2004;%d$y", n);
1640
77
      break;
1641
71
    case 2026: /* synchronized output */
1642
71
      n = (s->mode & MODE_SYNC) ? 1 : 2;
1643
71
      input_reply(ictx, 1, "\033[?2026;%d$y", n);
1644
71
      break;
1645
66
    case 2031:
1646
66
      input_reply(ictx, 1, "\033[?2031;2$y");
1647
66
      break;
1648
914
    }
1649
914
    break;
1650
914
  case INPUT_CSI_DSR:
1651
780
    switch (input_get(ictx, 0, 0, 0)) {
1652
67
    case -1:
1653
67
      break;
1654
194
    case 5:
1655
194
      input_reply(ictx, 1, "\033[0n");
1656
194
      break;
1657
66
    case 6:
1658
66
      input_reply(ictx, 1, "\033[%u;%uR", s->cy + 1,
1659
66
          s->cx + 1);
1660
66
      break;
1661
453
    default:
1662
453
      log_debug("%s: unknown '%c'", __func__, ictx->ch);
1663
453
      break;
1664
780
    }
1665
780
    break;
1666
2.76k
  case INPUT_CSI_ED:
1667
2.76k
    switch (input_get(ictx, 0, 0, 0)) {
1668
67
    case -1:
1669
67
      break;
1670
1.72k
    case 0:
1671
1.72k
      screen_write_clearendofscreen(sctx, bg);
1672
1.72k
      break;
1673
236
    case 1:
1674
236
      screen_write_clearstartofscreen(sctx, bg);
1675
236
      break;
1676
192
    case 2:
1677
192
      screen_write_clearscreen(sctx, bg);
1678
192
      break;
1679
422
    case 3:
1680
422
      if (input_get(ictx, 1, 0, 0) == 0) {
1681
        /*
1682
         * Linux console extension to clear history
1683
         * (for example before locking the screen).
1684
         */
1685
268
        screen_write_clearhistory(sctx);
1686
268
      }
1687
422
      break;
1688
118
    default:
1689
118
      log_debug("%s: unknown '%c'", __func__, ictx->ch);
1690
118
      break;
1691
2.76k
    }
1692
2.76k
    break;
1693
2.76k
  case INPUT_CSI_EL:
1694
2.31k
    switch (input_get(ictx, 0, 0, 0)) {
1695
194
    case -1:
1696
194
      break;
1697
1.73k
    case 0:
1698
1.73k
      screen_write_clearendofline(sctx, bg);
1699
1.73k
      break;
1700
211
    case 1:
1701
211
      screen_write_clearstartofline(sctx, bg);
1702
211
      break;
1703
83
    case 2:
1704
83
      screen_write_clearline(sctx, bg);
1705
83
      break;
1706
94
    default:
1707
94
      log_debug("%s: unknown '%c'", __func__, ictx->ch);
1708
94
      break;
1709
2.31k
    }
1710
2.31k
    break;
1711
2.31k
  case INPUT_CSI_HPA:
1712
879
    n = input_get(ictx, 0, 1, 1);
1713
879
    if (n != -1)
1714
685
      screen_write_cursormove(sctx, n - 1, -1, 1);
1715
879
    break;
1716
1.57k
  case INPUT_CSI_ICH:
1717
1.57k
    n = input_get(ictx, 0, 1, 1);
1718
1.57k
    if (n != -1)
1719
1.50k
      screen_write_insertcharacter(sctx, n, bg);
1720
1.57k
    break;
1721
1.48k
  case INPUT_CSI_IL:
1722
1.48k
    n = input_get(ictx, 0, 1, 1);
1723
1.48k
    if (n != -1)
1724
1.29k
      screen_write_insertline(sctx, n, bg);
1725
1.48k
    break;
1726
1.80k
  case INPUT_CSI_REP:
1727
1.80k
    n = input_get(ictx, 0, 1, 1);
1728
1.80k
    if (n == -1)
1729
194
      break;
1730
1731
1.61k
    m = screen_size_x(s) - s->cx;
1732
1.61k
    if (n > m)
1733
405
      n = m;
1734
1735
1.61k
    if (~ictx->flags & INPUT_LAST)
1736
894
      break;
1737
1738
719
    set = ictx->cell.set == 0 ? ictx->cell.g0set : ictx->cell.g1set;
1739
719
    if (set == 1)
1740
168
      ictx->cell.cell.attr |= GRID_ATTR_CHARSET;
1741
551
    else
1742
551
      ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET;
1743
719
    utf8_copy(&ictx->cell.cell.data, &ictx->last);
1744
27.3k
    for (i = 0; i < n; i++)
1745
26.5k
      screen_write_collect_add(sctx, &ictx->cell.cell);
1746
719
    break;
1747
392
  case INPUT_CSI_RCP:
1748
392
    input_restore_state(ictx);
1749
392
    break;
1750
606
  case INPUT_CSI_RM:
1751
606
    input_csi_dispatch_rm(ictx);
1752
606
    break;
1753
1.18k
  case INPUT_CSI_RM_PRIVATE:
1754
1.18k
    input_csi_dispatch_rm_private(ictx);
1755
1.18k
    break;
1756
203
  case INPUT_CSI_SCP:
1757
203
    input_save_state(ictx);
1758
203
    break;
1759
3.91k
  case INPUT_CSI_SGR:
1760
3.91k
    input_csi_dispatch_sgr(ictx);
1761
3.91k
    break;
1762
673
  case INPUT_CSI_SM:
1763
673
    input_csi_dispatch_sm(ictx);
1764
673
    break;
1765
1.00k
  case INPUT_CSI_SM_PRIVATE:
1766
1.00k
    input_csi_dispatch_sm_private(ictx);
1767
1.00k
    break;
1768
66
  case INPUT_CSI_SM_GRAPHICS:
1769
66
    input_csi_dispatch_sm_graphics(ictx);
1770
66
    break;
1771
1.20k
  case INPUT_CSI_SU:
1772
1.20k
    n = input_get(ictx, 0, 1, 1);
1773
1.20k
    if (n != -1)
1774
1.13k
      screen_write_scrollup(sctx, n, bg);
1775
1.20k
    break;
1776
600
  case INPUT_CSI_SD:
1777
600
    n = input_get(ictx, 0, 1, 1);
1778
600
    if (n != -1)
1779
534
      screen_write_scrolldown(sctx, n, bg);
1780
600
    break;
1781
1.37k
  case INPUT_CSI_TBC:
1782
1.37k
    switch (input_get(ictx, 0, 0, 0)) {
1783
194
    case -1:
1784
194
      break;
1785
479
    case 0:
1786
479
      if (s->cx < screen_size_x(s))
1787
285
        bit_clear(s->tabs, s->cx);
1788
479
      break;
1789
583
    case 3:
1790
583
      bit_nclear(s->tabs, 0, screen_size_x(s) - 1);
1791
583
      break;
1792
118
    default:
1793
118
      log_debug("%s: unknown '%c'", __func__, ictx->ch);
1794
118
      break;
1795
1.37k
    }
1796
1.37k
    break;
1797
1.37k
  case INPUT_CSI_VPA:
1798
1.15k
    n = input_get(ictx, 0, 1, 1);
1799
1.15k
    if (n != -1)
1800
960
      screen_write_cursormove(sctx, -1, n - 1, 1);
1801
1.15k
    break;
1802
846
  case INPUT_CSI_DECSCUSR:
1803
846
    n = input_get(ictx, 0, 0, 0);
1804
846
    if (n == -1)
1805
66
      break;
1806
780
    screen_set_cursor_style(n, &s->cstyle, &s->mode);
1807
780
    if (n == 0) {
1808
      /* Go back to default blinking state. */
1809
262
      screen_write_mode_clear(sctx, MODE_CURSOR_BLINKING_SET);
1810
262
    }
1811
780
    break;
1812
422
  case INPUT_CSI_XDA:
1813
422
    n = input_get(ictx, 0, 0, 0);
1814
422
    if (n == 0) {
1815
275
      input_reply(ictx, 1, "\033P>|tmux %s\033\\",
1816
275
          getversion());
1817
275
    }
1818
422
    break;
1819
1820
45.3k
  }
1821
1822
45.3k
  ictx->flags &= ~INPUT_LAST;
1823
45.3k
  return (0);
1824
45.3k
}
1825
1826
/* Handle CSI RM. */
1827
static void
1828
input_csi_dispatch_rm(struct input_ctx *ictx)
1829
606
{
1830
606
  struct screen_write_ctx *sctx = &ictx->ctx;
1831
606
  u_int      i;
1832
1833
2.51k
  for (i = 0; i < ictx->param_list_len; i++) {
1834
1.90k
    switch (input_get(ictx, i, 0, -1)) {
1835
1.12k
    case -1:
1836
1.12k
      break;
1837
324
    case 4:   /* IRM */
1838
324
      screen_write_mode_clear(sctx, MODE_INSERT);
1839
324
      break;
1840
194
    case 34:
1841
194
      screen_write_mode_set(sctx, MODE_CURSOR_VERY_VISIBLE);
1842
194
      break;
1843
263
    default:
1844
263
      log_debug("%s: unknown '%c'", __func__, ictx->ch);
1845
263
      break;
1846
1.90k
    }
1847
1.90k
  }
1848
606
}
1849
1850
/* Handle CSI private RM. */
1851
static void
1852
input_csi_dispatch_rm_private(struct input_ctx *ictx)
1853
1.18k
{
1854
1.18k
  struct screen_write_ctx *sctx = &ictx->ctx;
1855
1.18k
  struct grid_cell  *gc = &ictx->cell.cell;
1856
1.18k
  u_int      i;
1857
1858
5.19k
  for (i = 0; i < ictx->param_list_len; i++) {
1859
4.00k
    switch (input_get(ictx, i, 0, -1)) {
1860
651
    case -1:
1861
651
      break;
1862
199
    case 1:   /* DECCKM */
1863
199
      screen_write_mode_clear(sctx, MODE_KCURSOR);
1864
199
      break;
1865
220
    case 3:   /* DECCOLM */
1866
220
      screen_write_cursormove(sctx, 0, 0, 1);
1867
220
      screen_write_clearscreen(sctx, gc->bg);
1868
220
      break;
1869
216
    case 6:   /* DECOM */
1870
216
      screen_write_mode_clear(sctx, MODE_ORIGIN);
1871
216
      screen_write_cursormove(sctx, 0, 0, 1);
1872
216
      break;
1873
322
    case 7:   /* DECAWM */
1874
322
      screen_write_mode_clear(sctx, MODE_WRAP);
1875
322
      break;
1876
272
    case 12:
1877
272
      screen_write_mode_clear(sctx, MODE_CURSOR_BLINKING);
1878
272
      screen_write_mode_set(sctx, MODE_CURSOR_BLINKING_SET);
1879
272
      break;
1880
194
    case 25:  /* TCEM */
1881
194
      screen_write_mode_clear(sctx, MODE_CURSOR);
1882
194
      break;
1883
66
    case 1000:
1884
132
    case 1001:
1885
198
    case 1002:
1886
264
    case 1003:
1887
264
      screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
1888
264
      break;
1889
66
    case 1004:
1890
66
      screen_write_mode_clear(sctx, MODE_FOCUSON);
1891
66
      break;
1892
66
    case 1005:
1893
66
      screen_write_mode_clear(sctx, MODE_MOUSE_UTF8);
1894
66
      break;
1895
66
    case 1006:
1896
66
      screen_write_mode_clear(sctx, MODE_MOUSE_SGR);
1897
66
      break;
1898
526
    case 47:
1899
592
    case 1047:
1900
592
      screen_write_alternateoff(sctx, gc, 0);
1901
592
      break;
1902
232
    case 1049:
1903
232
      screen_write_alternateoff(sctx, gc, 1);
1904
232
      break;
1905
66
    case 2004:
1906
66
      screen_write_mode_clear(sctx, MODE_BRACKETPASTE);
1907
66
      break;
1908
99
    case 2031:
1909
99
      screen_write_mode_clear(sctx, MODE_THEME_UPDATES);
1910
99
      if (ictx->wp != NULL)
1911
99
        ictx->wp->flags &= ~PANE_THEMECHANGED;
1912
99
      break;
1913
149
    case 2026:  /* synchronized output */
1914
149
      screen_write_stop_sync(ictx->wp);
1915
149
      if (ictx->wp != NULL)
1916
149
        ictx->wp->flags |= PANE_REDRAW;
1917
149
      break;
1918
333
    default:
1919
333
      log_debug("%s: unknown '%c'", __func__, ictx->ch);
1920
333
      break;
1921
4.00k
    }
1922
4.00k
  }
1923
1.18k
}
1924
1925
/* Handle CSI SM. */
1926
static void
1927
input_csi_dispatch_sm(struct input_ctx *ictx)
1928
673
{
1929
673
  struct screen_write_ctx *sctx = &ictx->ctx;
1930
673
  u_int      i;
1931
1932
2.17k
  for (i = 0; i < ictx->param_list_len; i++) {
1933
1.49k
    switch (input_get(ictx, i, 0, -1)) {
1934
764
    case -1:
1935
764
      break;
1936
265
    case 4:   /* IRM */
1937
265
      screen_write_mode_set(sctx, MODE_INSERT);
1938
265
      break;
1939
194
    case 34:
1940
194
      screen_write_mode_clear(sctx, MODE_CURSOR_VERY_VISIBLE);
1941
194
      break;
1942
274
    default:
1943
274
      log_debug("%s: unknown '%c'", __func__, ictx->ch);
1944
274
      break;
1945
1.49k
    }
1946
1.49k
  }
1947
673
}
1948
1949
/* Handle CSI private SM. */
1950
static void
1951
input_csi_dispatch_sm_private(struct input_ctx *ictx)
1952
1.00k
{
1953
1.00k
  struct screen_write_ctx *sctx = &ictx->ctx;
1954
1.00k
  struct grid_cell  *gc = &ictx->cell.cell;
1955
1.00k
  u_int      i;
1956
1957
5.04k
  for (i = 0; i < ictx->param_list_len; i++) {
1958
4.04k
    switch (input_get(ictx, i, 0, -1)) {
1959
772
    case -1:
1960
772
      break;
1961
215
    case 1:   /* DECCKM */
1962
215
      screen_write_mode_set(sctx, MODE_KCURSOR);
1963
215
      break;
1964
195
    case 3:   /* DECCOLM */
1965
195
      screen_write_cursormove(sctx, 0, 0, 1);
1966
195
      screen_write_clearscreen(sctx, ictx->cell.cell.bg);
1967
195
      break;
1968
261
    case 6:   /* DECOM */
1969
261
      screen_write_mode_set(sctx, MODE_ORIGIN);
1970
261
      screen_write_cursormove(sctx, 0, 0, 1);
1971
261
      break;
1972
200
    case 7:   /* DECAWM */
1973
200
      screen_write_mode_set(sctx, MODE_WRAP);
1974
200
      break;
1975
271
    case 12:
1976
271
      screen_write_mode_set(sctx, MODE_CURSOR_BLINKING);
1977
271
      screen_write_mode_set(sctx, MODE_CURSOR_BLINKING_SET);
1978
271
      break;
1979
194
    case 25:  /* TCEM */
1980
194
      screen_write_mode_set(sctx, MODE_CURSOR);
1981
194
      break;
1982
66
    case 1000:
1983
66
      screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
1984
66
      screen_write_mode_set(sctx, MODE_MOUSE_STANDARD);
1985
66
      break;
1986
66
    case 1002:
1987
66
      screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
1988
66
      screen_write_mode_set(sctx, MODE_MOUSE_BUTTON);
1989
66
      break;
1990
81
    case 1003:
1991
81
      screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
1992
81
      screen_write_mode_set(sctx, MODE_MOUSE_ALL);
1993
81
      break;
1994
67
    case 1004:
1995
67
      screen_write_mode_set(sctx, MODE_FOCUSON);
1996
67
      break;
1997
67
    case 1005:
1998
67
      screen_write_mode_set(sctx, MODE_MOUSE_UTF8);
1999
67
      break;
2000
67
    case 1006:
2001
67
      screen_write_mode_set(sctx, MODE_MOUSE_SGR);
2002
67
      break;
2003
545
    case 47:
2004
611
    case 1047:
2005
611
      screen_write_alternateon(sctx, gc, 0);
2006
611
      break;
2007
156
    case 1049:
2008
156
      screen_write_alternateon(sctx, gc, 1);
2009
156
      break;
2010
66
    case 2004:
2011
66
      screen_write_mode_set(sctx, MODE_BRACKETPASTE);
2012
66
      break;
2013
66
    case 2031:
2014
66
      screen_write_mode_set(sctx, MODE_THEME_UPDATES);
2015
66
      if (ictx->wp != NULL) {
2016
66
        ictx->wp->last_theme = window_pane_get_theme(ictx->wp);
2017
66
        ictx->wp->flags &= ~PANE_THEMECHANGED;
2018
66
      }
2019
66
      break;
2020
153
    case 2026:  /* synchronized output */
2021
153
      screen_write_start_sync(ictx->wp);
2022
153
      break;
2023
467
    default:
2024
467
      log_debug("%s: unknown '%c'", __func__, ictx->ch);
2025
467
      break;
2026
4.04k
    }
2027
4.04k
  }
2028
1.00k
}
2029
2030
/* Handle CSI graphics SM. */
2031
static void
2032
input_csi_dispatch_sm_graphics(__unused struct input_ctx *ictx)
2033
66
{
2034
#ifdef ENABLE_SIXEL
2035
  int n, m, o;
2036
2037
  if (ictx->param_list_len > 3)
2038
    return;
2039
  n = input_get(ictx, 0, 0, 0);
2040
  m = input_get(ictx, 1, 0, 0);
2041
  o = input_get(ictx, 2, 0, 0);
2042
2043
  if (n == 1 && (m == 1 || m == 2 || m == 4)) {
2044
    input_reply(ictx, 1, "\033[?%d;0;%uS", n,
2045
        SIXEL_COLOUR_REGISTERS);
2046
  } else
2047
    input_reply(ictx, 1, "\033[?%d;3;%dS", n, o);
2048
#endif
2049
66
}
2050
2051
/* Handle CSI window operations. */
2052
static void
2053
input_csi_dispatch_winops(struct input_ctx *ictx)
2054
2.54k
{
2055
2.54k
  struct screen_write_ctx *sctx = &ictx->ctx;
2056
2.54k
  struct screen   *s = sctx->s;
2057
2.54k
  struct window_pane  *wp = ictx->wp;
2058
2.54k
  struct window   *w = NULL;
2059
2.54k
  u_int      x = screen_size_x(s), y = screen_size_y(s);
2060
2.54k
  int      n, m;
2061
2062
2.54k
  if (wp != NULL)
2063
2.54k
    w = wp->window;
2064
2065
2.54k
  m = 0;
2066
6.66k
  while ((n = input_get(ictx, m, 0, -1)) != -1) {
2067
5.57k
    switch (n) {
2068
206
    case 1:
2069
416
    case 2:
2070
612
    case 5:
2071
812
    case 6:
2072
1.00k
    case 7:
2073
1.20k
    case 11:
2074
1.39k
    case 13:
2075
1.58k
    case 20:
2076
1.78k
    case 21:
2077
1.85k
    case 24:
2078
1.85k
      break;
2079
113
    case 3:
2080
487
    case 4:
2081
658
    case 8:
2082
658
      m++;
2083
658
      if (input_get(ictx, m, 0, -1) == -1)
2084
588
        return;
2085
      /* FALLTHROUGH */
2086
462
    case 9:
2087
528
    case 10:
2088
528
      m++;
2089
528
      if (input_get(ictx, m, 0, -1) == -1)
2090
457
        return;
2091
71
      break;
2092
71
    case 14:
2093
66
      if (w == NULL)
2094
0
        break;
2095
66
      input_reply(ictx, 1, "\033[4;%u;%ut", y * w->ypixel,
2096
66
          x * w->xpixel);
2097
66
      break;
2098
194
    case 15:
2099
194
      if (w == NULL)
2100
0
        break;
2101
194
      input_reply(ictx, 1, "\033[5;%u;%ut", y * w->ypixel,
2102
194
          x * w->xpixel);
2103
194
      break;
2104
194
    case 16:
2105
194
      if (w == NULL)
2106
0
        break;
2107
194
      input_reply(ictx, 1, "\033[6;%u;%ut", w->ypixel,
2108
194
          w->xpixel);
2109
194
      break;
2110
194
    case 18:
2111
194
      input_reply(ictx, 1, "\033[8;%u;%ut", y, x);
2112
194
      break;
2113
194
    case 19:
2114
194
      input_reply(ictx, 1, "\033[9;%u;%ut", y, x);
2115
194
      break;
2116
859
    case 22:
2117
859
      m++;
2118
859
      switch (input_get(ictx, m, 0, -1)) {
2119
199
      case -1:
2120
199
        return;
2121
258
      case 0:
2122
549
      case 2:
2123
549
        screen_push_title(sctx->s);
2124
549
        break;
2125
859
      }
2126
660
      break;
2127
660
    case 23:
2128
640
      m++;
2129
640
      switch (input_get(ictx, m, 0, -1)) {
2130
204
      case -1:
2131
204
        return;
2132
106
      case 0:
2133
321
      case 2:
2134
321
        screen_pop_title(sctx->s);
2135
321
        if (wp == NULL)
2136
0
          break;
2137
321
        notify_pane("pane-title-changed", wp);
2138
321
        server_redraw_window_borders(w);
2139
321
        server_status_window(w);
2140
321
        break;
2141
640
      }
2142
436
      break;
2143
436
    default:
2144
262
      log_debug("%s: unknown '%c'", __func__, ictx->ch);
2145
262
      break;
2146
5.57k
    }
2147
4.12k
    m++;
2148
4.12k
  }
2149
2.54k
}
2150
2151
/* Helper for 256 colour SGR. */
2152
static int
2153
input_csi_dispatch_sgr_256_do(struct input_ctx *ictx, int fgbg, int c)
2154
1.24k
{
2155
1.24k
  struct grid_cell  *gc = &ictx->cell.cell;
2156
2157
1.24k
  if (c == -1 || c > 255) {
2158
709
    if (fgbg == 38)
2159
189
      gc->fg = 8;
2160
520
    else if (fgbg == 48)
2161
310
      gc->bg = 8;
2162
709
  } else {
2163
535
    if (fgbg == 38)
2164
168
      gc->fg = c | COLOUR_FLAG_256;
2165
367
    else if (fgbg == 48)
2166
205
      gc->bg = c | COLOUR_FLAG_256;
2167
162
    else if (fgbg == 58)
2168
162
      gc->us = c | COLOUR_FLAG_256;
2169
535
  }
2170
1.24k
  return (1);
2171
1.24k
}
2172
2173
/* Handle CSI SGR for 256 colours. */
2174
static void
2175
input_csi_dispatch_sgr_256(struct input_ctx *ictx, int fgbg, u_int *i)
2176
689
{
2177
689
  int c;
2178
2179
689
  c = input_get(ictx, (*i) + 1, 0, -1);
2180
689
  if (input_csi_dispatch_sgr_256_do(ictx, fgbg, c))
2181
689
    (*i)++;
2182
689
}
2183
2184
/* Helper for RGB colour SGR. */
2185
static int
2186
input_csi_dispatch_sgr_rgb_do(struct input_ctx *ictx, int fgbg, int r, int g,
2187
    int b)
2188
2.42k
{
2189
2.42k
  struct grid_cell  *gc = &ictx->cell.cell;
2190
2191
2.42k
  if (r == -1 || r > 255)
2192
803
    return (0);
2193
1.62k
  if (g == -1 || g > 255)
2194
350
    return (0);
2195
1.27k
  if (b == -1 || b > 255)
2196
468
    return (0);
2197
2198
804
  if (fgbg == 38)
2199
241
    gc->fg = colour_join_rgb(r, g, b);
2200
563
  else if (fgbg == 48)
2201
411
    gc->bg = colour_join_rgb(r, g, b);
2202
152
  else if (fgbg == 58)
2203
152
    gc->us = colour_join_rgb(r, g, b);
2204
804
  return (1);
2205
1.27k
}
2206
2207
/* Handle CSI SGR for RGB colours. */
2208
static void
2209
input_csi_dispatch_sgr_rgb(struct input_ctx *ictx, int fgbg, u_int *i)
2210
1.62k
{
2211
1.62k
  int r, g, b;
2212
2213
1.62k
  r = input_get(ictx, (*i) + 1, 0, -1);
2214
1.62k
  g = input_get(ictx, (*i) + 2, 0, -1);
2215
1.62k
  b = input_get(ictx, (*i) + 3, 0, -1);
2216
1.62k
  if (input_csi_dispatch_sgr_rgb_do(ictx, fgbg, r, g, b))
2217
456
    (*i) += 3;
2218
1.62k
}
2219
2220
/* Handle CSI SGR with a ISO parameter. */
2221
static void
2222
input_csi_dispatch_sgr_colon(struct input_ctx *ictx, u_int i)
2223
3.33k
{
2224
3.33k
  struct grid_cell  *gc = &ictx->cell.cell;
2225
3.33k
  char      *s = ictx->param_list[i].str, *copy, *ptr, *out;
2226
3.33k
  int      p[8];
2227
3.33k
  u_int      n;
2228
3.33k
  const char    *errstr;
2229
2230
29.9k
  for (n = 0; n < nitems(p); n++)
2231
26.6k
    p[n] = -1;
2232
3.33k
  n = 0;
2233
2234
3.33k
  ptr = copy = xstrdup(s);
2235
13.8k
  while ((out = strsep(&ptr, ":")) != NULL) {
2236
10.7k
    if (*out != '\0') {
2237
6.91k
      p[n++] = strtonum(out, 0, INT_MAX, &errstr);
2238
6.91k
      if (errstr != NULL || n == nitems(p)) {
2239
150
        free(copy);
2240
150
        return;
2241
150
      }
2242
6.91k
    } else {
2243
3.79k
      n++;
2244
3.79k
      if (n == nitems(p)) {
2245
74
        free(copy);
2246
74
        return;
2247
74
      }
2248
3.79k
    }
2249
10.4k
    log_debug("%s: %u = %d", __func__, n - 1, p[n - 1]);
2250
10.4k
  }
2251
3.10k
  free(copy);
2252
2253
3.10k
  if (n == 0)
2254
0
    return;
2255
3.10k
  if (p[0] == 4) {
2256
749
    if (n != 2)
2257
74
      return;
2258
675
    switch (p[1]) {
2259
66
    case 0:
2260
66
      gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2261
66
      break;
2262
66
    case 1:
2263
66
      gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2264
66
      gc->attr |= GRID_ATTR_UNDERSCORE;
2265
66
      break;
2266
74
    case 2:
2267
74
      gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2268
74
      gc->attr |= GRID_ATTR_UNDERSCORE_2;
2269
74
      break;
2270
68
    case 3:
2271
68
      gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2272
68
      gc->attr |= GRID_ATTR_UNDERSCORE_3;
2273
68
      break;
2274
69
    case 4:
2275
69
      gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2276
69
      gc->attr |= GRID_ATTR_UNDERSCORE_4;
2277
69
      break;
2278
133
    case 5:
2279
133
      gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2280
133
      gc->attr |= GRID_ATTR_UNDERSCORE_5;
2281
133
      break;
2282
675
    }
2283
675
    return;
2284
675
  }
2285
2.36k
  if (n < 2 || (p[0] != 38 && p[0] != 48 && p[0] != 58))
2286
597
    return;
2287
1.76k
  switch (p[1]) {
2288
938
  case 2:
2289
938
    if (n < 3)
2290
66
      break;
2291
872
    if (n == 5)
2292
793
      i = 2;
2293
79
    else
2294
79
      i = 3;
2295
872
    if (n < i + 3)
2296
67
      break;
2297
805
    input_csi_dispatch_sgr_rgb_do(ictx, p[0], p[i], p[i + 1],
2298
805
        p[i + 2]);
2299
805
    break;
2300
621
  case 5:
2301
621
    if (n < 3)
2302
66
      break;
2303
555
    input_csi_dispatch_sgr_256_do(ictx, p[0], p[2]);
2304
555
    break;
2305
1.76k
  }
2306
1.76k
}
2307
2308
/* Handle CSI SGR. */
2309
static void
2310
input_csi_dispatch_sgr(struct input_ctx *ictx)
2311
3.91k
{
2312
3.91k
  struct grid_cell  *gc = &ictx->cell.cell;
2313
3.91k
  u_int      i, link;
2314
3.91k
  int      n;
2315
2316
3.91k
  if (ictx->param_list_len == 0) {
2317
242
    memcpy(gc, &grid_default_cell, sizeof *gc);
2318
242
    return;
2319
242
  }
2320
2321
21.8k
  for (i = 0; i < ictx->param_list_len; i++) {
2322
18.2k
    if (ictx->param_list[i].type == INPUT_STRING) {
2323
3.33k
      input_csi_dispatch_sgr_colon(ictx, i);
2324
3.33k
      continue;
2325
3.33k
    }
2326
14.8k
    n = input_get(ictx, i, 0, 0);
2327
14.8k
    if (n == -1)
2328
0
      continue;
2329
2330
14.8k
    if (n == 38 || n == 48 || n == 58) {
2331
2.75k
      i++;
2332
2.75k
      switch (input_get(ictx, i, 0, -1)) {
2333
1.62k
      case 2:
2334
1.62k
        input_csi_dispatch_sgr_rgb(ictx, n, &i);
2335
1.62k
        break;
2336
689
      case 5:
2337
689
        input_csi_dispatch_sgr_256(ictx, n, &i);
2338
689
        break;
2339
2.75k
      }
2340
2.75k
      continue;
2341
2.75k
    }
2342
2343
12.1k
    switch (n) {
2344
1.42k
    case 0:
2345
1.42k
      link = gc->link;
2346
1.42k
      memcpy(gc, &grid_default_cell, sizeof *gc);
2347
1.42k
      gc->link = link;
2348
1.42k
      break;
2349
283
    case 1:
2350
283
      gc->attr |= GRID_ATTR_BRIGHT;
2351
283
      break;
2352
352
    case 2:
2353
352
      gc->attr |= GRID_ATTR_DIM;
2354
352
      break;
2355
303
    case 3:
2356
303
      gc->attr |= GRID_ATTR_ITALICS;
2357
303
      break;
2358
271
    case 4:
2359
271
      gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2360
271
      gc->attr |= GRID_ATTR_UNDERSCORE;
2361
271
      break;
2362
263
    case 5:
2363
543
    case 6:
2364
543
      gc->attr |= GRID_ATTR_BLINK;
2365
543
      break;
2366
209
    case 7:
2367
209
      gc->attr |= GRID_ATTR_REVERSE;
2368
209
      break;
2369
237
    case 8:
2370
237
      gc->attr |= GRID_ATTR_HIDDEN;
2371
237
      break;
2372
246
    case 9:
2373
246
      gc->attr |= GRID_ATTR_STRIKETHROUGH;
2374
246
      break;
2375
204
    case 21:
2376
204
      gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2377
204
      gc->attr |= GRID_ATTR_UNDERSCORE_2;
2378
204
      break;
2379
194
    case 22:
2380
194
      gc->attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_DIM);
2381
194
      break;
2382
194
    case 23:
2383
194
      gc->attr &= ~GRID_ATTR_ITALICS;
2384
194
      break;
2385
194
    case 24:
2386
194
      gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2387
194
      break;
2388
194
    case 25:
2389
194
      gc->attr &= ~GRID_ATTR_BLINK;
2390
194
      break;
2391
67
    case 27:
2392
67
      gc->attr &= ~GRID_ATTR_REVERSE;
2393
67
      break;
2394
196
    case 28:
2395
196
      gc->attr &= ~GRID_ATTR_HIDDEN;
2396
196
      break;
2397
195
    case 29:
2398
195
      gc->attr &= ~GRID_ATTR_STRIKETHROUGH;
2399
195
      break;
2400
197
    case 30:
2401
397
    case 31:
2402
595
    case 32:
2403
794
    case 33:
2404
989
    case 34:
2405
1.18k
    case 35:
2406
1.37k
    case 36:
2407
1.57k
    case 37:
2408
1.57k
      gc->fg = n - 30;
2409
1.57k
      break;
2410
195
    case 39:
2411
195
      gc->fg = 8;
2412
195
      break;
2413
245
    case 40:
2414
448
    case 41:
2415
661
    case 42:
2416
896
    case 43:
2417
977
    case 44:
2418
1.18k
    case 45:
2419
1.27k
    case 46:
2420
1.47k
    case 47:
2421
1.47k
      gc->bg = n - 40;
2422
1.47k
      break;
2423
194
    case 49:
2424
194
      gc->bg = 8;
2425
194
      break;
2426
202
    case 53:
2427
202
      gc->attr |= GRID_ATTR_OVERLINE;
2428
202
      break;
2429
194
    case 55:
2430
194
      gc->attr &= ~GRID_ATTR_OVERLINE;
2431
194
      break;
2432
194
    case 59:
2433
194
      gc->us = 8;
2434
194
      break;
2435
198
    case 90:
2436
393
    case 91:
2437
591
    case 92:
2438
786
    case 93:
2439
981
    case 94:
2440
1.17k
    case 95:
2441
1.50k
    case 96:
2442
1.70k
    case 97:
2443
1.70k
      gc->fg = n;
2444
1.70k
      break;
2445
67
    case 100:
2446
133
    case 101:
2447
199
    case 102:
2448
265
    case 103:
2449
332
    case 104:
2450
403
    case 105:
2451
525
    case 106:
2452
594
    case 107:
2453
594
      gc->bg = n - 10;
2454
594
      break;
2455
12.1k
    }
2456
12.1k
  }
2457
3.67k
}
2458
2459
/* End of input with BEL. */
2460
static int
2461
input_end_bel(struct input_ctx *ictx)
2462
432
{
2463
432
  log_debug("%s", __func__);
2464
2465
432
  ictx->input_end = INPUT_END_BEL;
2466
2467
432
  return (0);
2468
432
}
2469
2470
/* DCS string started. */
2471
static void
2472
input_enter_dcs(struct input_ctx *ictx)
2473
977
{
2474
977
  log_debug("%s", __func__);
2475
2476
977
  input_clear(ictx);
2477
977
  input_start_ground_timer(ictx);
2478
977
  ictx->flags &= ~INPUT_LAST;
2479
977
}
2480
2481
/* Handle DECRQSS query. */
2482
static int
2483
input_handle_decrqss(struct input_ctx *ictx)
2484
485
{
2485
485
  struct window_pane  *wp = ictx->wp;
2486
485
  struct options    *oo;
2487
485
  struct screen_write_ctx *sctx = &ictx->ctx;
2488
485
  u_char      *buf = ictx->input_buf;
2489
485
  size_t       len = ictx->input_len;
2490
485
  struct screen   *s = sctx->s;
2491
485
  int      ps, opt_ps, blinking;
2492
2493
485
  if (len < 3 || buf[1] != ' ' || buf[2] != 'q')
2494
219
    goto not_recognized;
2495
2496
  /*
2497
   * Cursor style query: DCS $ q SP q
2498
   * Reply: DCS 1 $ r SP q <Ps> SP q ST
2499
   */
2500
266
  if (s->cstyle == SCREEN_CURSOR_BLOCK ||
2501
199
      s->cstyle == SCREEN_CURSOR_UNDERLINE ||
2502
199
      s->cstyle == SCREEN_CURSOR_BAR) {
2503
199
    blinking = (s->mode & MODE_CURSOR_BLINKING) != 0;
2504
199
    switch (s->cstyle) {
2505
67
    case SCREEN_CURSOR_BLOCK:
2506
67
      ps = blinking ? 1 : 2;
2507
67
      break;
2508
66
    case SCREEN_CURSOR_UNDERLINE:
2509
66
      ps = blinking ? 3 : 4;
2510
66
      break;
2511
66
    case SCREEN_CURSOR_BAR:
2512
66
      ps = blinking ? 5 : 6;
2513
66
      break;
2514
0
    default:
2515
0
      ps = 0;
2516
0
      break;
2517
199
    }
2518
199
  } else {
2519
    /*
2520
     * No explicit runtime style: fall back to the configured
2521
     * cursor-style option (integer Ps 0..6). Pane options inherit.
2522
     */
2523
67
    if (wp != NULL)
2524
67
      oo = wp->options;
2525
0
    else
2526
0
      oo = global_w_options;
2527
67
    opt_ps = options_get_number(oo, "cursor-style");
2528
2529
    /* Sanity clamp: valid Ps are 0..6 per DECSCUSR. */
2530
67
    if (opt_ps < 0 || opt_ps > 6)
2531
0
      opt_ps = 0;
2532
67
    ps = opt_ps;
2533
67
  }
2534
2535
266
  log_debug("%s: DECRQSS cursor -> Ps=%d (cstyle=%d mode=%#x)", __func__,
2536
266
      ps, s->cstyle, s->mode);
2537
2538
266
  input_reply(ictx, 1, "\033P1$r q%d q\033\\", ps);
2539
266
  return (0);
2540
2541
219
not_recognized:
2542
  /* Unrecognized DECRQSS: send DCS 0 $ r Pt ST. */
2543
219
  input_reply(ictx, 1, "\033P0$r\033\\");
2544
219
  return (0);
2545
266
}
2546
2547
/* DCS terminator (ST) received. */
2548
static int
2549
input_dcs_dispatch(struct input_ctx *ictx)
2550
758
{
2551
758
  struct window_pane  *wp = ictx->wp;
2552
758
  struct options    *oo;
2553
758
  struct screen_write_ctx *sctx = &ictx->ctx;
2554
758
  u_char      *buf = ictx->input_buf;
2555
758
  size_t       len = ictx->input_len;
2556
758
  const char     prefix[] = "tmux;";
2557
758
  const u_int    prefixlen = (sizeof prefix) - 1;
2558
758
  long long    allow_passthrough = 0;
2559
#ifdef ENABLE_SIXEL
2560
  struct window   *w;
2561
  struct sixel_image  *si;
2562
  int      p2;
2563
#endif
2564
2565
758
  if (wp == NULL)
2566
0
    oo = global_w_options;
2567
758
  else
2568
758
    oo = wp->options;
2569
2570
758
  if (ictx->flags & INPUT_DISCARD) {
2571
66
    log_debug("%s: %zu bytes (discard)", __func__, len);
2572
66
    return (0);
2573
66
  }
2574
2575
#ifdef ENABLE_SIXEL
2576
  if (wp != NULL && buf[0] == 'q' && ictx->interm_len == 0) {
2577
    w = wp->window;
2578
    if (input_split(ictx) != 0)
2579
      return (0);
2580
    p2 = input_get(ictx, 1, 0, 0);
2581
    if (p2 == -1)
2582
      p2 = 0;
2583
    si = sixel_parse(buf, len, p2, w->xpixel, w->ypixel);
2584
    if (si != NULL)
2585
      screen_write_sixelimage(sctx, si, ictx->cell.cell.bg);
2586
  }
2587
#endif
2588
2589
  /* DCS sequences with intermediate byte '$' (includes DECRQSS). */
2590
692
  if (ictx->interm_len == 1 && ictx->interm_buf[0] == '$') {
2591
    /* DECRQSS is DCS $ q Pt ST. */
2592
557
    if (len >= 1 && buf[0] == 'q')
2593
485
      return (input_handle_decrqss(ictx));
2594
2595
    /*
2596
     * Not DECRQSS. DCS '$' is currently only used by DECRQSS, but
2597
     * leave other '$' DCS (if any appear in future) to existing
2598
     * handlers.
2599
     */
2600
557
  }
2601
2602
207
  allow_passthrough = options_get_number(oo, "allow-passthrough");
2603
207
  if (!allow_passthrough)
2604
207
    return (0);
2605
0
  log_debug("%s: \"%s\"", __func__, buf);
2606
2607
0
  if (len >= prefixlen && strncmp(buf, prefix, prefixlen) == 0) {
2608
0
    screen_write_rawstring(sctx, buf + prefixlen, len - prefixlen,
2609
0
        allow_passthrough == 2);
2610
0
  }
2611
2612
0
  return (0);
2613
207
}
2614
2615
/* OSC string started. */
2616
static void
2617
input_enter_osc(struct input_ctx *ictx)
2618
14.9k
{
2619
14.9k
  log_debug("%s", __func__);
2620
2621
14.9k
  input_clear(ictx);
2622
14.9k
  input_start_ground_timer(ictx);
2623
14.9k
  ictx->flags &= ~INPUT_LAST;
2624
14.9k
}
2625
2626
/* OSC terminator (ST) received. */
2627
static void
2628
input_exit_osc(struct input_ctx *ictx)
2629
14.9k
{
2630
14.9k
  struct screen_write_ctx *sctx = &ictx->ctx;
2631
14.9k
  struct window_pane  *wp = ictx->wp;
2632
14.9k
  u_char      *p = ictx->input_buf;
2633
14.9k
  u_int      option;
2634
2635
14.9k
  if (ictx->flags & INPUT_DISCARD)
2636
0
    return;
2637
14.9k
  if (ictx->input_len < 1 || *p < '0' || *p > '9')
2638
1.10k
    return;
2639
2640
13.8k
  log_debug("%s: \"%s\" (end %s)", __func__, p,
2641
13.8k
      ictx->input_end == INPUT_END_ST ? "ST" : "BEL");
2642
2643
13.8k
  option = 0;
2644
32.4k
  while (*p >= '0' && *p <= '9')
2645
18.6k
    option = option * 10 + *p++ - '0';
2646
13.8k
  if (*p != ';' && *p != '\0')
2647
113
    return;
2648
13.6k
  if (*p == ';')
2649
11.6k
    p++;
2650
2651
13.6k
  switch (option) {
2652
282
  case 0:
2653
494
  case 2:
2654
494
    if (wp != NULL &&
2655
494
        options_get_number(wp->options, "allow-set-title") &&
2656
494
        screen_set_title(sctx->s, p)) {
2657
74
      notify_pane("pane-title-changed", wp);
2658
74
      server_redraw_window_borders(wp->window);
2659
74
      server_status_window(wp->window);
2660
74
    }
2661
494
    break;
2662
782
  case 4:
2663
782
    input_osc_4(ictx, p);
2664
782
    break;
2665
273
  case 7:
2666
273
    if (screen_set_path(sctx->s, p) && wp != NULL) {
2667
67
      server_redraw_window_borders(wp->window);
2668
67
      server_status_window(wp->window);
2669
67
    }
2670
273
    break;
2671
7.06k
  case 8:
2672
7.06k
    input_osc_8(ictx, p);
2673
7.06k
    break;
2674
1.19k
  case 9:
2675
1.19k
    input_osc_9(ictx, p);
2676
1.19k
    break;
2677
240
  case 10:
2678
240
    input_osc_10(ictx, p);
2679
240
    break;
2680
248
  case 11:
2681
248
    input_osc_11(ictx, p);
2682
248
    break;
2683
512
  case 12:
2684
512
    input_osc_12(ictx, p);
2685
512
    break;
2686
1.72k
  case 52:
2687
1.72k
    input_osc_52(ictx, p);
2688
1.72k
    break;
2689
306
  case 104:
2690
306
    input_osc_104(ictx, p);
2691
306
    break;
2692
135
  case 110:
2693
135
    input_osc_110(ictx, p);
2694
135
    break;
2695
139
  case 111:
2696
139
    input_osc_111(ictx, p);
2697
139
    break;
2698
138
  case 112:
2699
138
    input_osc_112(ictx, p);
2700
138
    break;
2701
201
  case 133:
2702
201
    input_osc_133(ictx, p);
2703
201
    break;
2704
242
  default:
2705
242
    log_debug("%s: unknown '%u'", __func__, option);
2706
242
    break;
2707
13.6k
  }
2708
13.6k
}
2709
2710
/* APC string started. */
2711
static void
2712
input_enter_apc(struct input_ctx *ictx)
2713
2.67k
{
2714
2.67k
  log_debug("%s", __func__);
2715
2716
2.67k
  input_clear(ictx);
2717
2.67k
  input_start_ground_timer(ictx);
2718
2.67k
  ictx->flags &= ~INPUT_LAST;
2719
2.67k
}
2720
2721
/* APC terminator (ST) received. */
2722
static void
2723
input_exit_apc(struct input_ctx *ictx)
2724
2.66k
{
2725
2.66k
  struct screen_write_ctx *sctx = &ictx->ctx;
2726
2.66k
  struct window_pane  *wp = ictx->wp;
2727
2728
2.66k
  if (ictx->flags & INPUT_DISCARD)
2729
0
    return;
2730
2.66k
  log_debug("%s: \"%s\"", __func__, ictx->input_buf);
2731
2732
2.66k
  if (wp != NULL &&
2733
2.66k
      options_get_number(wp->options, "allow-set-title") &&
2734
2.66k
      screen_set_title(sctx->s, ictx->input_buf)) {
2735
1.45k
    notify_pane("pane-title-changed", wp);
2736
1.45k
    server_redraw_window_borders(wp->window);
2737
1.45k
    server_status_window(wp->window);
2738
1.45k
  }
2739
2.66k
}
2740
2741
/* Rename string started. */
2742
static void
2743
input_enter_rename(struct input_ctx *ictx)
2744
2.82k
{
2745
2.82k
  log_debug("%s", __func__);
2746
2747
2.82k
  input_clear(ictx);
2748
2.82k
  input_start_ground_timer(ictx);
2749
2.82k
  ictx->flags &= ~INPUT_LAST;
2750
2.82k
}
2751
2752
/* Rename terminator (ST) received. */
2753
static void
2754
input_exit_rename(struct input_ctx *ictx)
2755
2.81k
{
2756
2.81k
  struct window_pane  *wp = ictx->wp;
2757
2.81k
  struct window   *w;
2758
2.81k
  struct options_entry  *o;
2759
2760
2.81k
  if (wp == NULL)
2761
0
    return;
2762
2.81k
  if (ictx->flags & INPUT_DISCARD)
2763
0
    return;
2764
2.81k
  if (!options_get_number(ictx->wp->options, "allow-rename"))
2765
0
    return;
2766
2.81k
  log_debug("%s: \"%s\"", __func__, ictx->input_buf);
2767
2768
2.81k
  if (!utf8_isvalid(ictx->input_buf))
2769
549
    return;
2770
2.26k
  w = wp->window;
2771
2772
2.26k
  if (ictx->input_len == 0) {
2773
877
    o = options_get_only(w->options, "automatic-rename");
2774
877
    if (o != NULL)
2775
94
      options_remove_or_default(o, -1, NULL);
2776
877
    if (!options_get_number(w->options, "automatic-rename"))
2777
0
      window_set_name(w, "");
2778
1.38k
  } else {
2779
1.38k
    options_set_number(w->options, "automatic-rename", 0);
2780
1.38k
    window_set_name(w, ictx->input_buf);
2781
1.38k
  }
2782
2.26k
  server_redraw_window_borders(w);
2783
2.26k
  server_status_window(w);
2784
2.26k
}
2785
2786
/* Open UTF-8 character. */
2787
static int
2788
input_top_bit_set(struct input_ctx *ictx)
2789
7.96k
{
2790
7.96k
  struct screen_write_ctx *sctx = &ictx->ctx;
2791
7.96k
  struct utf8_data  *ud = &ictx->utf8data;
2792
2793
7.96k
  ictx->flags &= ~INPUT_LAST;
2794
2795
7.96k
  if (!ictx->utf8started) {
2796
6.56k
    ictx->utf8started = 1;
2797
6.56k
    if (utf8_open(ud, ictx->ch) != UTF8_MORE)
2798
4.46k
      input_stop_utf8(ictx);
2799
6.56k
    return (0);
2800
6.56k
  }
2801
2802
1.40k
  switch (utf8_append(ud, ictx->ch)) {
2803
537
  case UTF8_MORE:
2804
537
    return (0);
2805
867
  case UTF8_ERROR:
2806
867
    input_stop_utf8(ictx);
2807
867
    return (0);
2808
0
  case UTF8_DONE:
2809
0
    break;
2810
1.40k
  }
2811
0
  ictx->utf8started = 0;
2812
2813
0
  log_debug("%s %hhu '%*s' (width %hhu)", __func__, ud->size,
2814
0
      (int)ud->size, ud->data, ud->width);
2815
2816
0
  utf8_copy(&ictx->cell.cell.data, ud);
2817
0
  screen_write_collect_add(sctx, &ictx->cell.cell);
2818
2819
0
  utf8_copy(&ictx->last, &ictx->cell.cell.data);
2820
0
  ictx->flags |= INPUT_LAST;
2821
2822
0
  return (0);
2823
1.40k
}
2824
2825
/* Reply to a colour request. */
2826
static void
2827
input_osc_colour_reply(struct input_ctx *ictx, int add, u_int n, int idx, int c,
2828
    enum input_end_type end_type)
2829
356
{
2830
356
  u_char     r, g, b;
2831
356
  const char  *end;
2832
2833
356
  if (c != -1)
2834
154
    c = colour_force_rgb(c);
2835
356
  if (c == -1)
2836
202
      return;
2837
154
  colour_split_rgb(c, &r, &g, &b);
2838
2839
154
  if (end_type == INPUT_END_BEL)
2840
75
    end = "\007";
2841
79
  else
2842
79
    end = "\033\\";
2843
2844
154
  if (n == 4) {
2845
0
    input_reply(ictx, add,
2846
0
        "\033]%u;%d;rgb:%02hhx%02hhx/%02hhx%02hhx/%02hhx%02hhx%s",
2847
0
        n, idx, r, r, g, g, b, b, end);
2848
154
  } else {
2849
154
    input_reply(ictx, add,
2850
154
        "\033]%u;rgb:%02hhx%02hhx/%02hhx%02hhx/%02hhx%02hhx%s",
2851
154
        n, r, r, g, g, b, b, end);
2852
154
  }
2853
154
}
2854
2855
/* Handle the OSC 4 sequence for setting (multiple) palette entries. */
2856
static void
2857
input_osc_4(struct input_ctx *ictx, const char *p)
2858
782
{
2859
782
  char      *copy, *s, *next = NULL;
2860
782
  long       idx;
2861
782
  int      c, bad = 0, redraw = 0;
2862
782
  struct colour_palette *palette = ictx->palette;
2863
2864
782
  copy = s = xstrdup(p);
2865
3.14k
  while (s != NULL && *s != '\0') {
2866
2.56k
    idx = strtol(s, &next, 10);
2867
2.56k
    if (*next++ != ';') {
2868
173
      bad = 1;
2869
173
      break;
2870
173
    }
2871
2.38k
    if (idx < 0 || idx >= 256) {
2872
28
      bad = 1;
2873
28
      break;
2874
28
    }
2875
2876
2.36k
    s = strsep(&next, ";");
2877
2.36k
    if (strcmp(s, "?") == 0) {
2878
200
      c = colour_palette_get(palette, idx|COLOUR_FLAG_256);
2879
200
      if (c != -1) {
2880
0
        input_osc_colour_reply(ictx, 1, 4, idx, c,
2881
0
            ictx->input_end);
2882
0
        s = next;
2883
0
        continue;
2884
0
      }
2885
200
      input_add_request(ictx, INPUT_REQUEST_PALETTE, idx);
2886
200
      s = next;
2887
200
      continue;
2888
200
    }
2889
2.16k
    if ((c = colour_parseX11(s)) == -1) {
2890
1.50k
      s = next;
2891
1.50k
      continue;
2892
1.50k
    }
2893
660
    if (colour_palette_set(palette, idx, c))
2894
0
      redraw = 1;
2895
660
    s = next;
2896
660
  }
2897
782
  if (bad)
2898
201
    log_debug("bad OSC 4: %s", p);
2899
782
  if (redraw)
2900
0
    screen_write_fullredraw(&ictx->ctx);
2901
782
  free(copy);
2902
782
}
2903
2904
/* Handle the OSC 8 sequence for embedding hyperlinks. */
2905
static void
2906
input_osc_8(struct input_ctx *ictx, const char *p)
2907
7.06k
{
2908
7.06k
  struct hyperlinks *hl = ictx->ctx.s->hyperlinks;
2909
7.06k
  struct grid_cell  *gc = &ictx->cell.cell;
2910
7.06k
  const char    *start, *end, *uri;
2911
7.06k
  char      *id = NULL;
2912
2913
7.62k
  for (start = p; (end = strpbrk(start, ":;")) != NULL; start = end + 1) {
2914
7.33k
    if (end - start >= 4 && strncmp(start, "id=", 3) == 0) {
2915
2.63k
      if (id != NULL)
2916
66
        goto bad;
2917
2.56k
      id = xstrndup(start + 3, end - start - 3);
2918
2.56k
    }
2919
2920
    /* The first ; is the end of parameters and start of the URI. */
2921
7.26k
    if (*end == ';')
2922
6.69k
      break;
2923
7.26k
  }
2924
6.99k
  if (end == NULL || *end != ';')
2925
297
    goto bad;
2926
6.69k
  uri = end + 1;
2927
6.69k
  if (*uri == '\0') {
2928
103
    gc->link = 0;
2929
103
    free(id);
2930
103
    return;
2931
103
  }
2932
6.59k
  gc->link = hyperlinks_put(hl, uri, id);
2933
6.59k
  if (id == NULL)
2934
4.11k
    log_debug("hyperlink (anonymous) %s = %u", uri, gc->link);
2935
2.48k
  else
2936
2.48k
    log_debug("hyperlink (id=%s) %s = %u", id, uri, gc->link);
2937
6.59k
  free(id);
2938
6.59k
  return;
2939
2940
363
bad:
2941
363
  log_debug("bad OSC 8 %s", p);
2942
363
  free(id);
2943
363
}
2944
2945
/* Helper to handle setting the progress bar and redrawing. */
2946
static void
2947
input_set_progress_bar(struct input_ctx *ictx, enum progress_bar_state state,
2948
    int p)
2949
318
{
2950
318
  screen_set_progress_bar(ictx->ctx.s, state, p);
2951
318
  if (ictx->wp != NULL) {
2952
318
    server_redraw_window_borders(ictx->wp->window);
2953
318
    server_status_window(ictx->wp->window);
2954
318
  }
2955
318
}
2956
2957
/* Handle the OSC 9;4 sequence for progress bars. */
2958
static void
2959
input_osc_9(struct input_ctx *ictx, const char *p)
2960
1.19k
{
2961
1.19k
  const char    *pb = p;
2962
1.19k
  enum progress_bar_state  state;
2963
1.19k
  int      progress = 0;
2964
2965
1.19k
  if (*pb++ != '4')
2966
208
    return;
2967
985
  if (*pb == '\0' || (*pb == ';' && pb[1] == '\0'))
2968
135
    return;
2969
2970
850
  if (*pb++ != ';')
2971
76
    return;
2972
774
  if (*pb < '0' || *pb > '4')
2973
167
    goto bad;
2974
607
  state = *pb++ - '0';
2975
2976
607
  if (*pb == '\0' || (*pb == ';' && pb[1] == '\0')) {
2977
140
    input_set_progress_bar(ictx, state, -1);
2978
140
    return;
2979
140
  }
2980
2981
467
  if (*pb++ != ';')
2982
77
    goto bad;
2983
1.16k
  while (*pb >= '0' && *pb <= '9') {
2984
843
    if (progress > 100)
2985
66
      goto bad;
2986
777
    progress = progress * 10 + *pb++ - '0';
2987
777
  }
2988
324
  if (*pb != '\0' || progress < 0 || progress > 100)
2989
146
    goto bad;
2990
178
  input_set_progress_bar(ictx, state, progress);
2991
178
  return;
2992
2993
456
bad:
2994
456
  log_debug("bad OSC 9;4 %s", p);
2995
456
}
2996
2997
/* Handle the OSC 10 sequence for setting and querying foreground colour. */
2998
static void
2999
input_osc_10(struct input_ctx *ictx, const char *p)
3000
240
{
3001
240
  struct window_pane  *wp = ictx->wp;
3002
240
  struct grid_cell   defaults;
3003
240
  int      c;
3004
3005
240
  if (strcmp(p, "?") == 0) {
3006
69
    if (wp == NULL)
3007
0
      return;
3008
69
    c = window_pane_get_fg_control_client(wp);
3009
69
    if (c == -1) {
3010
69
      tty_default_colours(&defaults, wp);
3011
69
      if (COLOUR_DEFAULT(defaults.fg))
3012
69
        c = window_pane_get_fg(wp);
3013
0
      else
3014
0
        c = defaults.fg;
3015
69
    }
3016
69
    input_osc_colour_reply(ictx, 1, 10, 0, c, ictx->input_end);
3017
69
    return;
3018
69
  }
3019
3020
171
  if ((c = colour_parseX11(p)) == -1) {
3021
81
    log_debug("bad OSC 10: %s", p);
3022
81
    return;
3023
81
  }
3024
90
  if (ictx->palette != NULL) {
3025
0
    ictx->palette->fg = c;
3026
0
    if (wp != NULL)
3027
0
      wp->flags |= PANE_STYLECHANGED;
3028
0
    screen_write_fullredraw(&ictx->ctx);
3029
0
  }
3030
90
}
3031
3032
/* Handle the OSC 110 sequence for resetting foreground colour. */
3033
static void
3034
input_osc_110(struct input_ctx *ictx, const char *p)
3035
135
{
3036
135
  struct window_pane  *wp = ictx->wp;
3037
3038
135
  if (*p != '\0')
3039
68
    return;
3040
67
  if (ictx->palette != NULL) {
3041
0
    ictx->palette->fg = 8;
3042
0
    if (wp != NULL)
3043
0
      wp->flags |= PANE_STYLECHANGED;
3044
0
    screen_write_fullredraw(&ictx->ctx);
3045
0
  }
3046
67
}
3047
3048
/* Handle the OSC 11 sequence for setting and querying background colour. */
3049
static void
3050
input_osc_11(struct input_ctx *ictx, const char *p)
3051
248
{
3052
248
  struct window_pane  *wp = ictx->wp;
3053
248
  int      c;
3054
3055
248
  if (strcmp(p, "?") == 0) {
3056
66
    if (wp == NULL)
3057
0
      return;
3058
66
    c = window_pane_get_bg(wp);
3059
66
    input_osc_colour_reply(ictx, 1, 11, 0, c, ictx->input_end);
3060
66
    return;
3061
66
  }
3062
3063
182
  if ((c = colour_parseX11(p)) == -1) {
3064
93
    log_debug("bad OSC 11: %s", p);
3065
93
    return;
3066
93
  }
3067
89
  if (ictx->palette != NULL) {
3068
0
    ictx->palette->bg = c;
3069
0
    if (wp != NULL)
3070
0
      wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED);
3071
0
    screen_write_fullredraw(&ictx->ctx);
3072
0
  }
3073
89
}
3074
3075
/* Handle the OSC 111 sequence for resetting background colour. */
3076
static void
3077
input_osc_111(struct input_ctx *ictx, const char *p)
3078
139
{
3079
139
  struct window_pane  *wp = ictx->wp;
3080
3081
139
  if (*p != '\0')
3082
72
    return;
3083
67
  if (ictx->palette != NULL) {
3084
0
    ictx->palette->bg = 8;
3085
0
    if (wp != NULL)
3086
0
      wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED);
3087
0
    screen_write_fullredraw(&ictx->ctx);
3088
0
  }
3089
67
}
3090
3091
/* Handle the OSC 12 sequence for setting and querying cursor colour. */
3092
static void
3093
input_osc_12(struct input_ctx *ictx, const char *p)
3094
512
{
3095
512
  struct window_pane  *wp = ictx->wp;
3096
512
  int      c;
3097
3098
512
  if (strcmp(p, "?") == 0) {
3099
221
    if (wp != NULL) {
3100
221
      c = ictx->ctx.s->ccolour;
3101
221
      if (c == -1)
3102
67
        c = ictx->ctx.s->default_ccolour;
3103
221
      input_osc_colour_reply(ictx, 1, 12, 0, c, ictx->input_end);
3104
221
    }
3105
221
    return;
3106
221
  }
3107
3108
291
  if ((c = colour_parseX11(p)) == -1) {
3109
168
    log_debug("bad OSC 12: %s", p);
3110
168
    return;
3111
168
  }
3112
123
  screen_set_cursor_colour(ictx->ctx.s, c);
3113
123
}
3114
3115
/* Handle the OSC 112 sequence for resetting cursor colour. */
3116
static void
3117
input_osc_112(struct input_ctx *ictx, const char *p)
3118
138
{
3119
138
  if (*p == '\0') /* no arguments allowed */
3120
66
    screen_set_cursor_colour(ictx->ctx.s, -1);
3121
138
}
3122
3123
/* Handle the OSC 133 sequence. */
3124
static void
3125
input_osc_133(struct input_ctx *ictx, const char *p)
3126
201
{
3127
201
  struct grid   *gd = ictx->ctx.s->grid;
3128
201
  u_int      line = ictx->ctx.s->cy + gd->hsize;
3129
201
  struct grid_line  *gl;
3130
3131
201
  if (line > gd->hsize + gd->sy - 1)
3132
0
    return;
3133
201
  gl = grid_get_line(gd, line);
3134
3135
201
  switch (*p) {
3136
66
  case 'A':
3137
66
    gl->flags |= GRID_LINE_START_PROMPT;
3138
66
    break;
3139
66
  case 'C':
3140
66
    gl->flags |= GRID_LINE_START_OUTPUT;
3141
66
    break;
3142
201
  }
3143
201
}
3144
3145
/* Handle OSC 52 reply. */
3146
static void
3147
input_osc_52_reply(struct input_ctx *ictx, char clip)
3148
250
{
3149
250
  struct bufferevent  *ev = ictx->event;
3150
250
  struct paste_buffer *pb;
3151
250
  int      state;
3152
250
  const char    *buf;
3153
250
  size_t       len;
3154
3155
250
  state = options_get_number(global_options, "get-clipboard");
3156
250
  if (state == 0)
3157
0
    return;
3158
250
  if (state == 1) {
3159
250
    if ((pb = paste_get_top(NULL)) == NULL)
3160
4
      return;
3161
246
    buf = paste_buffer_data(pb, &len);
3162
246
    if (ictx->input_end == INPUT_END_BEL)
3163
71
      input_reply_clipboard(ev, buf, len, "\007", clip);
3164
175
    else
3165
175
      input_reply_clipboard(ev, buf, len, "\033\\", clip);
3166
246
    return;
3167
250
  }
3168
0
  input_add_request(ictx, INPUT_REQUEST_CLIPBOARD, ictx->input_end);
3169
0
}
3170
3171
/*
3172
 * Parse and decode OSC 52 clipboard data. Returns 0 on failure or if handled
3173
 * as a query. On success, returns 1 and sets *out, *outlen, and *flags (caller
3174
 * must free *out).
3175
 */
3176
static int
3177
input_osc_52_parse(struct input_ctx *ictx, const char *p, u_char **out,
3178
    int *outlen, char *clip)
3179
1.72k
{
3180
1.72k
  char    *end;
3181
1.72k
  size_t     len;
3182
1.72k
  const char  *allow = "cpqs01234567";
3183
1.72k
  u_int    i, j = 0;
3184
3185
1.72k
  if (options_get_number(global_options, "set-clipboard") != 2)
3186
0
    return (0);
3187
3188
1.72k
  if ((end = strchr(p, ';')) == NULL)
3189
72
    return (0);
3190
1.65k
  end++;
3191
1.65k
  if (*end == '\0')
3192
69
    return (0);
3193
1.58k
  log_debug("%s: %s", __func__, end);
3194
3195
4.10k
  for (i = 0; p + i != end; i++) {
3196
2.52k
    if (strchr(allow, p[i]) != NULL && strchr(clip, p[i]) == NULL)
3197
313
      clip[j++] = p[i];
3198
2.52k
  }
3199
1.58k
  log_debug("%s: %.*s %s", __func__, (int)(end - p - 1), p, clip);
3200
3201
1.58k
  if (strcmp(end, "?") == 0) {
3202
250
    input_osc_52_reply(ictx, *clip);
3203
250
    return (0);
3204
250
  }
3205
3206
1.33k
  len = ((strlen(end) + 3) / 4) * 3;
3207
1.33k
  if (len == 0)
3208
0
    return (0);
3209
3210
1.33k
  *out = xmalloc(len);
3211
1.33k
  if ((*outlen = b64_pton(end, *out, len)) == -1) {
3212
113
    free(*out);
3213
113
    *out = NULL;
3214
113
    return (0);
3215
113
  }
3216
3217
1.22k
  return (1);
3218
1.33k
}
3219
3220
/* Handle the OSC 52 sequence for setting the clipboard. */
3221
static void
3222
input_osc_52(struct input_ctx *ictx, const char *p)
3223
1.72k
{
3224
1.72k
  struct window_pane  *wp = ictx->wp;
3225
1.72k
  struct screen_write_ctx  ctx;
3226
1.72k
  u_char      *out;
3227
1.72k
  int      outlen;
3228
1.72k
  char       clip[sizeof "cpqs01234567"] = "";
3229
3230
1.72k
  if (!input_osc_52_parse(ictx, p, &out, &outlen, clip))
3231
504
    return;
3232
3233
1.22k
  if (wp == NULL) {
3234
    /* Popup window. */
3235
0
    if (ictx->c == NULL) {
3236
0
      free(out);
3237
0
      return;
3238
0
    }
3239
0
    tty_set_selection(&ictx->c->tty, clip, out, outlen);
3240
0
    paste_add(NULL, out, outlen);
3241
1.22k
  } else {
3242
    /* Normal window. */
3243
1.22k
    screen_write_start_pane(&ctx, wp, NULL);
3244
1.22k
    screen_write_setselection(&ctx, clip, out, outlen);
3245
1.22k
    screen_write_stop(&ctx);
3246
1.22k
    notify_pane("pane-set-clipboard", wp);
3247
1.22k
    paste_add(NULL, out, outlen);
3248
1.22k
  }
3249
1.22k
}
3250
3251
/* Handle the OSC 104 sequence for unsetting (multiple) palette entries. */
3252
static void
3253
input_osc_104(struct input_ctx *ictx, const char *p)
3254
306
{
3255
306
  char  *copy, *s;
3256
306
  long   idx;
3257
306
  int  bad = 0, redraw = 0;
3258
3259
306
  if (*p == '\0') {
3260
67
    colour_palette_clear(ictx->palette);
3261
67
    screen_write_fullredraw(&ictx->ctx);
3262
67
    return;
3263
67
  }
3264
3265
239
  copy = s = xstrdup(p);
3266
709
  while (*s != '\0') {
3267
617
    idx = strtol(s, &s, 10);
3268
617
    if (*s != '\0' && *s != ';') {
3269
79
      bad = 1;
3270
79
      break;
3271
79
    }
3272
538
    if (idx < 0 || idx >= 256) {
3273
68
      bad = 1;
3274
68
      break;
3275
68
    }
3276
470
    if (colour_palette_set(ictx->palette, idx, -1))
3277
0
      redraw = 1;
3278
470
    if (*s == ';')
3279
391
      s++;
3280
470
  }
3281
239
  if (bad)
3282
147
    log_debug("bad OSC 104: %s", p);
3283
239
  if (redraw)
3284
0
    screen_write_fullredraw(&ictx->ctx);
3285
239
  free(copy);
3286
239
}
3287
3288
/* Send a clipboard reply. */
3289
void
3290
input_reply_clipboard(struct bufferevent *bev, const char *buf, size_t len,
3291
    const char *end, char clip)
3292
246
{
3293
246
  char  *out = NULL;
3294
246
  int  outlen = 0;
3295
3296
246
  if (buf != NULL && len != 0) {
3297
246
    if (len >= ((size_t)INT_MAX * 3 / 4) - 1)
3298
0
      return;
3299
246
    outlen = 4 * ((len + 2) / 3) + 1;
3300
246
    out = xmalloc(outlen);
3301
246
    if ((outlen = b64_ntop(buf, len, out, outlen)) == -1) {
3302
0
      free(out);
3303
0
      return;
3304
0
    }
3305
246
  }
3306
3307
246
  bufferevent_write(bev, "\033]52;", 5);
3308
246
  if (clip != 0)
3309
73
    bufferevent_write(bev, &clip, 1);
3310
246
  bufferevent_write(bev, ";", 1);
3311
246
  if (outlen != 0)
3312
246
    bufferevent_write(bev, out, outlen);
3313
246
  bufferevent_write(bev, end, strlen(end));
3314
246
  free(out);
3315
246
}
3316
3317
/* Set input buffer size. */
3318
void
3319
input_set_buffer_size(size_t buffer_size)
3320
0
{
3321
0
  log_debug("%s: %lu -> %lu", __func__, input_buffer_size, buffer_size);
3322
0
  input_buffer_size = buffer_size;
3323
0
}
3324
3325
/* Request timer. Remove any requests that are too old. */
3326
static void
3327
input_request_timer_callback(__unused int fd, __unused short events, void *arg)
3328
0
{
3329
0
  struct input_ctx  *ictx = arg;
3330
0
  struct input_request  *ir, *ir1;
3331
0
  uint64_t     t = get_timer();
3332
3333
0
  TAILQ_FOREACH_SAFE(ir, &ictx->requests, entry, ir1) {
3334
0
    if (ir->t >= t - INPUT_REQUEST_TIMEOUT)
3335
0
      continue;
3336
0
    if (ir->type == INPUT_REQUEST_QUEUE)
3337
0
      input_send_reply(ir->ictx, ir->data);
3338
0
    input_free_request(ir);
3339
0
  }
3340
0
  if (ictx->request_count != 0)
3341
0
    input_start_request_timer(ictx);
3342
0
}
3343
3344
/* Start the request timer. */
3345
static void
3346
input_start_request_timer(struct input_ctx *ictx)
3347
0
{
3348
0
  struct timeval  tv = { .tv_sec = 0, .tv_usec = 100000 };
3349
3350
0
  event_del(&ictx->request_timer);
3351
0
  event_add(&ictx->request_timer, &tv);
3352
0
}
3353
3354
/* Create a request. */
3355
static struct input_request *
3356
input_make_request(struct input_ctx *ictx, enum input_request_type type)
3357
0
{
3358
0
  struct input_request  *ir;
3359
3360
0
  ir = xcalloc (1, sizeof *ir);
3361
0
  ir->type = type;
3362
0
  ir->ictx = ictx;
3363
0
  ir->t = get_timer();
3364
3365
0
  if (++ictx->request_count == 1)
3366
0
    input_start_request_timer(ictx);
3367
0
  TAILQ_INSERT_TAIL(&ictx->requests, ir, entry);
3368
3369
0
  return (ir);
3370
0
}
3371
3372
/* Free a request. */
3373
static void
3374
input_free_request(struct input_request *ir)
3375
0
{
3376
0
  struct input_ctx  *ictx = ir->ictx;
3377
3378
0
  if (ir->c != NULL)
3379
0
    TAILQ_REMOVE(&ir->c->input_requests, ir, centry);
3380
3381
0
  ictx->request_count--;
3382
0
  TAILQ_REMOVE(&ictx->requests, ir, entry);
3383
3384
0
  free(ir->data);
3385
0
  free(ir);
3386
0
}
3387
3388
/* Add a request. */
3389
static int
3390
input_add_request(struct input_ctx *ictx, enum input_request_type type, int idx)
3391
200
{
3392
200
  struct window_pane  *wp = ictx->wp;
3393
200
  struct window   *w;
3394
200
  struct client   *c = NULL, *loop;
3395
200
  struct input_request  *ir;
3396
200
  char       s[64];
3397
3398
200
  if (wp == NULL)
3399
0
    return (-1);
3400
200
  w = wp->window;
3401
3402
200
  TAILQ_FOREACH(loop, &clients, entry) {
3403
0
    if (loop->flags & CLIENT_UNATTACHEDFLAGS)
3404
0
      continue;
3405
0
    if (loop->session == NULL || !session_has(loop->session, w))
3406
0
      continue;
3407
0
    if (~loop->tty.flags & TTY_STARTED)
3408
0
      continue;
3409
0
    if (c == NULL)
3410
0
      c = loop;
3411
0
    else if (timercmp(&loop->activity_time, &c->activity_time, >))
3412
0
      c = loop;
3413
0
  }
3414
200
  if (c == NULL)
3415
200
    return (-1);
3416
3417
0
  ir = input_make_request(ictx, type);
3418
0
  ir->c = c;
3419
0
  ir->idx = idx;
3420
0
  ir->end = ictx->input_end;
3421
0
  TAILQ_INSERT_TAIL(&c->input_requests, ir, centry);
3422
3423
0
  switch (type) {
3424
0
  case INPUT_REQUEST_PALETTE:
3425
0
    xsnprintf(s, sizeof s, "\033]4;%d;?\033\\", idx);
3426
0
    tty_puts(&c->tty, s);
3427
0
    break;
3428
0
  case INPUT_REQUEST_CLIPBOARD:
3429
0
    tty_putcode_ss(&c->tty, TTYC_MS, "", "?");
3430
0
    break;
3431
0
  case INPUT_REQUEST_QUEUE:
3432
0
    break;
3433
0
  }
3434
3435
0
  return (0);
3436
0
}
3437
3438
/* Handle a palette reply. */
3439
static void
3440
input_request_palette_reply(struct input_request *ir, void *data)
3441
0
{
3442
0
  struct input_request_palette_data *pd = data;
3443
3444
0
  input_osc_colour_reply(ir->ictx, 0, 4, pd->idx, pd->c, ir->end);
3445
0
}
3446
3447
/* Handle a clipboard reply. */
3448
static void
3449
input_request_clipboard_reply(struct input_request *ir, void *data)
3450
0
{
3451
0
  struct input_ctx      *ictx = ir->ictx;
3452
0
  struct bufferevent      *ev = ictx->event;
3453
0
  struct input_request_clipboard_data *cd = data;
3454
0
  int          state;
3455
0
  char          *copy;
3456
3457
0
  state = options_get_number(global_options, "get-clipboard");
3458
0
  if (state == 0 || state == 1)
3459
0
    return;
3460
0
  if (state == 3) {
3461
0
    copy = xmalloc(cd->len);
3462
0
    memcpy(copy, cd->buf, cd->len);
3463
0
    paste_add(NULL, copy, cd->len);
3464
0
  }
3465
3466
0
  if (ir->idx == INPUT_END_BEL)
3467
0
    input_reply_clipboard(ev, cd->buf, cd->len, "\007", cd->clip);
3468
0
  else
3469
0
    input_reply_clipboard(ev, cd->buf, cd->len, "\033\\", cd->clip);
3470
0
}
3471
3472
/* Handle a reply to a request. */
3473
void
3474
input_request_reply(struct client *c, enum input_request_type type, void *data)
3475
0
{
3476
0
  struct input_request      *ir, *ir1, *found = NULL;
3477
0
  struct input_request_palette_data *pd = data;
3478
0
  int          complete = 0;
3479
3480
0
  TAILQ_FOREACH_SAFE(ir, &c->input_requests, centry, ir1) {
3481
0
    if (ir->type != type) {
3482
0
      input_free_request(ir);
3483
0
      continue;
3484
0
    }
3485
0
    if (type == INPUT_REQUEST_PALETTE) {
3486
0
      if (pd->idx != ir->idx) {
3487
0
        input_free_request(ir);
3488
0
        continue;
3489
0
      }
3490
0
      found = ir;
3491
0
      break;
3492
0
    }
3493
0
    if (type == INPUT_REQUEST_CLIPBOARD) {
3494
0
      found = ir;
3495
0
      break;
3496
0
    }
3497
0
  }
3498
0
  if (found == NULL)
3499
0
    return;
3500
3501
0
  TAILQ_FOREACH_SAFE(ir, &found->ictx->requests, entry, ir1) {
3502
0
    if (complete && ir->type != INPUT_REQUEST_QUEUE)
3503
0
      break;
3504
0
    if (ir->type == INPUT_REQUEST_QUEUE)
3505
0
      input_send_reply(ir->ictx, ir->data);
3506
0
    else if (ir == found) {
3507
0
      if (ir->type == INPUT_REQUEST_PALETTE)
3508
0
        input_request_palette_reply(ir, data);
3509
0
      else if (ir->type == INPUT_REQUEST_CLIPBOARD)
3510
0
        input_request_clipboard_reply(ir, data);
3511
0
      complete = 1;
3512
0
    }
3513
0
    input_free_request(ir);
3514
0
  }
3515
0
}
3516
3517
/* Cancel pending requests for client. */
3518
void
3519
input_cancel_requests(struct client *c)
3520
0
{
3521
0
  struct input_request  *ir, *ir1;
3522
3523
0
  TAILQ_FOREACH_SAFE(ir, &c->input_requests, centry, ir1)
3524
0
    input_free_request(ir);
3525
0
}
3526
3527
/* Report current theme. */
3528
static void
3529
input_report_current_theme(struct input_ctx *ictx)
3530
66
{
3531
66
  struct window_pane  *wp = ictx->wp;
3532
3533
66
  if (wp != NULL) {
3534
66
    wp->last_theme = window_pane_get_theme(wp);
3535
66
    wp->flags &= ~PANE_THEMECHANGED;
3536
3537
66
    switch (wp->last_theme) {
3538
0
    case THEME_DARK:
3539
0
      log_debug("%s: %%%u dark theme", __func__, wp->id);
3540
0
      input_reply(ictx, 0, "\033[?997;1n");
3541
0
      break;
3542
0
    case THEME_LIGHT:
3543
0
      log_debug("%s: %%%u light theme", __func__, wp->id);
3544
0
      input_reply(ictx, 0, "\033[?997;2n");
3545
0
      break;
3546
66
    case THEME_UNKNOWN:
3547
66
      log_debug("%s: %%%u unknown theme", __func__, wp->id);
3548
66
      break;
3549
66
    }
3550
66
  }
3551
66
}