1 /* -*- c-basic-offset:2; tab-width:2; indent-tabs-mode:nil -*- */
2
3 #include "vt_parser.h"
4
5 #include <stdio.h> /* sprintf */
6 #include <string.h> /* memmove */
7 #include <stdlib.h> /* atoi */
8 #include <fcntl.h> /* open */
9 #include <unistd.h> /* write/getcwd */
10 #include <sys/time.h> /* gettimeofday */
11 #include <time.h> /* clock */
12 #include <ctype.h> /* iscntrl */
13 #ifdef DEBUG
14 #include <stdarg.h> /* va_list */
15 #endif
16
17 #if defined(USE_LIBSSH2) && !defined(USE_WIN32API)
18 /*
19 * <wchar.h> has already been included without _XOPEN_SOURCE,
20 * so #define _XOPEN_SOURCE here doesn't work.
21 */
22 #if 0
23 #define _XOPEN_SOURCE
24 #include <wchar.h> /* wcwidth */
25 #else
26 int wcwidth(wchar_t c);
27 #endif
28 #endif
29
30 #include <pobl/bl_debug.h>
31 #include <pobl/bl_mem.h> /* malloc/free */
32 #include <pobl/bl_util.h> /* DIGIT_STR_LEN */
33 #include <pobl/bl_conf_io.h>/* bl_get_user_rc_path */
34 #include <pobl/bl_str.h> /* strdup */
35 #include <pobl/bl_args.h>
36 #include <pobl/bl_unistd.h> /* bl_usleep */
37 #include <pobl/bl_locale.h> /* bl_get_locale */
38 #include <mef/ef_ucs4_map.h> /* ef_map_to_ucs4 */
39 #include <mef/ef_ucs_property.h>
40 #include <mef/ef_locale_ucs4_map.h>
41 #include <mef/ef_ko_kr_map.h>
42
43 #include "vt_iscii.h"
44 #include "vt_str_parser.h"
45 #include "vt_shape.h" /* vt_is_arabic_combining */
46 #include "vt_transfer.h"
47
48 #if defined(__CYGWIN__) || defined(__MSYS__)
49 #include "cygfile.h"
50 #endif
51
52 /*
53 * kterm BUF_SIZE in ptyx.h is 4096.
54 */
55 #define PTY_RD_BUFFER_SIZE 3072
56
57 #define CTL_BEL 0x07
58 #define CTL_BS 0x08
59 #define CTL_TAB 0x09
60 #define CTL_LF 0x0a
61 #define CTL_VT 0x0b
62 #define CTL_FF 0x0c
63 #define CTL_CR 0x0d
64 #define CTL_SO 0x0e
65 #define CTL_SI 0x0f
66 #define CTL_ESC 0x1b
67
68 #define CURRENT_STR_P(vt_parser) \
69 ((vt_parser)->r_buf.chars + (vt_parser)->r_buf.filled_len - (vt_parser)->r_buf.left)
70
71 #define HAS_XTERM_LISTENER(vt_parser, method) \
72 ((vt_parser)->xterm_listener && ((vt_parser)->xterm_listener->method))
73
74 #define HAS_CONFIG_LISTENER(vt_parser, method) \
75 ((vt_parser)->config_listener && ((vt_parser)->config_listener->method))
76
77 #if 1
78 #define MAX_PS_DIGIT 0xffff
79 #endif
80
81 #if 0
82 #define EDIT_DEBUG
83 #endif
84
85 #if 0
86 #define EDIT_ROUGH_DEBUG
87 #endif
88
89 #if 0
90 #define INPUT_DEBUG
91 #endif
92
93 #if 0
94 #define ESCSEQ_DEBUG
95 #endif
96
97 #if 0
98 #define OUTPUT_DEBUG
99 #endif
100
101 #if 0
102 #define DUMP_HEX
103 #endif
104
105 #if 0
106 #define SUPPORT_VTE_CJK_WIDTH
107 #endif
108
109 #ifndef NO_IMAGE
110 #define SUPPORT_ITERM2_OSC1337
111 #endif
112
113 /* mode must be less than 64 */
114 #define MOD32(mode) ((mode) >= 32 ? (mode) - 32 : (mode))
115 #define DIV32(mode) ((mode) >= 32) /* 1 or 0 */
116 #define SHIFT_FLAG_0(mode) ((mode) >= 32 ? 0 : (1 << (mode)))
117 #define SHIFT_FLAG_1(mode) ((mode) >= 32 ? (1 << ((mode) - 32)) : 0)
118
119 /*
120 * The default of DECMODE_1010 is 'set' (scroll to bottom on tty output) on xterm,
121 * but is 'reset' on mlterm ("exit_backscroll_by_pty" option).
122 */
123 #define INITIAL_VTMODE_FLAGS_0 \
124 SHIFT_FLAG_0(DECMODE_2) | /* is_vt52_mode == 0 */ \
125 SHIFT_FLAG_0(DECMODE_7) | /* auto_wrap == 1 (compatible with xterm, not with VT220) */ \
126 SHIFT_FLAG_0(DECMODE_25) | /* is_visible_cursor == 1 */ \
127 SHIFT_FLAG_0(DECMODE_1034) | /* mod_meta_mode = 8bit (compatible with xterm) */ \
128 SHIFT_FLAG_0(VTMODE_12); /* local echo is false */
129 #define INITIAL_VTMODE_FLAGS_1 \
130 SHIFT_FLAG_1(DECMODE_2) | /* is_vt52_mode == 0 */ \
131 SHIFT_FLAG_1(DECMODE_7) | /* auto_wrap == 1 (compatible with xterm, not with VT220) */ \
132 SHIFT_FLAG_1(DECMODE_25) | /* is_visible_cursor == 1 */ \
133 SHIFT_FLAG_1(DECMODE_1034) | /* mod_meta_mode = 8bit (compatible with xterm) */ \
134 SHIFT_FLAG_1(VTMODE_12); /* local echo is false */
135
136 #define SHIFT_FLAG(mode) (1 << MOD32(mode))
137 #define GET_VTMODE_FLAG(vt_parser, mode) \
138 ((vt_parser)->vtmode_flags[DIV32(mode)] & SHIFT_FLAG(mode))
139 /* returns 1 or 0 */
140 #define GET_VTMODE_FLAG2(vt_parser, mode) \
141 (((vt_parser)->vtmode_flags[DIV32(mode)] >> MOD32(mode)) & 1)
142 #define GET_SAVED_VTMODE_FLAG(vt_parser, mode) \
143 ((vt_parser)->saved_vtmode_flags[DIV32(mode)] & SHIFT_FLAG(mode))
144 /* returns 1 or 0 */
145 #define GET_SAVED_VTMODE_FLAG2(vt_parser, mode) \
146 (((vt_parser)->saved_vtmode_flags[DIV32(mode)] >> MOD32(mode)) & 1)
147
148 #define IS_APP_CURSOR_KEYS(vt_parser) GET_VTMODE_FLAG(vt_parser, DECMODE_1)
149 #define ALLOW_DECCOLM(vt_parser) GET_VTMODE_FLAG(vt_parser, DECMODE_40)
150 #define KEEP_SCREEN_ON_DECCOLM(vt_parser) GET_VTMODE_FLAG(vt_parser, DECMODE_95)
151 #define BOLD_AFFECTS_BG(vt_parser) GET_VTMODE_FLAG(vt_parser, DECMODE_116)
152 #define IS_APP_ESCAPE(vt_parser) GET_VTMODE_FLAG(vt_parser, DECMODE_7727)
153 #define CURSOR_TO_RIGHT_OF_SIXEL(vt_parser) GET_VTMODE_FLAG(vt_parser, DECMODE_8452)
154 #define SEND_RECV_MODE(vt_parser) GET_VTMODE_FLAG(vt_parser, VTMODE_12)
155 #define AUTO_CR(vt_parser) GET_VTMODE_FLAG(vt_parser, VTMODE_20)
156
157 #define VTMODE(mode) ((mode) + 10000)
158
159 #define destroy_drcs(drcs) \
160 vt_drcs_destroy(drcs); \
161 (drcs) = NULL;
162
163 /*
164 * If VTMODE_NUM >= 64, enlarge the size of vt_parser_t::vtmode_flags.
165 * See get_initial_vtmode_flags() to check initial values of these modes.
166 */
167 typedef enum {
168 /* DECSET/DECRST */
169 /* vtmode_flags[0] */
170 DECMODE_1 = 0,
171 DECMODE_2,
172 DECMODE_3,
173 DECMODE_5,
174 DECMODE_6,
175 DECMODE_7,
176 DECMODE_25,
177 DECMODE_40,
178 DECMODE_47,
179 DECMODE_66,
180 DECMODE_67,
181 DECMODE_69,
182 DECMODE_80,
183 DECMODE_95,
184 DECMODE_116,
185 DECMODE_117,
186 DECMODE_1000,
187 DECMODE_1002, /* Don't add an entry between 1000 and 1002 (see set_vtmode() idx - DECMODE_1000) */
188 DECMODE_1003,
189 DECMODE_1004,
190 DECMODE_1005,
191 DECMODE_1006,
192 DECMODE_1015, /* Don't add an entry between 1005 and 1015 (see set_vtmode() idx - DECMODE_1005) */
193 DECMODE_1010,
194 DECMODE_1034,
195 DECMODE_1036,
196 DECMODE_1042,
197 DECMODE_1047,
198 DECMODE_1048,
199 DECMODE_1049,
200 DECMODE_2004,
201 DECMODE_7727,
202
203 /* vtmode_flags[1] */
204 DECMODE_8428,
205 DECMODE_8452,
206 DECMODE_8800,
207
208 /* SM/RM */
209 VTMODE_2,
210 VTMODE_4,
211 VTMODE_12,
212 VTMODE_20,
213 VTMODE_33,
214 VTMODE_34,
215
216 VTMODE_NUM,
217 } vtmode_t;
218
219 typedef struct area {
220 u_int32_t min;
221 u_int32_t max;
222
223 } area_t;
224
225 /* --- static variables --- */
226
227 static u_int16_t vtmodes[] = {
228 /* DECSET/DECRST */
229 1, 2, 3, 5, 6, 7, 25, 40, 47, 66, 67, 69, 80, 95, 116, 117,
230 1000, 1002, /* Don't add an entry between 1000 and 1002 (see set_vtmode()) */
231 1003, 1004, 1005, 1006, 1015, /* Don't add an entry between 1005 and 1015 (see set_vtmode()) */
232 1010, 1034, 1036,
233 1042, 1047, 1048, 1049, 2004, 7727, 8428, 8452, 8800,
234
235 /* SM/RM */
236 VTMODE(2), VTMODE(4), VTMODE(12), VTMODE(20), VTMODE(33), VTMODE(34),
237 };
238
239 static int use_alt_buffer = 1;
240
241 static area_t *unicode_noconv_areas;
242 static u_int num_unicode_noconv_areas;
243
244 static area_t *full_width_areas;
245 static u_int num_full_width_areas;
246
247 static area_t *half_width_areas;
248 static u_int num_half_width_areas;
249
250 static char *auto_detect_encodings;
251 static struct {
252 vt_char_encoding_t encoding;
253 ef_parser_t *parser;
254
255 } * auto_detect;
256 static u_int num_auto_detect_encodings;
257
258 static int use_ttyrec_format;
259
260 static clock_t timeout_read_pty = CLOCKS_PER_SEC / 100; /* 0.01 sec */
261
262 static char *primary_da;
263 static char *secondary_da;
264
265 static int is_broadcasting;
266
267 static int old_drcs_sixel; /* Compatible behavior with RLogin 2.23.0 or before */
268
269 static u_int local_echo_wait_msec = 250;
270
271 #ifdef USE_LIBSSH2
272 static int use_scp_full;
273 #endif
274
275 static u_int8_t alt_color_idxs[] = { 0, 1, 2, 4, 8, 3, 5, 9, 6, 10, 12, 7, 11, 13, 14, 15, } ;
276
277 static char *send_file;
278 static char *recv_dir;
279
280 /* --- static functions --- */
281
282 #ifdef DEBUG
283 #if 0
284 #define debug_print_unknown bl_debug_printf
285 #else
debug_print_unknown(const char * format,...)286 static void debug_print_unknown(const char *format, ...) {
287 va_list arg_list;
288
289 va_start(arg_list, format);
290
291 fprintf(stderr, BL_DEBUG_TAG " received unknown sequence ");
292 vfprintf(stderr, format, arg_list);
293 }
294 #endif
295 #endif
296
297 /* XXX This function should be moved to pobl */
str_replace(char * str,int c1,int c2)298 static void str_replace(char *str, int c1, int c2) {
299 while (*str) {
300 if (*str == c1) {
301 *str = c2;
302 }
303
304 str++;
305 }
306 }
307
set_area_to_table(area_t * area_table,u_int * num,char * areas)308 static area_t *set_area_to_table(area_t *area_table, u_int *num, char *areas) {
309 char *area;
310
311 #ifdef __DEBUG
312 if (area_table == unicode_noconv_areas) {
313 bl_debug_printf("Unicode noconv area:");
314 } else if (area_table == full_width_areas) {
315 bl_debug_printf("Unicode full width area:");
316 } else {
317 bl_debug_printf("Unicode half width area:");
318 }
319 bl_msg_printf(" parsing %s\n", areas);
320 #endif
321
322 if (areas == NULL || *areas == '\0') {
323 free(area_table);
324 *num = 0;
325
326 return NULL;
327 } else {
328 void *p;
329
330 if (!(p = realloc(area_table, sizeof(*area_table) * (bl_count_char_in_str(areas, ',') + 2)))) {
331 return area_table;
332 }
333
334 area_table = p;
335 }
336
337 *num = 0;
338
339 while ((area = bl_str_sep(&areas, ","))) {
340 u_int min;
341 u_int max;
342
343 if (vt_parse_unicode_area(area, &min, &max)) {
344 u_int count = 0;
345
346 while (1) {
347 if (count == *num) {
348 area_table[*num].min = min;
349 area_table[(*num)++].max = max;
350 break;
351 }
352
353 if (area_table[count].min <= min) {
354 if (area_table[count].max + 1 >= min) {
355 if (area_table[count].max < max) {
356 area_table[count].max = max;
357 }
358 break;
359 }
360 } else {
361 if (area_table[count].min <= max + 1) {
362 if (area_table[count].min > min) {
363 area_table[count].min = min;
364 }
365 if (area_table[count].max < max) {
366 area_table[count].max = max;
367 }
368 } else {
369 memmove(area_table + count + 1, area_table + count,
370 (*num - count) * sizeof(*area_table));
371 area_table[count].max = max;
372 area_table[count].min = min;
373 (*num)++;
374 }
375 break;
376 }
377
378 count++;
379 }
380 }
381 }
382
383 #ifdef __DEBUG
384 {
385 u_int count;
386
387 for (count = 0; count < *num; count++) {
388 bl_debug_printf("AREA %x-%x\n", area_table[count].min, area_table[count].max);
389 }
390 }
391 #endif
392
393 return area_table;
394 }
395
response_area_table(vt_pty_t * pty,u_char * key,area_t * area_table,u_int num,int to_menu)396 static void response_area_table(vt_pty_t *pty, u_char *key, area_t *area_table, u_int num,
397 int to_menu) {
398 u_char *value;
399
400 /* 20: U+FFFFFFFF-FFFFFFFF, */
401 if (num > 0 && (value = alloca(20 * num))) {
402 u_int count;
403 u_char *p;
404
405 p = value;
406 count = 0;
407 while (1) {
408 sprintf(p, area_table[count].min == area_table[count].max ? "U+%x" : "U+%x-%x",
409 area_table[count].min, area_table[count].max);
410 p += strlen(p);
411 if (++count < num) {
412 *(p++) = ',';
413 } else {
414 break;
415 }
416 }
417 } else {
418 value = "";
419 }
420
421 vt_response_config(pty, key, value, to_menu);
422 }
423
hit_area(area_t * areas,u_int num,u_int code)424 static inline int hit_area(area_t *areas, u_int num, u_int code) {
425 if (num > 0 && areas[0].min <= code && code <= areas[num - 1].max) {
426 u_int count;
427
428 if (num == 1) {
429 return 1;
430 }
431 count = 0;
432 do {
433 if (areas[count].min <= code && code <= areas[count].max) {
434 return 1;
435 }
436 } while (++count < num);
437 }
438
439 return 0;
440 }
441
is_noconv_unicode(u_char * ch)442 static inline int is_noconv_unicode(u_char *ch) {
443 if (unicode_noconv_areas || ch[2] == 0x20) {
444 u_int32_t code = ef_bytes_to_int(ch, 4);
445
446 if (hit_area(unicode_noconv_areas, num_unicode_noconv_areas, code)) {
447 return 1;
448 }
449
450 /*
451 * Don't convert these characters in order not to show them.
452 * see vt_char_cols().
453 */
454 if ((0x200c <= code && code <= 0x200f) || (0x202a <= code && code <= 0x202e)) {
455 return 1;
456 }
457 }
458
459 return 0;
460 }
461
modify_ucs_property(u_int32_t code,int col_size_of_width_a,ef_property_t prop)462 static inline ef_property_t modify_ucs_property(u_int32_t code, int col_size_of_width_a,
463 ef_property_t prop) {
464 if (prop & EF_AWIDTH) {
465 #ifdef SUPPORT_VTE_CJK_WIDTH
466 char *env;
467 #endif
468
469 if (col_size_of_width_a == 2) {
470 prop |= EF_FULLWIDTH;
471 }
472 #ifdef SUPPORT_VTE_CJK_WIDTH
473 else if ((env = getenv("VTE_CJK_WIDTH")) &&
474 (strcmp(env, "wide") == 0 || strcmp(env, "1") == 0)) {
475 prop |= EF_FULLWIDTH;
476 }
477 #endif
478 }
479
480 if (prop & EF_FULLWIDTH) {
481 if (half_width_areas && hit_area(half_width_areas, num_half_width_areas, code)) {
482 return prop & ~EF_FULLWIDTH;
483 }
484 } else {
485 if (full_width_areas && hit_area(full_width_areas, num_full_width_areas, code)) {
486 return prop | EF_FULLWIDTH;
487 }
488 }
489
490 return prop;
491 }
492
start_vt100_cmd(vt_parser_t * vt_parser,int trigger_xterm_event)493 static void start_vt100_cmd(vt_parser_t *vt_parser,
494 int trigger_xterm_event /* dispatch to x_screen or not. */
495 ) {
496 vt_set_use_multi_col_char(vt_parser->use_multi_col_char);
497
498 if (trigger_xterm_event && HAS_XTERM_LISTENER(vt_parser, start)) {
499 /*
500 * XXX Adhoc implementation.
501 * Converting visual -> logical in xterm_listener->start.
502 */
503 (*vt_parser->xterm_listener->start)(vt_parser->xterm_listener->self);
504 } else {
505 vt_screen_logical(vt_parser->screen);
506 }
507 }
508
stop_vt100_cmd(vt_parser_t * vt_parser,int trigger_xterm_event)509 static void stop_vt100_cmd(vt_parser_t *vt_parser,
510 int trigger_xterm_event /* dispatch to x_screen or not. */
511 ) {
512 vt_screen_render(vt_parser->screen);
513 vt_screen_visual(vt_parser->screen);
514
515 if (trigger_xterm_event && HAS_XTERM_LISTENER(vt_parser, stop)) {
516 (*vt_parser->xterm_listener->stop)(vt_parser->xterm_listener->self);
517 }
518 }
519
interrupt_vt100_cmd(vt_parser_t * vt_parser)520 static void interrupt_vt100_cmd(vt_parser_t *vt_parser) {
521 if (HAS_XTERM_LISTENER(vt_parser, interrupt)) {
522 vt_screen_render(vt_parser->screen);
523 vt_screen_visual(vt_parser->screen);
524
525 (*vt_parser->xterm_listener->interrupt)(vt_parser->xterm_listener->self);
526
527 vt_screen_logical(vt_parser->screen);
528 }
529 }
530
change_read_buffer_size(vt_read_buffer_t * r_buf,size_t len)531 static int change_read_buffer_size(vt_read_buffer_t *r_buf, size_t len) {
532 void *p;
533
534 if (!(p = realloc(r_buf->chars, len))) {
535 return 0;
536 }
537
538 r_buf->chars = p;
539 r_buf->len = len;
540
541 /*
542 * Not check if r_buf->left and r_buf->filled_len is larger than r_buf->len.
543 * It should be checked before calling this function.
544 */
545
546 return 1;
547 }
548
get_now_suffix(char * now)549 static char* get_now_suffix(char *now /* 16 bytes */) {
550 time_t t;
551 struct tm *tm;
552
553 time(&t);
554 tm = localtime(&t);
555
556 sprintf(now, "-%04d%02d%02d%02d%02d%02d", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
557 tm->tm_hour, tm->tm_min, tm->tm_sec);
558
559 return now;
560 }
561
get_home_file_path(const char * prefix,const char * name,const char * suffix)562 static char *get_home_file_path(const char *prefix, const char *name, const char *suffix) {
563 char *file_name;
564
565 if (!(file_name = alloca(7 + strlen(prefix) + 1 + strlen(name) + 1 + strlen(suffix) + 1))) {
566 return NULL;
567 }
568
569 sprintf(file_name, "mlterm/%s%s.%s", prefix, name, suffix);
570 str_replace(file_name + 7, '/', '_');
571
572 return bl_get_user_rc_path(file_name);
573 }
574
575 /*
576 * 0: Error
577 * 1: No error
578 * >=2: Probable
579 */
parse_string(ef_parser_t * cc_parser,u_char * str,size_t len)580 static int parse_string(ef_parser_t *cc_parser, u_char *str, size_t len) {
581 ef_char_t ch;
582 int ret;
583 u_int nfull;
584 u_int nkana;
585
586 ret = 1;
587 nfull = 0;
588 nkana = 0;
589 (*cc_parser->init)(cc_parser);
590 (*cc_parser->set_str)(cc_parser, str, len);
591
592 while (1) {
593 if (!(*cc_parser->next_char)(cc_parser, &ch)) {
594 if (cc_parser->is_eos) {
595 if (nkana * 8 > nfull) {
596 /* kana is over 12.5%. */
597 ret = 2;
598 }
599
600 return ret;
601 } else {
602 if (((str[len - cc_parser->left]) & 0x7f) <= 0x1f) {
603 /* skip C0 or C1 */
604 ef_parser_increment(cc_parser);
605 } else {
606 return 0;
607 }
608 }
609 } else if (ch.size > 1) {
610 if (ch.cs == ISO10646_UCS4_1) {
611 if (ret == 1 && (ch.property & EF_FULLWIDTH)) {
612 ret = 2;
613 }
614 } else {
615 if (IS_CS94MB(ch.cs)) {
616 if (ch.ch[0] <= 0x20 || ch.ch[0] == 0x7f || ch.ch[1] <= 0x20 || ch.ch[1] == 0x7f) {
617 /* mef can return illegal character code. */
618 return 0;
619 } else if (ret == 1 && (ch.cs == JISX0208_1983 || ch.cs == JISC6226_1978 ||
620 ch.cs == JISX0213_2000_1) &&
621 (ch.ch[0] == 0x24 || ch.ch[0] == 0x25) && 0x21 <= ch.ch[1] &&
622 ch.ch[1] <= 0x73) {
623 /* Hiragana/Katakana */
624 nkana++;
625 }
626 }
627
628 nfull++;
629 }
630 }
631 }
632 }
633
634 /* Check num_auto_detect_encodings > 0 before calling this function. */
detect_encoding(vt_parser_t * vt_parser)635 static void detect_encoding(vt_parser_t *vt_parser) {
636 u_char *str;
637 size_t len;
638 size_t count;
639 u_int idx;
640 int cur_idx;
641 int cand_idx;
642 int threshold;
643
644 str = vt_parser->r_buf.chars;
645 len = vt_parser->r_buf.filled_len;
646
647 for (count = 0; count < len - 1; count++) {
648 if (str[count] >= 0x80 && str[count + 1] >= 0x80) {
649 goto detect;
650 }
651 }
652
653 return;
654
655 detect:
656 cur_idx = -1;
657 threshold = 0;
658 for (idx = 0; idx < num_auto_detect_encodings; idx++) {
659 if (auto_detect[idx].encoding == vt_parser->encoding) {
660 if ((threshold = parse_string(auto_detect[idx].parser, str, len)) > 1) {
661 return;
662 }
663
664 cur_idx = idx;
665 break;
666 }
667 }
668
669 cand_idx = -1;
670 for (idx = 0; idx < num_auto_detect_encodings; idx++) {
671 int ret;
672
673 if (idx != cur_idx && (ret = parse_string(auto_detect[idx].parser, str, len)) > threshold) {
674 cand_idx = idx;
675
676 if (ret > 1) {
677 break;
678 }
679 }
680 }
681
682 if (cand_idx >= 0) {
683 #ifdef DEBUG
684 bl_debug_printf(BL_DEBUG_TAG " Character encoding is changed to %s.\n",
685 vt_get_char_encoding_name(auto_detect[cand_idx].encoding));
686 #endif
687
688 vt_parser_change_encoding(vt_parser, auto_detect[cand_idx].encoding);
689 }
690 }
691
is_dcs_or_osc(u_char * str)692 inline static int is_dcs_or_osc(u_char *str /* The length should be 2 or more. */
693 ) {
694 return *str == 0x90 || memcmp(str, "\x1bP", 2) == 0 || memcmp(str, "\x1b]", 2) == 0;
695 }
696
write_ttyrec_header(int fd,size_t len,int keep_time)697 static void write_ttyrec_header(int fd, size_t len, int keep_time) {
698 u_int32_t buf[3];
699
700 #ifdef HAVE_GETTIMEOFDAY
701 if (!keep_time) {
702 struct timeval tval;
703
704 gettimeofday(&tval, NULL);
705 #ifdef WORDS_BIGENDIAN
706 buf[0] = LE32DEC(((u_char *)&tval.tv_sec));
707 buf[1] = LE32DEC(((u_char *)&tval.tv_usec));
708 buf[2] = LE32DEC(((u_char *)&len));
709 #else
710 buf[0] = tval.tv_sec;
711 buf[1] = tval.tv_usec;
712 buf[2] = len;
713 #endif
714
715 #if __DEBUG
716 bl_debug_printf("write len %d at %d\n", len, lseek(fd, 0, SEEK_CUR));
717 #endif
718
719 write(fd, buf, 12);
720 } else
721 #endif
722 {
723 lseek(fd, 8, SEEK_CUR);
724
725 #ifdef WORDS_BIGENDIAN
726 buf[0] = LE32DEC(((u_char *)&len));
727 #else
728 buf[0] = len;
729 #endif
730
731 write(fd, buf, 4);
732 }
733 }
734
receive_bytes(vt_parser_t * vt_parser)735 static int receive_bytes(vt_parser_t *vt_parser) {
736 size_t len;
737
738 if (vt_parser->r_buf.left == vt_parser->r_buf.len) {
739 /* Buffer is full => Expand buffer */
740
741 len = vt_parser->r_buf.len >= PTY_RD_BUFFER_SIZE * 5 ? PTY_RD_BUFFER_SIZE * 10
742 : PTY_RD_BUFFER_SIZE;
743
744 if (!change_read_buffer_size(&vt_parser->r_buf, vt_parser->r_buf.len + len)) {
745 return 0;
746 }
747 } else {
748 if (0 < vt_parser->r_buf.left && vt_parser->r_buf.left < vt_parser->r_buf.filled_len) {
749 memmove(vt_parser->r_buf.chars, CURRENT_STR_P(vt_parser),
750 vt_parser->r_buf.left * sizeof(u_char));
751 }
752
753 /* vt_parser->r_buf.left must be always less than vt_parser->r_buf.len
754 */
755 if ((len = vt_parser->r_buf.len - vt_parser->r_buf.left) > PTY_RD_BUFFER_SIZE &&
756 !is_dcs_or_osc(vt_parser->r_buf.chars)) {
757 len = PTY_RD_BUFFER_SIZE;
758 }
759 }
760
761 if ((vt_parser->r_buf.new_len = vt_read_pty(
762 vt_parser->pty, vt_parser->r_buf.chars + vt_parser->r_buf.left, len)) == 0) {
763 vt_parser->r_buf.filled_len = vt_parser->r_buf.left;
764
765 return 0;
766 }
767
768 if (vt_parser->logging_vt_seq) {
769 if (vt_parser->log_file == -1) {
770 char *path;
771 char buf[16];
772
773 if (!(path = get_home_file_path(vt_pty_get_slave_name(vt_parser->pty) + 5,
774 get_now_suffix(buf), "log"))) {
775 goto end;
776 }
777
778 if ((vt_parser->log_file = open(path, O_CREAT | O_WRONLY, 0600)) == -1) {
779 free(path);
780
781 goto end;
782 }
783
784 free(path);
785
786 /*
787 * O_APPEND in open() forces lseek(0,SEEK_END) in write()
788 * and disables lseek(pos,SEEK_SET) before calling write().
789 * So don't specify O_APPEND in open() and call lseek(0,SEEK_END)
790 * manually after open().
791 */
792 lseek(vt_parser->log_file, 0, SEEK_END);
793 bl_file_set_cloexec(vt_parser->log_file);
794
795 if (use_ttyrec_format) {
796 char seq[6 + DIGIT_STR_LEN(int)*2 + 1];
797
798 /* The height of "CSI 8 t" doesn't include status line. */
799 sprintf(seq, "\x1b[8;%d;%dt", vt_screen_get_logical_rows(vt_parser->screen),
800 vt_screen_get_logical_cols(vt_parser->screen));
801 write_ttyrec_header(vt_parser->log_file, strlen(seq), 0);
802 write(vt_parser->log_file, seq, strlen(seq));
803 }
804 }
805
806 if (use_ttyrec_format) {
807 if (vt_parser->r_buf.left > 0) {
808 lseek(vt_parser->log_file,
809 lseek(vt_parser->log_file, 0, SEEK_CUR) - vt_parser->r_buf.filled_len - 12,
810 SEEK_SET);
811
812 if (vt_parser->r_buf.left < vt_parser->r_buf.filled_len) {
813 write_ttyrec_header(vt_parser->log_file,
814 vt_parser->r_buf.filled_len - vt_parser->r_buf.left, 1);
815
816 lseek(vt_parser->log_file,
817 lseek(vt_parser->log_file, 0, SEEK_CUR) + vt_parser->r_buf.filled_len -
818 vt_parser->r_buf.left,
819 SEEK_SET);
820 }
821 }
822
823 write_ttyrec_header(vt_parser->log_file,
824 vt_parser->r_buf.left + vt_parser->r_buf.new_len, 0);
825
826 write(vt_parser->log_file, vt_parser->r_buf.chars,
827 vt_parser->r_buf.left + vt_parser->r_buf.new_len);
828 } else {
829 write(vt_parser->log_file, vt_parser->r_buf.chars + vt_parser->r_buf.left,
830 vt_parser->r_buf.new_len);
831 }
832
833 #ifndef USE_WIN32API
834 fsync(vt_parser->log_file);
835 #endif
836 } else {
837 if (vt_parser->log_file != -1) {
838 close(vt_parser->log_file);
839 vt_parser->log_file = -1;
840 }
841 }
842
843 end:
844 vt_parser->r_buf.filled_len = (vt_parser->r_buf.left += vt_parser->r_buf.new_len);
845
846 if (vt_parser->r_buf.filled_len <= PTY_RD_BUFFER_SIZE &&
847 vt_parser->r_buf.len > PTY_RD_BUFFER_SIZE) {
848 /* Shrink buffer */
849 change_read_buffer_size(&vt_parser->r_buf, PTY_RD_BUFFER_SIZE);
850 }
851
852 if (vt_parser->use_auto_detect && num_auto_detect_encodings > 0) {
853 detect_encoding(vt_parser);
854 }
855
856 #ifdef INPUT_DEBUG
857 {
858 size_t count;
859
860 bl_debug_printf(BL_DEBUG_TAG " pty msg (len %d) is received:", vt_parser->r_buf.left);
861
862 for (count = 0; count < vt_parser->r_buf.left; count++) {
863 #ifdef DUMP_HEX
864 if (isprint(vt_parser->r_buf.chars[count])) {
865 bl_msg_printf("%c ", vt_parser->r_buf.chars[count]);
866 } else {
867 bl_msg_printf("%.2x ", vt_parser->r_buf.chars[count]);
868 }
869 #else
870 bl_msg_printf("%c", vt_parser->r_buf.chars[count]);
871 #endif
872 }
873
874 bl_msg_printf("[END]\n");
875 }
876 #endif
877
878 return 1;
879 }
880
881 /*
882 * If buffer exists, vt_parser->w_buf.last_ch is cached.
883 * If buffer doesn't exist, vt_parser->w_buf.last_ch is cleared.
884 */
flush_buffer(vt_parser_t * vt_parser)885 static int flush_buffer(vt_parser_t *vt_parser) {
886 vt_write_buffer_t *buffer;
887
888 buffer = &vt_parser->w_buf;
889
890 if (buffer->filled_len == 0) {
891 return 0;
892 }
893
894 #ifdef OUTPUT_DEBUG
895 {
896 u_int count;
897
898 bl_msg_printf("\nflushing chars(%d)...==>", buffer->filled_len);
899 for (count = 0; count < buffer->filled_len; count++) {
900 u_int code = vt_char_code(&buffer->chars[count]);
901
902 #ifdef DUMP_HEX
903 bl_msg_printf("%x", code);
904 #else
905 bl_msg_printf("%c", code);
906 #endif
907 }
908
909 bl_msg_printf("<===\n");
910 }
911 #endif
912
913 (*buffer->output_func)(vt_parser->screen, buffer->chars, buffer->filled_len);
914
915 /* last_ch which will be used & cleared in REP sequence is cached. */
916 buffer->last_ch = &buffer->chars[buffer->filled_len - 1];
917 /* buffer is cleared. */
918 buffer->filled_len = 0;
919
920 #ifdef EDIT_DEBUG
921 vt_edit_dump(vt_parser->screen->edit);
922 #endif
923
924 return 1;
925 }
926
put_char(vt_parser_t * vt_parser,u_int32_t ch,ef_charset_t cs,ef_property_t prop)927 static void put_char(vt_parser_t *vt_parser, u_int32_t ch, ef_charset_t cs,
928 ef_property_t prop) {
929 vt_color_t fg_color;
930 vt_color_t bg_color;
931 int is_fullwidth;
932 int is_awidth;
933 int is_comb;
934 int is_bold;
935 int is_italic;
936 int line_style;
937 int is_blinking;
938 int is_protected;
939 int is_reversed;
940
941 if (vt_parser->w_buf.filled_len == PTY_WR_BUFFER_SIZE) {
942 flush_buffer(vt_parser);
943 }
944
945 /*
946 * checking width property of the char.
947 */
948
949 if (prop & EF_FULLWIDTH) {
950 is_fullwidth = 1;
951 } else {
952 is_fullwidth = 0;
953 }
954
955 if (prop & EF_AWIDTH) {
956 is_awidth = 1;
957 } else {
958 is_awidth = 0;
959 }
960
961 #ifdef __DEBUG
962 bl_debug_printf("%x %d %x => %s\n", ch, len, cs, is_fullwidth ? "Fullwidth" : "Single");
963 #endif
964
965 if ((prop & EF_COMBINING)
966 #if !defined(NO_DYNAMIC_LOAD_CTL) || defined(USE_IND)
967 || (ch == '\xe9' && IS_ISCII(cs)) /* nukta is always combined. */
968 #endif
969 ) {
970 is_comb = 1;
971 } else {
972 is_comb = 0;
973 }
974
975 fg_color = vt_parser->fg_color;
976 bg_color = vt_parser->bg_color;
977 is_italic = vt_parser->is_italic ? 1 : 0;
978 is_blinking = vt_parser->is_blinking ? 1 : 0;
979 is_protected = vt_parser->is_protected ? 1 : 0;
980 is_reversed = vt_parser->is_reversed ? 1 : 0;
981 line_style = vt_parser->line_style;
982 if (cs == ISO10646_UCS4_1 && 0x2580 <= ch && ch <= 0x259f) {
983 /* prevent these block characters from being drawn doubly. */
984 is_bold = 0;
985 } else {
986 is_bold = vt_parser->is_bold ? 1 : 0;
987 }
988
989 if (fg_color == VT_FG_COLOR) {
990 if (is_italic && (vt_parser->alt_color_mode & ALT_COLOR_ITALIC)) {
991 is_italic = 0;
992 fg_color = VT_ITALIC_COLOR;
993 }
994
995 if ((line_style & LS_CROSSED_OUT) && (vt_parser->alt_color_mode & ALT_COLOR_CROSSED_OUT)) {
996 line_style &= ~LS_CROSSED_OUT;
997 fg_color = VT_CROSSED_OUT_COLOR;
998 }
999
1000 if (is_blinking && (vt_parser->alt_color_mode & ALT_COLOR_BLINKING)) {
1001 is_blinking = 0;
1002 fg_color = VT_BLINKING_COLOR;
1003 }
1004
1005 if ((line_style & LS_UNDERLINE) && (vt_parser->alt_color_mode & ALT_COLOR_UNDERLINE)) {
1006 line_style &= ~LS_UNDERLINE;
1007 fg_color = VT_UNDERLINE_COLOR;
1008 }
1009
1010 if (is_bold && (vt_parser->alt_color_mode & ALT_COLOR_BOLD)) {
1011 is_bold = 0;
1012 fg_color = VT_BOLD_COLOR;
1013 }
1014
1015 if (is_reversed && (vt_parser->alt_color_mode & ALT_COLOR_REVERSE)) {
1016 is_reversed = 0;
1017 fg_color = VT_REVERSE_COLOR;
1018 }
1019 } else {
1020 if (is_bold) {
1021 if (IS_VTSYS_BASE_COLOR(fg_color)) {
1022 fg_color |= VT_BOLD_COLOR_MASK;
1023 }
1024 if (BOLD_AFFECTS_BG(vt_parser) && IS_VTSYS_BASE_COLOR(bg_color)) {
1025 bg_color |= VT_BOLD_COLOR_MASK;
1026 }
1027 }
1028 }
1029
1030 if (is_reversed) {
1031 vt_color_t tmp = bg_color;
1032 bg_color = fg_color;
1033 fg_color = tmp;
1034 }
1035
1036 if (vt_parser->alt_colors.flags) {
1037 int idx = is_bold | ((vt_parser->is_reversed ? 1 : 0) << 1) |
1038 ((line_style & LS_UNDERLINE) ? 4 : 0) | (is_blinking << 3);
1039
1040 if (/* idx < 16 && */ (vt_parser->alt_colors.flags & (1 << idx))) {
1041 fg_color = vt_parser->alt_colors.fg[idx];
1042 bg_color = vt_parser->alt_colors.bg[idx];
1043 }
1044 }
1045
1046 /*
1047 * 2.9.2 Alternate Text Colors in VT520-VT525ProgrammerInformation.pdf
1048 * "The foreground color of text with the invisible attribute becomes the background color."
1049 */
1050 if (vt_parser->is_invisible) {
1051 fg_color = bg_color;
1052 }
1053
1054 if (vt_parser->use_char_combining && is_comb) {
1055 if (vt_parser->w_buf.filled_len == 0) {
1056 /*
1057 * vt_line_set_modified() is done in vt_screen_combine_with_prev_char()
1058 * internally.
1059 */
1060 if (vt_screen_combine_with_prev_char(vt_parser->screen, ch, cs, is_fullwidth, is_awidth,
1061 is_comb, fg_color, bg_color, is_bold, is_italic,
1062 line_style, is_blinking, is_protected)) {
1063 return;
1064 }
1065 } else {
1066 if (vt_char_combine(&vt_parser->w_buf.chars[vt_parser->w_buf.filled_len - 1], ch, cs,
1067 is_fullwidth, is_awidth, is_comb, fg_color, bg_color, is_bold, is_italic,
1068 line_style, is_blinking, is_protected)) {
1069 return;
1070 }
1071 }
1072
1073 /*
1074 * if combining failed , char is normally appended.
1075 */
1076 }
1077
1078 #ifndef NO_IMAGE
1079 {
1080 vt_drcs_font_t *font;
1081 int pic_id;
1082 int pic_pos;
1083
1084 if (cs != US_ASCII &&
1085 (font = vt_drcs_get_font(vt_parser->drcs,
1086 cs == CS_REVISION_1(US_ASCII) ? US_ASCII : cs, 0)) &&
1087 /* XXX The width of pua is always regarded as 1. (is_fullwidth is ignored) */
1088 vt_drcs_get_picture(font, &pic_id, &pic_pos, ch)) {
1089 vt_char_copy(&vt_parser->w_buf.chars[vt_parser->w_buf.filled_len],
1090 vt_screen_get_bce_ch(vt_parser->screen));
1091 vt_char_combine_picture(&vt_parser->w_buf.chars[vt_parser->w_buf.filled_len++],
1092 pic_id, pic_pos);
1093
1094 return;
1095 }
1096 }
1097 #endif
1098
1099 vt_char_set(&vt_parser->w_buf.chars[vt_parser->w_buf.filled_len++], ch, cs, is_fullwidth,
1100 is_awidth, is_comb, fg_color, bg_color, is_bold, is_italic, line_style,
1101 is_blinking, is_protected);
1102
1103 if (cs != ISO10646_UCS4_1) {
1104 return;
1105 }
1106
1107 if (0x1f000 <= ch && ch <= 0x1f9ff && (ch <= 0x1f6ff || 0x1f900 <= ch) &&
1108 HAS_XTERM_LISTENER(vt_parser, get_emoji_data)) {
1109 /*
1110 * Emoji pictures (mostly U+1F000-1F6FF) provided by
1111 * https://github.com/github/gemoji
1112 */
1113
1114 vt_char_t *emoji1;
1115 vt_char_t *emoji2;
1116
1117 emoji1 = &vt_parser->w_buf.chars[vt_parser->w_buf.filled_len - 1];
1118 emoji2 = NULL;
1119
1120 if (0x1f1e6 <= ch && ch <= 0x1f1ff /* REGIONAL INDICATOR SYMBOL LETTER A-Z */) {
1121 vt_char_t *prev_ch;
1122
1123 if (vt_parser->w_buf.filled_len <= 1) {
1124 prev_ch = vt_screen_get_n_prev_char(vt_parser->screen, 1);
1125 } else {
1126 prev_ch = emoji1 - 1;
1127 }
1128
1129 if (prev_ch) {
1130 if (0x1f1e6 <= vt_char_code(prev_ch) && vt_char_code(prev_ch) <= 0x1f1ff) {
1131 emoji2 = emoji1;
1132 emoji1 = prev_ch;
1133 }
1134 }
1135 } else if (0x1f3fb <= ch && ch <= 0x1f3ff) /* EMOJI MODIFIER FITZPATRIC TYPE 1-6 */ {
1136 vt_char_t *prev_ch;
1137
1138 if (vt_parser->w_buf.filled_len <= 1) {
1139 prev_ch = vt_screen_get_n_prev_char(vt_parser->screen, 1);
1140 } else {
1141 prev_ch = emoji1 - 1;
1142 }
1143
1144 if (prev_ch) {
1145 emoji2 = emoji1;
1146 emoji1 = prev_ch;
1147 }
1148 }
1149
1150 if ((*vt_parser->xterm_listener->get_emoji_data)(vt_parser->xterm_listener->self, emoji1,
1151 emoji2)) {
1152 if (emoji2) {
1153 /* Base char: emoji1, Comb1: picture, Comb2: emoji2 */
1154 if (emoji2 == emoji1 + 1) {
1155 vt_char_combine(emoji1, ch, cs, is_fullwidth, is_awidth, is_comb, fg_color, bg_color,
1156 is_bold, is_italic, line_style, is_blinking, is_protected);
1157 } else {
1158 /*
1159 * vt_line_set_modified() is done in
1160 * vt_screen_combine_with_prev_char() internally.
1161 */
1162 vt_screen_combine_with_prev_char(vt_parser->screen, ch, cs, is_fullwidth, is_awidth,
1163 is_comb, fg_color, bg_color, is_bold, is_italic,
1164 line_style, is_blinking, is_protected);
1165 }
1166 vt_parser->w_buf.filled_len--;
1167 }
1168
1169 /*
1170 * Flush buffer before searching and deleting unused pictures
1171 * in x_picture.c.
1172 */
1173 flush_buffer(vt_parser);
1174 }
1175 } else if (vt_parser->use_char_combining) {
1176 /*
1177 * Arabic combining
1178 */
1179
1180 vt_char_t *prev2;
1181 vt_char_t *prev;
1182 vt_char_t *cur;
1183 int n;
1184
1185 cur = &vt_parser->w_buf.chars[vt_parser->w_buf.filled_len - 1];
1186 n = 0;
1187
1188 if (vt_parser->w_buf.filled_len >= 2) {
1189 prev = cur - 1;
1190 } else {
1191 if (!(prev = vt_screen_get_n_prev_char(vt_parser->screen, ++n))) {
1192 return;
1193 }
1194 }
1195
1196 if (vt_parser->w_buf.filled_len >= 3) {
1197 prev2 = cur - 2;
1198 } else {
1199 /* possibly NULL */
1200 prev2 = vt_screen_get_n_prev_char(vt_parser->screen, ++n);
1201 }
1202
1203 if (IS_ARABIC_CHAR(ch) && vt_is_arabic_combining(prev2, prev, cur)) {
1204 if (vt_parser->w_buf.filled_len >= 2) {
1205 if (vt_char_combine(prev, ch, cs, is_fullwidth, is_awidth, is_comb, fg_color, bg_color,
1206 is_bold, is_italic, line_style, is_blinking, is_protected)) {
1207 vt_parser->w_buf.filled_len--;
1208 }
1209 } else {
1210 /*
1211 * vt_line_set_modified() is done in
1212 * vt_screen_combine_with_prev_char() internally.
1213 */
1214 if (vt_screen_combine_with_prev_char(vt_parser->screen, ch, cs, is_fullwidth, is_awidth,
1215 is_comb, fg_color, bg_color, is_bold, is_italic,
1216 line_style, is_blinking, is_protected)) {
1217 vt_parser->w_buf.filled_len--;
1218 }
1219 }
1220 }
1221 }
1222 }
1223
push_to_saved_names(vt_saved_names_t * saved,char * name)1224 static void push_to_saved_names(vt_saved_names_t *saved, char *name) {
1225 void *p;
1226
1227 if (!(p = realloc(saved->names, (saved->num + 1) * sizeof(name)))) {
1228 return;
1229 }
1230
1231 saved->names = p;
1232 saved->names[saved->num++] = name ? strdup(name) : NULL;
1233 }
1234
pop_from_saved_names(vt_saved_names_t * saved)1235 static char *pop_from_saved_names(vt_saved_names_t *saved) {
1236 char *name;
1237
1238 name = saved->names[--saved->num];
1239
1240 if (saved->num == 0) {
1241 free(saved->names);
1242 saved->names = NULL;
1243 }
1244
1245 return name;
1246 }
1247
1248 /*
1249 * VT100_PARSER Escape Sequence Commands.
1250 */
1251
save_cursor(vt_parser_t * vt_parser)1252 static void save_cursor(vt_parser_t *vt_parser) {
1253 vt_storable_states_t *dest;
1254
1255 dest = (vt_screen_is_alternative_edit(vt_parser->screen)) ? &(vt_parser->saved_alternate)
1256 : &(vt_parser->saved_normal);
1257 dest->is_saved = 1;
1258 dest->fg_color = vt_parser->fg_color;
1259 dest->bg_color = vt_parser->bg_color;
1260 dest->is_bold = vt_parser->is_bold;
1261 dest->is_italic = vt_parser->is_italic;
1262 dest->line_style = vt_parser->line_style;
1263 dest->is_reversed = vt_parser->is_reversed;
1264 dest->is_blinking = vt_parser->is_blinking;
1265 dest->is_invisible = vt_parser->is_invisible;
1266 dest->is_protected = vt_parser->is_protected;
1267 dest->is_relative_origin = vt_screen_is_relative_origin(vt_parser->screen);
1268 dest->last_column_flag = vt_screen_get_last_column_flag(vt_parser->screen);
1269 dest->cs = vt_parser->cs;
1270
1271 vt_screen_save_cursor(vt_parser->screen);
1272 }
1273
init_encoding_parser(vt_parser_t * vt_parser)1274 static void init_encoding_parser(vt_parser_t *vt_parser) {
1275 (*vt_parser->cc_parser->init)(vt_parser->cc_parser);
1276 vt_parser->gl = US_ASCII;
1277 vt_parser->g0 = US_ASCII;
1278 vt_parser->g1 = US_ASCII;
1279 vt_parser->is_so = 0;
1280 }
1281
1282 static void set_vtmode(vt_parser_t *vt_parser, int mode, int flag);
1283 static void change_char_attr(vt_parser_t *vt_parser, int flag);
1284
restore_cursor(vt_parser_t * vt_parser)1285 static void restore_cursor(vt_parser_t *vt_parser) {
1286 vt_storable_states_t *src;
1287
1288 src = (vt_screen_is_alternative_edit(vt_parser->screen)) ? &(vt_parser->saved_alternate)
1289 : &(vt_parser->saved_normal);
1290 if (src->is_saved) {
1291 vt_parser->fg_color = src->fg_color;
1292 vt_screen_set_bce_fg_color(vt_parser->screen, src->fg_color);
1293 vt_parser->bg_color = src->bg_color;
1294 vt_screen_set_bce_bg_color(vt_parser->screen, src->bg_color);
1295 vt_parser->is_bold = src->is_bold;
1296 vt_parser->is_italic = src->is_italic;
1297 vt_parser->line_style = src->line_style;
1298 vt_parser->is_reversed = src->is_reversed;
1299 vt_parser->is_blinking = src->is_blinking;
1300 vt_parser->is_invisible = src->is_invisible;
1301 vt_parser->is_protected = src->is_protected;
1302 vt_screen_set_relative_origin(vt_parser->screen, src->is_relative_origin ? 1 : 0);
1303 /* See "Last Column Flag specifics" at https://github.com/mattiase/wraptest */
1304 vt_screen_set_last_column_flag(vt_parser->screen, src->last_column_flag ? 1 : 0);
1305 if (IS_ENCODING_BASED_ON_ISO2022(vt_parser->encoding)) {
1306 if ((src->cs == DEC_SPECIAL) && (src->cs != vt_parser->cs)) {
1307 /* force grapchics mode by sending \E(0 to current parser*/
1308 u_char DEC_SEQ[] = {CTL_ESC, '(', '0'};
1309 ef_char_t ch;
1310 ef_parser_t *parser;
1311
1312 init_encoding_parser(vt_parser);
1313 parser = vt_parser->cc_parser;
1314 (*parser->set_str)(parser, DEC_SEQ, sizeof(DEC_SEQ));
1315 (*parser->next_char)(parser, &ch);
1316 }
1317 } else {
1318 /* XXX: what to do for g0/g1? */
1319 if (src->cs == DEC_SPECIAL) {
1320 vt_parser->gl = DEC_SPECIAL;
1321 } else {
1322 vt_parser->gl = US_ASCII;
1323 }
1324 }
1325
1326 vt_screen_restore_cursor(vt_parser->screen);
1327 } else {
1328 /*
1329 * Moves the cursor to the home position (upper left of screen).
1330 * Resets origin mode (DECOM).
1331 * Turns all character attributes off (normal setting).
1332 * Maps the ASCII character set into GL, and the DEC Supplemental Graphic set into GR.
1333 * (see https://www.vt100.net/docs/vt510-rm/DECRC.html)
1334 */
1335 change_char_attr(vt_parser, 0);
1336 set_vtmode(vt_parser, 6, 0); /* goto(0, 0) internally */
1337 }
1338 }
1339
set_maximize(vt_parser_t * vt_parser,int flag)1340 static void set_maximize(vt_parser_t *vt_parser, int flag) {
1341 if (HAS_XTERM_LISTENER(vt_parser, resize)) {
1342 stop_vt100_cmd(vt_parser, 0);
1343 (*vt_parser->xterm_listener->resize)(vt_parser->xterm_listener->self, 0, 0, flag, 0);
1344 start_vt100_cmd(vt_parser, 0);
1345 }
1346 }
1347
get_cell_size(vt_parser_t * vt_parser,u_int * col_width,u_int * line_height)1348 static int get_cell_size(vt_parser_t *vt_parser, u_int *col_width, u_int *line_height) {
1349 if (HAS_XTERM_LISTENER(vt_parser, get_window_size)) {
1350 u_int width;
1351 u_int height;
1352
1353 (*vt_parser->xterm_listener->get_window_size)(vt_parser->xterm_listener->self, &width, &height);
1354
1355 /* XXX This doesn't work on vertical mode. */
1356 if ((*col_width = width / vt_screen_get_logical_cols(vt_parser->screen)) == 0 ||
1357 (*line_height = height / vt_screen_get_logical_rows(vt_parser->screen)) == 0) {
1358 return 0;
1359 }
1360
1361 return 1;
1362 } else {
1363 return 0;
1364 }
1365 }
1366
1367 /*
1368 * width|height == 0: maximize
1369 * width|height == -1: current value
1370 */
resize(vt_parser_t * vt_parser,int width,int height,int by_char)1371 static void resize(vt_parser_t *vt_parser, int width, int height, int by_char) {
1372 if (HAS_XTERM_LISTENER(vt_parser, resize)) {
1373 int flag = 0;
1374
1375 if (by_char) {
1376 if (width == 0 || height == 0) {
1377 u_int col_width;
1378 u_int line_height;
1379
1380 if (!HAS_XTERM_LISTENER(vt_parser, get_display_size) ||
1381 !get_cell_size(vt_parser, &col_width, &line_height)) {
1382 if (width == 0) {
1383 width = -1;
1384 }
1385 if (height == 0) {
1386 height = -1;
1387 }
1388 } else {
1389 u_int w;
1390 u_int h;
1391
1392 (*vt_parser->xterm_listener->get_display_size)(vt_parser->xterm_listener->self, &w, &h);
1393 if (width == 0) {
1394 width = w / col_width;
1395 }
1396 if (height == 0) {
1397 height = h / line_height;
1398
1399 goto do_resize;
1400 }
1401 }
1402 }
1403
1404 if (width == -1) {
1405 width = vt_screen_get_logical_cols(vt_parser->screen);
1406 }
1407 if (height == -1) {
1408 height = vt_screen_get_logical_rows(vt_parser->screen);
1409 }
1410
1411 /*
1412 * 'height' argument of this function should includes status line according to
1413 * the following document, but teraterm (4.95) excludes status line by CSI 8 t.
1414 * mlterm considers height of "CSI t", "OSC 5379;geometry", DECSNLS and DECSLPP
1415 * to be excluding status line.
1416 *
1417 * https://vt100.net/docs/vt510-rm/DECSNLS.html
1418 * The terminal supports three different font heights, which allows 26, 42, or 53 data
1419 * lines to be displayed on the screen or 25, 41, or 52 data lines to be displayed on
1420 * the screen, plus a status line.
1421 */
1422 if (vt_screen_has_status_line(vt_parser->screen)) {
1423 height ++;
1424 }
1425
1426 do_resize:
1427 if (vt_screen_resize(vt_parser->screen, width, height) == 2) {
1428 flag = 1;
1429 }
1430
1431 /*
1432 * xterm_listener::resize(0,0) means that screen should be
1433 * resized according to the size of pty.
1434 */
1435 width = 0;
1436 height = 0;
1437 } else {
1438 if ((width == 0 || height == 0) && HAS_XTERM_LISTENER(vt_parser, get_display_size)) {
1439 u_int w;
1440 u_int h;
1441
1442 (*vt_parser->xterm_listener->get_display_size)(vt_parser->xterm_listener->self, &w, &h);
1443 if (width == 0) {
1444 width = w;
1445 }
1446 if (height == 0) {
1447 height = h;
1448 }
1449 }
1450
1451 if (width == -1) {
1452 width = 0; /* xterm_listener->resize() doesn't resize width if width == 0. */
1453 }
1454 if (height == -1) {
1455 height = 0; /* xterm_listener->resize() doesn't resize height if height == 0. */
1456 }
1457 }
1458
1459 stop_vt100_cmd(vt_parser, 0);
1460 (*vt_parser->xterm_listener->resize)(vt_parser->xterm_listener->self, width, height, 0, flag);
1461 start_vt100_cmd(vt_parser, 0);
1462 }
1463 }
1464
reverse_video(vt_parser_t * vt_parser,int flag)1465 static void reverse_video(vt_parser_t *vt_parser, int flag) {
1466 if (HAS_XTERM_LISTENER(vt_parser, reverse_video)) {
1467 stop_vt100_cmd(vt_parser, 0);
1468 (*vt_parser->xterm_listener->reverse_video)(vt_parser->xterm_listener->self, flag);
1469 start_vt100_cmd(vt_parser, 0);
1470 }
1471 }
1472
set_mouse_report(vt_parser_t * vt_parser,vt_mouse_report_mode_t mode)1473 static void set_mouse_report(vt_parser_t *vt_parser, vt_mouse_report_mode_t mode) {
1474 if (HAS_XTERM_LISTENER(vt_parser, set_mouse_report)) {
1475 /*
1476 * If xterm_set_mouse_report() calls x_stop_selecting() etc,
1477 * remove #if 0 - #end.
1478 *
1479 * If #if 0 - #end is removed, ctl_render() is at least twice
1480 * in one sequence packet from w3m because w3m sends CSI?1000h every time.
1481 */
1482 #if 0
1483 stop_vt100_cmd(vt_parser, 0);
1484 #endif
1485
1486 vt_parser->mouse_mode = mode;
1487 (*vt_parser->xterm_listener->set_mouse_report)(vt_parser->xterm_listener->self);
1488
1489 #if 0
1490 start_vt100_cmd(vt_parser, 0);
1491 #endif
1492 }
1493 }
1494
request_locator(vt_parser_t * vt_parser)1495 static void request_locator(vt_parser_t *vt_parser) {
1496 if (HAS_XTERM_LISTENER(vt_parser, request_locator)) {
1497 vt_mouse_report_mode_t orig;
1498
1499 #if 0
1500 stop_vt100_cmd(vt_parser, 0);
1501 #endif
1502
1503 if (vt_parser->mouse_mode < LOCATOR_CHARCELL_REPORT) {
1504 orig = vt_parser->mouse_mode;
1505 vt_parser->mouse_mode = LOCATOR_CHARCELL_REPORT;
1506 } else {
1507 orig = 0;
1508 }
1509
1510 vt_parser->locator_mode |= LOCATOR_REQUEST;
1511
1512 (*vt_parser->xterm_listener->request_locator)(vt_parser->xterm_listener->self);
1513
1514 vt_parser->locator_mode &= ~LOCATOR_REQUEST;
1515
1516 if (orig) {
1517 vt_parser->mouse_mode = orig;
1518 }
1519
1520 #if 0
1521 start_vt100_cmd(vt_parser, 0);
1522 #endif
1523 }
1524 }
1525
parse_title(vt_parser_t * vt_parser,char * src)1526 static char *parse_title(vt_parser_t *vt_parser, char *src /* the caller should allocated */) {
1527 size_t len;
1528 ef_parser_t *parser;
1529 vt_char_encoding_t src_encoding;
1530 ef_char_t ch;
1531 u_int num_chars;
1532 vt_char_encoding_t dst_encoding;
1533 char *dst;
1534
1535 if (src == NULL) {
1536 return NULL;
1537 }
1538
1539 dst = NULL;
1540
1541 len = strlen(src);
1542 if (vt_parser->set_title_using_hex) {
1543 if (!(len = bl_hex_decode(src, src, len))) {
1544 #ifdef DEBUG
1545 bl_debug_printf("Failed to decode %s as hex string.\n", src);
1546 #endif
1547 goto end;
1548 }
1549 src[len] = '\0';
1550 }
1551
1552 if (vt_parser->set_title_using_utf8 ? vt_parser->encoding == VT_UTF8 : 1) {
1553 parser = vt_parser->cc_parser;
1554 src_encoding = vt_parser->encoding;
1555 } else {
1556 if (!(parser = vt_char_encoding_parser_new(VT_UTF8))) {
1557 goto end;
1558 }
1559 src_encoding = VT_UTF8;
1560 }
1561
1562 (*parser->init)(parser);
1563 (*parser->set_str)(parser, src, len);
1564 num_chars = 0;
1565 while ((*parser->next_char)(parser, &ch)) {
1566 if ((ef_bytes_to_int(ch.ch, ch.size) & ~0x80) < 0x20) {
1567 #ifdef DEBUG
1568 bl_debug_printf("%s which contains control characters is ignored for window title.\n",
1569 src);
1570 #endif
1571 goto end;
1572 }
1573 num_chars++;
1574 }
1575
1576 /* locale encoding */
1577 dst_encoding = vt_get_char_encoding("auto");
1578
1579 if (src_encoding == dst_encoding) {
1580 return src;
1581 }
1582
1583 if ((dst = malloc(num_chars * UTF_MAX_SIZE + 1))) {
1584 (*parser->init)(parser);
1585 (*parser->set_str)(parser, src, len);
1586 len = vt_char_encoding_convert_with_parser(dst, num_chars * UTF_MAX_SIZE, dst_encoding,
1587 parser);
1588 dst[len] = '\0';
1589
1590 if (parser != vt_parser->cc_parser) {
1591 (*parser->destroy)(parser);
1592 }
1593 }
1594
1595 end:
1596 free(src);
1597
1598 return dst;
1599 }
1600
set_window_name(vt_parser_t * vt_parser,u_char * name)1601 static void set_window_name(vt_parser_t *vt_parser,
1602 u_char *name /* should be malloc'ed or NULL. */
1603 ) {
1604 free(vt_parser->win_name);
1605 vt_parser->win_name = name;
1606
1607 if (HAS_XTERM_LISTENER(vt_parser, set_window_name)) {
1608 #if 0
1609 stop_vt100_cmd(vt_parser, 0);
1610 #endif
1611 (*vt_parser->xterm_listener->set_window_name)(vt_parser->xterm_listener->self, name);
1612 #if 0
1613 start_vt100_cmd(vt_parser, 0);
1614 #endif
1615 }
1616 }
1617
set_icon_name(vt_parser_t * vt_parser,u_char * name)1618 static void set_icon_name(vt_parser_t *vt_parser,
1619 u_char *name /* should be malloc'ed or NULL. */
1620 ) {
1621 free(vt_parser->icon_name);
1622 vt_parser->icon_name = name;
1623
1624 if (HAS_XTERM_LISTENER(vt_parser, set_icon_name)) {
1625 #if 0
1626 stop_vt100_cmd(vt_parser, 0);
1627 #endif
1628 (*vt_parser->xterm_listener->set_icon_name)(vt_parser->xterm_listener->self, name);
1629 #if 0
1630 start_vt100_cmd(vt_parser, 0);
1631 #endif
1632 }
1633 }
1634
switch_im_mode(vt_parser_t * vt_parser)1635 static void switch_im_mode(vt_parser_t *vt_parser) {
1636 if (HAS_XTERM_LISTENER(vt_parser, switch_im_mode)) {
1637 #if 0
1638 stop_vt100_cmd(vt_parser, 0);
1639 #endif
1640 (*vt_parser->xterm_listener->switch_im_mode)(vt_parser->xterm_listener->self);
1641 #if 0
1642 start_vt100_cmd(vt_parser, 0);
1643 #endif
1644 }
1645 }
1646
im_is_active(vt_parser_t * vt_parser)1647 static int im_is_active(vt_parser_t *vt_parser) {
1648 if (HAS_XTERM_LISTENER(vt_parser, im_is_active)) {
1649 return (*vt_parser->xterm_listener->im_is_active)(vt_parser->xterm_listener->self);
1650 } else {
1651 return 0;
1652 }
1653 }
1654
set_modkey_mode(vt_parser_t * vt_parser,int key,int mode)1655 static void set_modkey_mode(vt_parser_t *vt_parser, int key, int mode) {
1656 if (key == 1) {
1657 if (-1 <= mode && mode <= 3) {
1658 vt_parser->modify_cursor_keys = mode;
1659 }
1660 } else if (key == 2) {
1661 if (-1 <= mode && mode <= 3) {
1662 vt_parser->modify_function_keys = mode;
1663 }
1664 } else if (key == 4) {
1665 if (0 <= mode && mode <= 2) {
1666 vt_parser->modify_other_keys = mode;
1667 }
1668 }
1669 }
1670
report_window_size(vt_parser_t * vt_parser,int by_char)1671 static void report_window_size(vt_parser_t *vt_parser, int by_char) {
1672 if (HAS_XTERM_LISTENER(vt_parser, get_window_size)) {
1673 int ps;
1674 u_int width;
1675 u_int height;
1676 char seq[5 + 1 /* ps */ + DIGIT_STR_LEN(u_int) * 2 + 1];
1677
1678 if (by_char) {
1679 width = vt_screen_get_logical_cols(vt_parser->screen);
1680 height = vt_screen_get_logical_rows(vt_parser->screen);
1681 ps = 8;
1682 } else {
1683 (*vt_parser->xterm_listener->get_window_size)(vt_parser->xterm_listener->self,
1684 &width, &height);
1685 ps = 4;
1686 }
1687
1688 sprintf(seq, "\x1b[%d;%d;%dt", ps, height, width);
1689 vt_write_to_pty(vt_parser->pty, seq, strlen(seq));
1690 }
1691 }
1692
report_display_size(vt_parser_t * vt_parser,int by_char)1693 static void report_display_size(vt_parser_t *vt_parser, int by_char) {
1694 if (HAS_XTERM_LISTENER(vt_parser, get_display_size)) {
1695 int ps;
1696 u_int width;
1697 u_int height;
1698 char seq[5 + 1 /* ps */ + DIGIT_STR_LEN(u_int) * 2 + 1];
1699
1700 (*vt_parser->xterm_listener->get_display_size)(vt_parser->xterm_listener->self,
1701 &width, &height);
1702
1703 if (by_char) {
1704 u_int col_width;
1705 u_int line_height;
1706
1707 if (!get_cell_size(vt_parser, &col_width, &line_height) ||
1708 (width /= col_width) == 0 || (height /= line_height) == 0) {
1709 return;
1710 }
1711
1712 ps = 9;
1713 } else {
1714 ps = 5;
1715 }
1716
1717 sprintf(seq, "\x1b[%d;%d;%dt", ps, height, width);
1718 vt_write_to_pty(vt_parser->pty, seq, strlen(seq));
1719 }
1720 }
1721
report_cell_size(vt_parser_t * vt_parser)1722 static void report_cell_size(vt_parser_t *vt_parser) {
1723 u_int col_width;
1724 u_int line_height;
1725
1726 if (get_cell_size(vt_parser, &col_width, &line_height)) {
1727 char seq[6 + DIGIT_STR_LEN(u_int) * 2 + 1];
1728
1729 sprintf(seq, "\x1b[6;%d;%dt", line_height, col_width);
1730 vt_write_to_pty(vt_parser->pty, seq, strlen(seq));
1731 }
1732 }
1733
report_window_or_icon_name(vt_parser_t * vt_parser,int is_window)1734 static void report_window_or_icon_name(vt_parser_t *vt_parser, int is_window) {
1735 char *seq;
1736 char *pre;
1737 char *title;
1738 size_t len;
1739 vt_char_encoding_t src_encoding;
1740 vt_char_encoding_t dst_encoding;
1741
1742 if (is_window) {
1743 title = vt_parser->win_name;
1744 pre = "\x1b]l";
1745 } else {
1746 title = vt_parser->icon_name;
1747 pre = "\x1b]L";
1748 }
1749
1750 if (!title) {
1751 title = "";
1752 }
1753
1754 /* see parse_title() */
1755 src_encoding = vt_get_char_encoding("auto");
1756
1757 if (vt_parser->get_title_using_utf8) {
1758 dst_encoding = VT_UTF8;
1759 } else {
1760 dst_encoding = vt_parser->encoding;
1761 }
1762
1763 len = strlen(title);
1764
1765 if (src_encoding != dst_encoding) {
1766 char *p;
1767
1768 if (!(p = alloca(len * UTF_MAX_SIZE + 1))) {
1769 goto error;
1770 }
1771
1772 len = vt_char_encoding_convert(p, len * UTF_MAX_SIZE, dst_encoding,
1773 title, len, src_encoding);
1774 title = p;
1775 }
1776
1777 if (!(seq = alloca(3 + len * (vt_parser->get_title_using_hex ? 2 : 1) + 3))) {
1778 goto error;
1779 }
1780
1781 strcpy(seq, pre);
1782
1783 if (vt_parser->get_title_using_hex) {
1784 len = bl_hex_encode(seq + 3, title, len);
1785 } else {
1786 memcpy(seq + 3, title, len);
1787 }
1788 strcpy(seq + 3 + len, "\x1b\\");
1789 vt_write_to_pty(vt_parser->pty, seq, strlen(seq));
1790
1791 return;
1792
1793 error:
1794 vt_write_to_pty(vt_parser->pty, pre, 3);
1795 vt_write_to_pty(vt_parser->pty, "\x1b\\", 2);
1796 }
1797
set_presentation_state(vt_parser_t * vt_parser,char * seq)1798 static void set_presentation_state(vt_parser_t *vt_parser, char *seq) {
1799 int row;
1800 int col;
1801 int page;
1802 char rend;
1803 char attr;
1804 char flag;
1805
1806 if (sscanf(seq, "%d;%d;%d;%c;%c;%c;0;2;@;BB%%5%%5\x1b\\",
1807 &row, &col, &page, &rend, &attr, &flag) == 6) {
1808 vt_screen_goto(vt_parser->screen, col - 1, row - 1);
1809
1810 if (rend & 0x20) {
1811 vt_parser->is_reversed = ((rend & 0x8) == 0x8);
1812 vt_parser->is_blinking = ((rend & 0x4) == 0x4);
1813 vt_parser->line_style &= ~LS_UNDERLINE;
1814 vt_parser->line_style |= ((rend & 0x2) ? LS_UNDERLINE_SINGLE : 0);
1815 vt_parser->is_bold = ((rend & 0x1) == 0x1);
1816 }
1817
1818 if (attr & 0x20) {
1819 vt_parser->is_protected = ((attr & 0x1) == 0x1);
1820 }
1821
1822 if (flag & 0x20) {
1823 vt_screen_set_auto_wrap(vt_parser->screen, ((flag & 0x8) == 0x8));
1824 vt_screen_set_relative_origin(vt_parser->screen, ((flag & 0x1) == 0x1));
1825 }
1826 }
1827 }
1828
report_presentation_state(vt_parser_t * vt_parser,int ps)1829 static void report_presentation_state(vt_parser_t *vt_parser, int ps) {
1830 if (ps == 1) {
1831 /* DECCIR */
1832 char seq[DIGIT_STR_LEN(u_int) * 3 + 31];
1833 int rend = 0x40;
1834 int attr = 0x40;
1835 int flag = 0x40;
1836
1837 if (vt_parser->is_reversed) {
1838 rend |= 0x8;
1839 }
1840 if (vt_parser->is_blinking) {
1841 rend |= 0x4;
1842 }
1843 if (vt_parser->line_style & LS_UNDERLINE) {
1844 rend |= 0x2;
1845 }
1846 if (vt_parser->is_bold) {
1847 rend |= 0x1;
1848 }
1849
1850 if (vt_parser->is_protected) {
1851 attr |= 0x1;
1852 }
1853
1854 if (vt_screen_is_auto_wrap(vt_parser->screen)) {
1855 flag |= 0x8;
1856 }
1857 if (vt_screen_is_relative_origin(vt_parser->screen)) {
1858 flag |= 0x1;
1859 }
1860
1861 sprintf(seq, "\x1bP1$u%d;%d;%d;%c;%c;%c;0;2;@;BB%%5%%5\x1b\\",
1862 vt_screen_cursor_logical_row(vt_parser->screen) + 1,
1863 vt_screen_cursor_logical_col(vt_parser->screen) + 1,
1864 vt_screen_get_page_id(vt_parser->screen) + 1, rend, attr, flag);
1865
1866 vt_write_to_pty(vt_parser->pty, seq, strlen(seq));
1867 } else if (ps == 2) {
1868 /* DECTABSR */
1869 char *seq;
1870 u_int max_digit_len = 1;
1871 u_int cols = vt_screen_get_logical_cols(vt_parser->screen);
1872 u_int tmp = cols;
1873
1874 while ((tmp /= 10) > 0) {
1875 max_digit_len++;
1876 }
1877
1878 if ((seq = alloca(5 + (max_digit_len + 1) * cols + 3))) {
1879 u_int count;
1880 char *p;
1881
1882 p = strcpy(seq, "\x1bP2$u") + 5;
1883
1884 for (count = 0; count < cols; count++) {
1885 if (vt_screen_is_tab_stop(vt_parser->screen, count)) {
1886 sprintf(p, "%d/", count + 1);
1887 p += strlen(p);
1888 }
1889 }
1890
1891 if (p != seq + 5) {
1892 p--;
1893 }
1894
1895 strcpy(p, "\x1b\\");
1896
1897 vt_write_to_pty(vt_parser->pty, seq, p + 2 - seq);
1898 }
1899 }
1900 }
1901
report_color_table(vt_parser_t * vt_parser,int pu)1902 static void report_color_table(vt_parser_t *vt_parser, int pu) {
1903 int color;
1904 u_int8_t r, g, b;
1905 char seq[5+(3*5+4)*256+255+3];
1906 char *p;
1907
1908 p = strcpy(seq, "\x1bP2$s") + 5;
1909
1910 if (pu == 2) {
1911 /* RGB */
1912 for (color = 0; color < 256; color++) {
1913 vt_get_color_rgba(color, &r, &g, &b, NULL);
1914 sprintf(p, "%d;2;%d;%d;%d/", color, r * 100 / 255, g * 100 / 255, b * 100 / 255);
1915 p += strlen(p);
1916 }
1917 } else if (pu == 1) {
1918 /* HLS */
1919 int h, l, s;
1920 for (color = 0; color < 256; color++) {
1921 vt_get_color_rgba(color, &r, &g, &b, NULL);
1922 bl_rgb_to_hls(&h, &l, &s, r, g, b);
1923 sprintf(p, "%d;1;%d;%d;%d/", color, h, l, s);
1924 p += strlen(p);
1925 }
1926 } else {
1927 return;
1928 }
1929
1930 strcpy(p - 1, "\x1b\\");
1931
1932 vt_write_to_pty(vt_parser->pty, seq, strlen(seq));
1933 }
1934
1935 #ifndef NO_IMAGE
cursor_char_is_picture_and_modified(vt_screen_t * screen)1936 static int cursor_char_is_picture_and_modified(vt_screen_t *screen) {
1937 vt_line_t *line;
1938 vt_char_t *ch;
1939
1940 if ((line = vt_screen_get_cursor_line(screen)) && vt_line_is_modified(line) &&
1941 (ch = vt_char_at(line, vt_screen_cursor_char_index(screen))) && vt_get_picture_char(ch)) {
1942 return 1;
1943 } else {
1944 return 0;
1945 }
1946 }
1947
1948 /* Don't call this if SIXEL_NO_SCROLLING is false. */
check_sixel_anim(vt_screen_t * screen,u_char * str,size_t left)1949 static int check_sixel_anim(vt_screen_t *screen, u_char *str, size_t left) {
1950 vt_line_t *line = vt_screen_get_line(screen, 0); /* Always non-NULL */
1951 vt_char_t *ch;
1952
1953 if ((ch = vt_char_at(line, 0)) && vt_get_picture_char(ch)) {
1954 while (--left > 0) {
1955 if (*(++str) == '\x1b') {
1956 if (--left == 0) {
1957 break;
1958 }
1959
1960 if (*(++str) == 'P') {
1961 /* It seems animation sixel. */
1962 return 1;
1963 }
1964 }
1965 }
1966 }
1967
1968 return 0;
1969 }
1970
show_picture(vt_parser_t * vt_parser,char * file_path,int clip_beg_col,int clip_beg_row,int clip_cols,int clip_rows,int img_cols,int img_rows,int keep_aspect,int is_sixel)1971 static void show_picture(vt_parser_t *vt_parser, char *file_path, int clip_beg_col,
1972 int clip_beg_row, int clip_cols, int clip_rows,
1973 int img_cols, int img_rows, int keep_aspect,
1974 int is_sixel /* 0: not sixel, 1: sixel, 2: sixel anim, 3: macro */
1975 ) {
1976 #ifndef DONT_OPTIMIZE_DRAWING_PICTURE
1977 if (is_sixel == 2) {
1978 (*vt_parser->xterm_listener->show_tmp_picture)(vt_parser->xterm_listener->self, file_path);
1979
1980 vt_parser->yield = 1;
1981
1982 return;
1983 }
1984 #endif /* DONT_OPTIMIZE_DRAWING_PICTURE */
1985
1986 if (HAS_XTERM_LISTENER(vt_parser, get_picture_data)) {
1987 vt_char_t *data;
1988
1989 #ifdef __DEBUG
1990 struct timeval tv1, tv2;
1991 gettimeofday(&tv1, NULL);
1992 #endif
1993
1994 if ((data = (*vt_parser->xterm_listener->get_picture_data)(
1995 vt_parser->xterm_listener->self, file_path, &img_cols, &img_rows, NULL, NULL,
1996 is_sixel ? &vt_parser->sixel_palette : NULL, keep_aspect, 0)) &&
1997 clip_beg_row < img_rows && clip_beg_col < img_cols) {
1998 vt_char_t *p;
1999 int row;
2000 int cursor_col;
2001 int orig_auto_wrap;
2002
2003 /* Flush buffer before vt_screen_overwrite_chars(picture data). */
2004 flush_buffer(vt_parser);
2005
2006 #ifdef __DEBUG
2007 gettimeofday(&tv2, NULL);
2008 bl_debug_printf("Processing sixel time (msec) %lu - %lu = %lu\n",
2009 tv2.tv_sec * 1000 + tv2.tv_usec / 1000,
2010 tv1.tv_sec * 1000 + tv1.tv_usec / 1000,
2011 tv2.tv_sec * 1000 + tv2.tv_usec / 1000 -
2012 tv1.tv_sec * 1000 - tv1.tv_usec / 1000);
2013 #endif
2014
2015 if (clip_cols == 0) {
2016 clip_cols = img_cols - clip_beg_col;
2017 }
2018
2019 if (clip_rows == 0) {
2020 clip_rows = img_rows - clip_beg_row;
2021 }
2022
2023 if (clip_beg_row + clip_rows > img_rows) {
2024 clip_rows = img_rows - clip_beg_row;
2025 }
2026
2027 if (clip_beg_col + clip_cols > img_cols) {
2028 clip_cols = img_cols - clip_beg_col;
2029 }
2030
2031 p = data + (img_cols * clip_beg_row);
2032 row = 0;
2033
2034 if (is_sixel && !vt_parser->sixel_scrolling) {
2035 vt_screen_save_cursor(vt_parser->screen); /* XXX */
2036 vt_parser->is_visible_cursor = 0;
2037 vt_screen_goto_home(vt_parser->screen);
2038 vt_screen_goto_beg_of_line(vt_parser->screen);
2039 }
2040
2041 if (cursor_char_is_picture_and_modified(vt_parser->screen)) {
2042 /* Perhaps it is animation. */
2043 interrupt_vt100_cmd(vt_parser);
2044 vt_parser->yield = 1;
2045 }
2046
2047 orig_auto_wrap = vt_screen_is_auto_wrap(vt_parser->screen);
2048 vt_screen_set_auto_wrap(vt_parser->screen, 0);
2049 cursor_col = vt_screen_cursor_logical_col(vt_parser->screen);
2050
2051 while (1) {
2052 vt_screen_overwrite_chars(vt_parser->screen, p + clip_beg_col, clip_cols);
2053
2054 if (++row >= clip_rows) {
2055 break;
2056 }
2057
2058 if (is_sixel && !vt_parser->sixel_scrolling) {
2059 if (!vt_screen_go_downward(vt_parser->screen, 1)) {
2060 break;
2061 }
2062 } else {
2063 vt_screen_line_feed(vt_parser->screen);
2064 }
2065
2066 vt_screen_go_horizontally(vt_parser->screen, cursor_col);
2067
2068 p += img_cols;
2069 }
2070
2071 if (is_sixel) {
2072 if (vt_parser->sixel_scrolling) {
2073 if (!CURSOR_TO_RIGHT_OF_SIXEL(vt_parser) &&
2074 /* mlterm always enables DECSET 8452 in status line. */
2075 !vt_status_line_is_focused(vt_parser->screen)) {
2076 vt_screen_line_feed(vt_parser->screen);
2077 vt_screen_go_horizontally(vt_parser->screen, cursor_col);
2078 }
2079 } else {
2080 vt_screen_restore_cursor(vt_parser->screen); /* XXX */
2081 vt_parser->is_visible_cursor = 1;
2082 }
2083 }
2084
2085 vt_str_destroy(data, img_cols * img_rows);
2086
2087 vt_screen_set_auto_wrap(vt_parser->screen, orig_auto_wrap);
2088
2089 if (strstr(file_path, "://")) {
2090 /* Showing remote image is very heavy. */
2091 vt_parser->yield = 1;
2092 }
2093 }
2094 }
2095 }
2096
define_drcs_picture(vt_parser_t * vt_parser,char * path,ef_charset_t cs,int idx,u_int pix_width,u_int pix_height,u_int col_width,u_int line_height)2097 static void define_drcs_picture(vt_parser_t *vt_parser, char *path, ef_charset_t cs, int idx,
2098 u_int pix_width /* can be 0 */, u_int pix_height /* can be 0 */,
2099 u_int col_width, u_int line_height) {
2100 if (HAS_XTERM_LISTENER(vt_parser, get_picture_data)) {
2101 vt_char_t *data;
2102 int cols = 0;
2103 int rows = 0;
2104 int cols_small = 0;
2105 int rows_small = 0;
2106
2107 if (pix_width > 0 && pix_height > 0) {
2108 if (old_drcs_sixel) {
2109 cols = pix_width / col_width;
2110 rows = pix_height / line_height;
2111 } else {
2112 cols = (pix_width + col_width - 1) / col_width;
2113 rows = (pix_height + line_height - 1) / line_height;
2114 }
2115 }
2116
2117 if (idx <= 0x5f &&
2118 (data = (*vt_parser->xterm_listener->get_picture_data)(vt_parser->xterm_listener->self,
2119 path, &cols, &rows, &cols_small,
2120 &rows_small, NULL, 0, 1))) {
2121 u_int pages;
2122 u_int offset = 0;
2123 vt_drcs_font_t *font;
2124
2125 if (!vt_parser->drcs) {
2126 vt_parser->drcs = vt_drcs_new();
2127 }
2128
2129 if (!old_drcs_sixel) {
2130 cols_small = cols;
2131 rows_small = rows;
2132 }
2133
2134 for (pages = (cols_small * rows_small + 95) / 96; pages > 0; pages--) {
2135 font = vt_drcs_get_font(vt_parser->drcs, cs, 1);
2136
2137 vt_drcs_add_picture(font, vt_char_picture_id(vt_get_picture_char(data)),
2138 offset, idx, cols, rows, cols_small, rows_small);
2139
2140 offset += (96 - idx);
2141 idx = 0;
2142
2143 if (cs == CS94SB_ID(0x7e)) {
2144 cs = CS96SB_ID(0x30);
2145 } else if (cs == CS96SB_ID(0x7e)) {
2146 cs = CS94SB_ID(0x30);
2147 } else {
2148 cs++;
2149 }
2150 }
2151
2152 vt_str_destroy(data, cols * rows);
2153 }
2154 }
2155 }
2156
2157 /*
2158 * The 2nd \x1bP...\x1b\\ in the following sequence (e.g. biplane.six)
2159 * overwrites the image of the 1st \x1bP...\x1b\\.
2160 * (\x1b[8k moves the cursor upward after drawing the 1st image.)
2161 * \x1bP...\x1b\\\x1b[8k\x1bP;1...\x1b\\
2162 * ^-> Pixel positions specified as 0 remain at their current color
2163 *
2164 * -> The 1st and 2nd sequences are saved in the same file and
2165 * load_sixel_from_data() in c_sixel.c draws them at once.
2166 *
2167 * XXX
2168 * return -1 if len == 0, and wait for the next sequence.
2169 */
is_separated_sixel(u_char * str,size_t len)2170 static int is_separated_sixel(u_char *str, size_t len) {
2171 if (len >= 3) {
2172 if (*str == '\x1d') {
2173 str++;
2174 len--;
2175 } else if (*str == '\x1b' && *(str + 1) == ']') {
2176 str += 2;
2177 len -= 2;
2178 } else {
2179 return 0;
2180 }
2181
2182 while ('0' <= *str && *str <= '9') {
2183 str++;
2184 if (--len == 0) {
2185 return 0;
2186 }
2187 }
2188
2189 if (*str == 'A' || *str == 'k') {
2190 u_int count = 0;
2191
2192 str++;
2193 len--;
2194 while (len >= 3 /* \x90;1 => 3 */) {
2195 if (*str == '\x1b' && *(str + 1) == 'P') {
2196 str += 2;
2197 len -= 2;
2198 } else {
2199 len--;
2200 if (*(str++) != 0x90) {
2201 goto next_loop;
2202 }
2203 }
2204
2205 if ('0' <= *str && *str <= '9') {
2206 str++;
2207 len--;
2208 }
2209
2210 if (len >= 2 && *str == ';') {
2211 if (*(++str) == '1') {
2212 return 1;
2213 }
2214 len--;
2215 }
2216
2217 next_loop:
2218 /*
2219 * It is assumed that the distance between 1st and 2nd sequence is
2220 * less than about 10 bytes.
2221 */
2222 if (++count >= 10) {
2223 break;
2224 }
2225 }
2226 }
2227 }
2228
2229 return 0;
2230 }
2231
2232 static int increment_str(u_char **str, size_t *left);
2233
save_sixel_or_regis(vt_parser_t * vt_parser,char * path,u_char * dcs_beg,u_char ** body,size_t * body_len)2234 static int save_sixel_or_regis(vt_parser_t *vt_parser, char *path, u_char *dcs_beg,
2235 u_char **body /* q ... */ , size_t *body_len) {
2236 u_char *str_p = *body;
2237 size_t left = *body_len;
2238 int is_end;
2239 FILE *fp;
2240
2241 if (left > 2 && *(str_p + 1) == '\0') {
2242 fp = fopen(path, "a");
2243 is_end = *(str_p + 2);
2244 /*
2245 * dcs_beg will equal to str_p after str_p is
2246 * incremented by the following increment_str().
2247 */
2248 dcs_beg = (str_p += 2) + 1;
2249 left -= 2;
2250 } else {
2251 char *format;
2252 vt_color_t color;
2253 u_int8_t red;
2254 u_int8_t green;
2255 u_int8_t blue;
2256
2257 fp = fopen(path, "w");
2258 is_end = 0;
2259
2260 if (strcmp(path + strlen(path) - 4, ".rgs") == 0) {
2261 /* Clear background by VT_BG_COLOR */
2262
2263 /* 13 + 3*3 + 1 = 23 */
2264 format = "S(I(R%dG%dB%d))S(E)";
2265 color = VT_BG_COLOR;
2266 } else if (strcmp(path + strlen(path) - 4, ".six") == 0) {
2267 /*
2268 * Set VT_FG_COLOR to the default value of the first entry of the sixel palette,
2269 * because some sixel graphics data has not palette definitions (#0;2;r;g;b).
2270 * '9' is a mark which means that this definition is added by mlterm itself.
2271 * (see c_sixel.c)
2272 */
2273
2274 /* 7 + 3*3 + 1 = 17 */
2275 format = "#0;9;%d;%d;%d";
2276 color = VT_FG_COLOR;
2277 } else {
2278 format = NULL;
2279 }
2280
2281 if (format && HAS_XTERM_LISTENER(vt_parser, get_rgb) &&
2282 (*vt_parser->xterm_listener->get_rgb)(vt_parser->xterm_listener->self, &red,
2283 &green, &blue, color)) {
2284 char color_seq[23];
2285
2286 if (color == VT_FG_COLOR) {
2287 /* sixel */
2288 red = red * 100 / 255;
2289 green = green * 100 / 255;
2290 blue = blue * 100 / 255;
2291 }
2292
2293 fwrite(dcs_beg, 1, str_p - dcs_beg + 1, fp);
2294 sprintf(color_seq, format, red, green, blue);
2295 fwrite(color_seq, 1, strlen(color_seq), fp);
2296 dcs_beg = str_p + 1;
2297 }
2298
2299 /*
2300 * +1 in case str_p[left - vt_parser->r_buf.new_len]
2301 * points "\\" of "\x1b\\".
2302 */
2303 if (left > vt_parser->r_buf.new_len + 1) {
2304 str_p += (left - vt_parser->r_buf.new_len - 1);
2305 left = vt_parser->r_buf.new_len + 1;
2306 }
2307 }
2308
2309 while (1) {
2310 if (!increment_str(&str_p, &left)) {
2311 if (is_end == 2) {
2312 left++;
2313 break;
2314 }
2315
2316 if (vt_parser->logging_vt_seq && use_ttyrec_format) {
2317 fclose(fp);
2318 free(path);
2319
2320 *body = str_p;
2321 *body_len = left;
2322
2323 return 0;
2324 }
2325
2326 fwrite(dcs_beg, 1, str_p - dcs_beg + 1, fp);
2327
2328 vt_parser->r_buf.left = 0;
2329 if (!receive_bytes(vt_parser)) {
2330 fclose(fp);
2331 memcpy(vt_parser->r_buf.chars,
2332 strcmp(path + strlen(path) - 4, ".six") == 0 ? "\x1bPq\0" : "\x1bPp\0", 4);
2333 free(path);
2334 vt_parser->r_buf.chars[4] = is_end;
2335 vt_parser->r_buf.filled_len = vt_parser->r_buf.left = 5;
2336
2337 /* No more data in pty. */
2338 vt_parser->yield = 1;
2339
2340 *body = str_p;
2341 *body_len = left;
2342
2343 return 0;
2344 }
2345
2346 dcs_beg = str_p = CURRENT_STR_P(vt_parser);
2347 left = vt_parser->r_buf.left;
2348 }
2349
2350 if (is_end == 2) {
2351 if (is_separated_sixel(str_p, left)) {
2352 /* continued (XXX Hack for biplane.six) */
2353 is_end = 0;
2354 } else {
2355 str_p--;
2356 left++;
2357 break;
2358 }
2359 }
2360 /*
2361 * 0x9c is regarded as ST here, because sixel sequence
2362 * unuses it certainly.
2363 */
2364 else if (*str_p == 0x9c) {
2365 is_end = 2;
2366 } else if (*str_p == CTL_ESC) {
2367 is_end = 1;
2368 } else if (is_end == 1) {
2369 if (*str_p == '\\') {
2370 is_end = 2;
2371 } else {
2372 is_end = 0;
2373 }
2374 }
2375 }
2376
2377 fwrite(dcs_beg, 1, str_p - dcs_beg + 1, fp);
2378 fclose(fp);
2379
2380 *body = str_p;
2381 *body_len = left;
2382
2383 return 1;
2384 }
2385
check_cell_size(vt_parser_t * vt_parser,u_int col_width,u_int line_height)2386 static int check_cell_size(vt_parser_t *vt_parser, u_int col_width, u_int line_height) {
2387 u_int cw;
2388 u_int lh;
2389
2390 /*
2391 * XXX
2392 * This works except vertical mode, but no problem because images are not
2393 * supported on vertical mode.
2394 */
2395 if (get_cell_size(vt_parser, &cw, &lh) && cw == col_width && lh == line_height) {
2396 return 1;
2397 } else {
2398 return 0;
2399 }
2400 }
2401 #endif
2402
snapshot(vt_parser_t * vt_parser,vt_char_encoding_t encoding,char * file_name,vt_write_content_area_t area)2403 static void snapshot(vt_parser_t *vt_parser, vt_char_encoding_t encoding,
2404 char *file_name, vt_write_content_area_t area) {
2405 char buf[16];
2406 char *path;
2407 int fd;
2408 ef_conv_t *conv;
2409
2410 if (!(path = get_home_file_path(file_name, get_now_suffix(buf), "snp"))) {
2411 return;
2412 }
2413
2414 fd = open(path, O_WRONLY | O_CREAT, 0600);
2415 free(path);
2416 if (fd == -1) {
2417 #ifdef DEBUG
2418 bl_debug_printf(BL_DEBUG_TAG " Failed to open %s\n", file_name);
2419 #endif
2420
2421 return;
2422 }
2423
2424 if (encoding == VT_UNKNOWN_ENCODING || (conv = vt_char_encoding_conv_new(encoding)) == NULL) {
2425 conv = vt_parser->cc_conv;
2426 }
2427
2428 vt_screen_write_content(vt_parser->screen, fd, conv, 0, area);
2429
2430 if (conv != vt_parser->cc_conv) {
2431 (*conv->destroy)(conv);
2432 }
2433
2434 close(fd);
2435 }
2436
set_col_size_of_width_a(vt_parser_t * vt_parser,u_int col_size_a)2437 static void set_col_size_of_width_a(vt_parser_t *vt_parser, u_int col_size_a) {
2438 if (col_size_a == 1 || col_size_a == 2) {
2439 #ifdef USE_LIBSSH2
2440 /* Don't change it after vt_parser_set_pty() on mosh. See vt_parser_set_pty(). */
2441 if (!vt_parser->pty || vt_pty_get_mode(vt_parser->pty) != PTY_MOSH)
2442 #endif
2443 {
2444 vt_parser->col_size_of_width_a = col_size_a;
2445 }
2446 } else {
2447 #ifdef DEBUG
2448 bl_warn_printf(BL_DEBUG_TAG " col size should be 1 or 2. default value 1 is used.\n");
2449 #endif
2450
2451 vt_parser->col_size_of_width_a = 1;
2452 }
2453 }
2454
2455 /*
2456 * This function will destroy the content of pt.
2457 */
config_protocol_set(vt_parser_t * vt_parser,char * pt,int save)2458 static void config_protocol_set(vt_parser_t *vt_parser, char *pt, int save) {
2459 int ret;
2460 char *dev;
2461
2462 ret = vt_parse_proto_prefix(&dev, &pt, save);
2463 if (ret <= 0) {
2464 /*
2465 * ret == -1: do_challenge failed.
2466 * ret == 0: illegal format.
2467 * to_menu is necessarily 0 because it is pty that msg should be returned
2468 * to.
2469 */
2470 vt_response_config(vt_parser->pty, ret < 0 ? "forbidden" : "error", NULL, 0);
2471
2472 return;
2473 }
2474
2475 if (dev && strlen(dev) <= 7 && strstr(dev, "font")) {
2476 char *key;
2477 char *val;
2478
2479 if (vt_parse_proto(NULL, &key, &val, &pt, 0, 0) && val &&
2480 HAS_CONFIG_LISTENER(vt_parser, set_font)) {
2481 /*
2482 * Screen is redrawn not in vt_parser->config_listener->set_font
2483 * but in stop_vt100_cmd, so it is not necessary to hold
2484 * vt_parser->config_listener->set_font between stop_vt100_cmd and
2485 * start_vt100_cmd.
2486 */
2487 #if 0
2488 stop_vt100_cmd(vt_parser, 0);
2489 #endif
2490
2491 (*vt_parser->config_listener->set_font)(vt_parser->config_listener->self, dev, key, val,
2492 save);
2493
2494 #if 0
2495 start_vt100_cmd(vt_parser, 0);
2496 #endif
2497 }
2498 } else if (dev && strcmp(dev, "color") == 0) {
2499 char *key;
2500 char *val;
2501
2502 if (vt_parse_proto(NULL, &key, &val, &pt, 0, 0) && val &&
2503 HAS_CONFIG_LISTENER(vt_parser, set_color)) {
2504 /*
2505 * Screen is redrawn not in vt_parser->config_listener->set_color
2506 * but in stop_vt100_cmd, so it is not necessary to hold
2507 * vt_parser->config_listener->set_font between stop_vt100_cmd and
2508 * start_vt100_cmd.
2509 */
2510 #if 0
2511 stop_vt100_cmd(vt_parser, 0);
2512 #endif
2513
2514 (*vt_parser->config_listener->set_color)(vt_parser->config_listener->self, dev, key,
2515 val, save);
2516
2517 #if 0
2518 start_vt100_cmd(vt_parser, 0);
2519 #endif
2520 }
2521 } else {
2522 stop_vt100_cmd(vt_parser, 0);
2523
2524 if ((!HAS_CONFIG_LISTENER(vt_parser, exec) ||
2525 !(*vt_parser->config_listener->exec)(vt_parser->config_listener->self, pt))) {
2526 bl_conf_write_t *conf;
2527
2528 if (save) {
2529 char *path;
2530
2531 /* XXX */
2532 if ((path = bl_get_user_rc_path("mlterm/main")) == NULL) {
2533 return;
2534 }
2535
2536 conf = bl_conf_write_open(path);
2537 free(path);
2538 } else {
2539 conf = NULL;
2540 }
2541
2542 /* accept multiple key=value pairs. */
2543 while (pt) {
2544 char *key;
2545 char *val;
2546
2547 if (!vt_parse_proto(dev ? NULL : &dev, &key, &val, &pt, 0, 1)) {
2548 break;
2549 }
2550
2551 if (conf) {
2552 /* XXX */
2553 if (strcmp(key, "xim") != 0) {
2554 bl_conf_io_write(conf, key, val);
2555 }
2556 }
2557
2558 if (val == NULL) {
2559 val = "";
2560 }
2561
2562 if (HAS_CONFIG_LISTENER(vt_parser, set) &&
2563 (*vt_parser->config_listener->set)(vt_parser->config_listener->self, dev, key,
2564 val)) {
2565 if (!vt_parser->config_listener) {
2566 /* pty changed. */
2567 break;
2568 }
2569 }
2570
2571 dev = NULL;
2572 }
2573
2574 if (conf) {
2575 bl_conf_write_close(conf);
2576
2577 if (HAS_CONFIG_LISTENER(vt_parser, saved)) {
2578 (*vt_parser->config_listener->saved)();
2579 }
2580 }
2581 }
2582
2583 start_vt100_cmd(vt_parser, 0);
2584 }
2585 }
2586
config_protocol_set_simple(vt_parser_t * vt_parser,char * key,char * val,int visualize)2587 static void config_protocol_set_simple(vt_parser_t *vt_parser, char *key, char *val,
2588 int visualize) {
2589 if (HAS_CONFIG_LISTENER(vt_parser, set)) {
2590 if (visualize) {
2591 stop_vt100_cmd(vt_parser, 0);
2592 }
2593
2594 (*vt_parser->config_listener->set)(vt_parser->config_listener->self, NULL, key, val);
2595
2596 if (visualize) {
2597 start_vt100_cmd(vt_parser, 0);
2598 }
2599 }
2600 }
2601
2602 /*
2603 * This function will destroy the content of pt.
2604 */
config_protocol_get(vt_parser_t * vt_parser,char * pt,int to_menu,int * flag)2605 static void config_protocol_get(vt_parser_t *vt_parser, char *pt, int to_menu, int *flag) {
2606 char *dev;
2607 char *key;
2608 int ret;
2609
2610 if (to_menu == 0 && strchr(pt, ';') == NULL) {
2611 /* pt doesn't have challenge */
2612 to_menu = -1;
2613
2614 stop_vt100_cmd(vt_parser, 0);
2615 }
2616 #if 0
2617 else {
2618 /*
2619 * It is assumed that screen is not redrawn not in
2620 * vt_parser->config_listener->get, so vt_parser->config_listener->get
2621 * is not held between stop_vt100_cmd and start_vt100_cmd.
2622 */
2623 stop_vt100_cmd(vt_parser, 0);
2624 }
2625 #endif
2626
2627 ret = vt_parse_proto(&dev, &key, NULL, &pt, to_menu == 0, 0);
2628 if (ret <= 0) {
2629 /*
2630 * ret == -1: do_challenge failed.
2631 * ret == 0: illegal format.
2632 * to_menu is necessarily 0 because it is pty that msg should be returned
2633 * to.
2634 */
2635 vt_response_config(vt_parser->pty, ret < 0 ? "forbidden" : "error", NULL, 0);
2636
2637 goto end;
2638 }
2639
2640 if (dev && strlen(dev) <= 7 && strstr(dev, "font")) {
2641 char *cs;
2642
2643 /* Compat with old format (3.6.3 or before): <cs>,<fontsize> */
2644 cs = bl_str_sep(&key, ",");
2645
2646 if (HAS_CONFIG_LISTENER(vt_parser, get_font)) {
2647 (*vt_parser->config_listener->get_font)(vt_parser->config_listener->self, dev, cs,
2648 to_menu);
2649 }
2650 } else if (dev && strcmp(dev, "color") == 0) {
2651 if (HAS_CONFIG_LISTENER(vt_parser, get_color)) {
2652 (*vt_parser->config_listener->get_color)(vt_parser->config_listener->self, key,
2653 to_menu);
2654 }
2655 } else if (HAS_CONFIG_LISTENER(vt_parser, get)) {
2656 (*vt_parser->config_listener->get)(vt_parser->config_listener->self, dev, key, to_menu);
2657 }
2658
2659 end:
2660 if (to_menu == -1) {
2661 start_vt100_cmd(vt_parser, 0);
2662 }
2663 #if 0
2664 else {
2665 start_vt100_cmd(vt_parser, 0);
2666 }
2667 #endif
2668 }
2669
2670 #ifdef SUPPORT_ITERM2_OSC1337
2671
2672 #include <pobl/bl_path.h> /* bl_basename */
2673
2674 /*
2675 * This function will destroy the content of pt.
2676 */
iterm2_proprietary_set(vt_parser_t * vt_parser,char * pt)2677 static void iterm2_proprietary_set(vt_parser_t *vt_parser, char *pt) {
2678 if (strncmp(pt, "File=", 5) == 0) {
2679 /* See https://www.iterm2.com/images.html (2014/03/20) */
2680
2681 char *args;
2682 char *encoded;
2683 char *decoded;
2684 size_t e_len;
2685 u_int width;
2686 u_int height;
2687 char *path;
2688 int keep_aspect;
2689
2690 args = pt + 5;
2691 width = height = 0;
2692 keep_aspect = 1; /* default value is 1. */
2693
2694 if ((encoded = strchr(args, ':'))) {
2695 char *beg;
2696 char *end;
2697
2698 *(encoded++) = '\0';
2699
2700 if ((beg = strstr(args, "name=")) &&
2701 ((end = strchr((beg += 5), ';')) || (end = beg + strlen(beg))) &&
2702 (path = malloc(7 + (end - beg) + 1))) {
2703 char *file;
2704 char *new_path;
2705 size_t d_len;
2706
2707 strcpy(path, "mlterm/");
2708
2709 d_len = bl_base64_decode(path + 7, beg, end - beg);
2710 path[7 + d_len] = '\0';
2711 file = bl_basename(path);
2712 memmove(path + 7, file, strlen(file) + 1);
2713 new_path = bl_get_user_rc_path(path);
2714 free(path);
2715 path = new_path;
2716 } else {
2717 path = get_home_file_path("", vt_pty_get_slave_name(vt_parser->pty) + 5, "img");
2718 }
2719
2720 if ((beg = strstr(args, "width=")) &&
2721 ((end = strchr((beg += 6), ';')) || (end = beg + strlen(beg)))) {
2722 *(end--) = '\0';
2723 if ('0' <= *end && *end <= '9') {
2724 width = atoi(beg);
2725 } else if (*end == '%') {
2726 /* XXX vertical mode is not considered */
2727 width = atoi(beg) * vt_screen_get_logical_cols(vt_parser->screen) / 100;
2728 } else {
2729 /* XXX Npx is not supported */
2730 }
2731 *(end + 1) = ';'; /* For next strstr() */
2732 }
2733
2734 if ((beg = strstr(args, "height=")) &&
2735 ((end = strchr((beg += 7), ';')) || (end = beg + strlen(beg)))) {
2736 *(end--) = '\0';
2737 if ('0' <= *end && *end <= '9') {
2738 height = atoi(beg);
2739 } else if (*end == '%') {
2740 /* XXX vertical mode is not considered */
2741 height = atoi(beg) * vt_screen_get_logical_rows(vt_parser->screen) / 100;
2742 } else {
2743 /* XXX Npx is not supported */
2744 }
2745 /* *(end + 1) = ';'; */
2746 }
2747
2748 if ((beg = strstr(args, "preserveAspectRatio=")) && beg[20] == '0') {
2749 keep_aspect = 0;
2750 }
2751 } else {
2752 encoded = args;
2753 path = get_home_file_path("", vt_pty_get_slave_name(vt_parser->pty) + 5, "img");
2754 }
2755
2756 if (!path) {
2757 return;
2758 }
2759 #ifdef DEBUG
2760 else {
2761 bl_debug_printf(BL_DEBUG_TAG " OSC 1337 file is stored at %s.\n", path);
2762 }
2763 #endif
2764
2765 if ((e_len = strlen(encoded)) > 0 && (decoded = malloc(e_len))) {
2766 size_t d_len;
2767 FILE *fp;
2768
2769 if ((d_len = bl_base64_decode(decoded, encoded, e_len)) > 0 && (fp = fopen(path, "w"))) {
2770 fwrite(decoded, 1, d_len, fp);
2771 fclose(fp);
2772
2773 show_picture(vt_parser, path, 0, 0, 0, 0, width, height, keep_aspect, 0);
2774
2775 remove(path);
2776 }
2777
2778 free(decoded);
2779 }
2780
2781 free(path);
2782 }
2783 }
2784 #endif
2785
change_char_fine_color(vt_parser_t * vt_parser,int * ps,int num)2786 static int change_char_fine_color(vt_parser_t *vt_parser, int *ps, int num) {
2787 int proceed;
2788 vt_color_t color;
2789
2790 if (ps[0] != 38 && ps[0] != 48) {
2791 return 0;
2792 }
2793
2794 if (num >= 3 && ps[1] == 5) {
2795 proceed = 3;
2796 color = (ps[2] <= 0 ? 0 : ps[2]);
2797 } else if (num >= 5 && ps[1] == 2) {
2798 proceed = 5;
2799 color = vt_get_closest_color(ps[2] <= 0 ? 0 : ps[2], ps[3] <= 0 ? 0 : ps[3],
2800 ps[4] <= 0 ? 0 : ps[4]);
2801 } else {
2802 return 1;
2803 }
2804
2805 if (vt_parser->use_ansi_colors) {
2806 if (ps[0] == 38) {
2807 vt_parser->fg_color = color;
2808 vt_screen_set_bce_fg_color(vt_parser->screen, color);
2809 } else /* if( ps[0] == 48) */
2810 {
2811 vt_parser->bg_color = color;
2812 vt_screen_set_bce_bg_color(vt_parser->screen, color);
2813 }
2814 }
2815
2816 return proceed;
2817 }
2818
change_char_attr(vt_parser_t * vt_parser,int flag)2819 static void change_char_attr(vt_parser_t *vt_parser, int flag) {
2820 vt_color_t fg_color;
2821 vt_color_t bg_color;
2822
2823 fg_color = vt_parser->fg_color;
2824 bg_color = vt_parser->bg_color;
2825
2826 if (flag == 0) {
2827 /* Normal */
2828 fg_color = VT_FG_COLOR;
2829 bg_color = VT_BG_COLOR;
2830 vt_parser->is_bold = 0;
2831 vt_parser->is_italic = 0;
2832 vt_parser->line_style = 0;
2833 vt_parser->is_reversed = 0;
2834 vt_parser->is_blinking = 0;
2835 vt_parser->is_invisible = 0;
2836 } else if (flag == 1) {
2837 /* Bold */
2838 vt_parser->is_bold = 1;
2839 } else if (flag == 2) {
2840 /* XXX Faint */
2841 vt_parser->is_bold = 0;
2842 } else if (flag == 3) {
2843 /* Italic */
2844 vt_parser->is_italic = 1;
2845 } else if (flag == 4) {
2846 /* Underscore */
2847 vt_parser->line_style = (vt_parser->line_style & ~LS_UNDERLINE) | LS_UNDERLINE_SINGLE;
2848 } else if (flag == 5 || flag == 6) {
2849 /* Blink (6 is repidly blinking) */
2850 vt_parser->is_blinking = 1;
2851 vt_screen_enable_blinking(vt_parser->screen);
2852 } else if (flag == 7) {
2853 /* Inverse */
2854 vt_parser->is_reversed = 1;
2855 } else if (flag == 8) {
2856 vt_parser->is_invisible = 1;
2857 } else if (flag == 9) {
2858 vt_parser->line_style |= LS_CROSSED_OUT;
2859 } else if (flag == 21) {
2860 /* Double underscore */
2861 vt_parser->line_style = (vt_parser->line_style & ~LS_UNDERLINE) | LS_UNDERLINE_DOUBLE;
2862 } else if (flag == 22) {
2863 /* Bold */
2864 vt_parser->is_bold = 0;
2865 } else if (flag == 23) {
2866 /* Italic */
2867 vt_parser->is_italic = 0;
2868 } else if (flag == 24) {
2869 /* Underline */
2870 vt_parser->line_style &= ~LS_UNDERLINE;
2871 } else if (flag == 25) {
2872 /* blink */
2873 vt_parser->is_blinking = 0;
2874 } else if (flag == 27) {
2875 vt_parser->is_reversed = 0;
2876 } else if (flag == 28) {
2877 vt_parser->is_invisible = 0;
2878 } else if (flag == 29) {
2879 vt_parser->line_style &= ~LS_CROSSED_OUT;
2880 } else if (flag == 39) {
2881 /* default fg */
2882 fg_color = VT_FG_COLOR;
2883 } else if (flag == 49) {
2884 bg_color = VT_BG_COLOR;
2885 } else if (flag == 53) {
2886 vt_parser->line_style |= LS_OVERLINE;
2887 } else if (flag == 55) {
2888 vt_parser->line_style &= ~LS_OVERLINE;
2889 } else if (vt_parser->use_ansi_colors) {
2890 /* Color attributes */
2891
2892 if (30 <= flag && flag <= 37) {
2893 /* 30=VT_BLACK(0) ... 37=VT_WHITE(7) */
2894 fg_color = flag - 30;
2895 } else if (40 <= flag && flag <= 47) {
2896 /* 40=VT_BLACK(0) ... 47=VT_WHITE(7) */
2897 bg_color = flag - 40;
2898 } else if (90 <= flag && flag <= 97) {
2899 fg_color = (flag - 90) | VT_BOLD_COLOR_MASK;
2900 } else if (100 <= flag && flag <= 107) {
2901 bg_color = (flag - 100) | VT_BOLD_COLOR_MASK;
2902 }
2903 #ifdef DEBUG
2904 else {
2905 bl_warn_printf(BL_DEBUG_TAG " unknown char attr flag(%d).\n", flag);
2906 }
2907 #endif
2908 }
2909
2910 if (fg_color != vt_parser->fg_color) {
2911 vt_parser->fg_color = fg_color;
2912 vt_screen_set_bce_fg_color(vt_parser->screen, fg_color);
2913 }
2914
2915 if (bg_color != vt_parser->bg_color) {
2916 vt_parser->bg_color = bg_color;
2917 vt_screen_set_bce_bg_color(vt_parser->screen, bg_color);
2918 }
2919 }
2920
get_rgb(vt_parser_t * vt_parser,vt_color_t color)2921 static void get_rgb(vt_parser_t *vt_parser, vt_color_t color) {
2922 u_int8_t red;
2923 u_int8_t green;
2924 u_int8_t blue;
2925 int ret;
2926
2927 if (IS_ALT_COLOR(color)) {
2928 ret = (HAS_XTERM_LISTENER(vt_parser, get_rgb) &&
2929 (*vt_parser->xterm_listener->get_rgb)(vt_parser->xterm_listener->self, &red, &green,
2930 &blue, color));
2931 color = color + 0x100 - VT_BOLD_COLOR;
2932 } else {
2933 ret = vt_get_color_rgba(color, &red, &green, &blue, NULL);
2934 }
2935
2936 if (ret) {
2937 char seq[4 + DIGIT_STR_LEN(int) + 1 + 18 + 2 + 1];
2938
2939 sprintf(seq, "\x1b]4;%d;rgb:%.2x%.2x/%.2x%.2x/%.2x%.2x\x1b\\",
2940 color, red, red, green, green, blue, blue);
2941 vt_write_to_pty(vt_parser->pty, seq, strlen(seq));
2942 }
2943 }
2944
get_fgbg_rgb(vt_parser_t * vt_parser,int ps)2945 static void get_fgbg_rgb(vt_parser_t *vt_parser, int ps /* 10, 11 */) {
2946 u_int8_t red;
2947 u_int8_t green;
2948 u_int8_t blue;
2949
2950 if (HAS_XTERM_LISTENER(vt_parser, get_rgb) &&
2951 (*vt_parser->xterm_listener->get_rgb)(vt_parser->xterm_listener->self, &red, &green,
2952 &blue, ps == 10 ? VT_FG_COLOR : VT_BG_COLOR)) {
2953 char seq[2 + DIGIT_STR_LEN(int) + 1 + 18 + 2 + 1];
2954
2955 sprintf(seq, "\x1b]%d;rgb:%.2x%.2x/%.2x%.2x/%.2x%.2x\x1b\\",
2956 ps, red, red, green, green, blue, blue);
2957
2958 vt_write_to_pty(vt_parser->pty, seq, strlen(seq));
2959 }
2960 }
2961
2962 /*
2963 * This function will destroy the content of pt.
2964 */
change_color_rgb(vt_parser_t * vt_parser,u_char * pt)2965 static void change_color_rgb(vt_parser_t *vt_parser, u_char *pt) {
2966 char *p;
2967
2968 while ((p = strchr(pt, ';'))) {
2969 char *next;
2970
2971 if ((next = strchr(p + 1, ';'))) {
2972 *(next++) = '\0';
2973 }
2974
2975 if (strcmp(p + 1, "?") == 0) {
2976 vt_color_t color;
2977
2978 *p = '\0';
2979
2980 if ((color = vt_get_color(pt)) != VT_UNKNOWN_COLOR) {
2981 get_rgb(vt_parser, color);
2982 }
2983 } else {
2984 *p = '=';
2985
2986 if ((p = alloca(6 + strlen(pt) + 1))) {
2987 sprintf(p, "color:%s", pt);
2988 config_protocol_set(vt_parser, p, 0);
2989 }
2990 }
2991
2992 if (!next) {
2993 break;
2994 }
2995
2996 pt = next;
2997 }
2998 }
2999
get_special_color_name(const char c)3000 static char *get_special_color_name(const char c /* '0' - '4' */) {
3001 if (c == '0') {
3002 return "bd_color";
3003 } else if (c == '1') {
3004 return "ul_color";
3005 } else if (c == '2') {
3006 return "bl_color";
3007 } else if (c == '3') {
3008 return "rv_color"; /* XXX Not supported for now */
3009 } else /* if (c == '4') */ {
3010 return "it_color";
3011 }
3012 }
3013
change_special_color(vt_parser_t * vt_parser,u_char * pt)3014 static void change_special_color(vt_parser_t *vt_parser, u_char *pt) {
3015 char *p;
3016
3017 while ((p = strchr(pt, ';'))) {
3018 char *next;
3019
3020 if ((next = strchr(p + 1, ';'))) {
3021 *(next++) = '\0';
3022 }
3023
3024 if ('0' <= *pt && *pt <= '4') {
3025 if (strcmp(p + 1, "?") == 0) {
3026 get_rgb(vt_parser, *pt - '0' + VT_BOLD_COLOR);
3027 } else {
3028 config_protocol_set_simple(vt_parser, get_special_color_name(*pt), p + 1, 0);
3029 }
3030 }
3031
3032 if (!next) {
3033 break;
3034 }
3035
3036 pt = next;
3037 }
3038 }
3039
change_fgbg_color(vt_parser_t * vt_parser,int ps,u_char * pt)3040 static void change_fgbg_color(vt_parser_t *vt_parser, int ps /* 10, 11 */, u_char *pt) {
3041 while (1) {
3042 char *next;
3043
3044 if ((next = strchr(pt, ';'))) {
3045 *(next++) = '\0';
3046 }
3047
3048 if (10 <= ps && ps <= 11) {
3049 if (strcmp(pt, "?") == 0) {
3050 get_fgbg_rgb(vt_parser, ps);
3051 } else {
3052 char *key;
3053
3054 if (ps == 10) {
3055 key = "fg_color";
3056 } else /* if (ps == 11) */ {
3057 key = "bg_color";
3058 }
3059
3060 config_protocol_set_simple(vt_parser, key, pt, 0);
3061 }
3062 }
3063
3064 if (!next) {
3065 break;
3066 }
3067
3068 pt = next;
3069 ps ++;
3070 }
3071 }
3072
reset_color_rgb(vt_parser_t * vt_parser,u_char * pt,int is_spcolor)3073 static void reset_color_rgb(vt_parser_t *vt_parser, u_char *pt, int is_spcolor) {
3074 u_char *p;
3075 char seq[11];
3076 int color;
3077
3078 if (*pt == '\0') {
3079 if (is_spcolor) {
3080 for (color = '0'; color <= '4'; color++) {
3081 config_protocol_set_simple(vt_parser, get_special_color_name(color), "", 0);
3082 }
3083 } else {
3084 for (color = 0; color < 256; color++) {
3085 sprintf(seq, "color:%d=", color);
3086 config_protocol_set(vt_parser, seq, 0);
3087 }
3088 }
3089 } else {
3090 while ((p = bl_str_sep(&pt, ";"))) {
3091 if (is_spcolor) {
3092 if ('0' <= *p && *p <= '4') {
3093 config_protocol_set_simple(vt_parser, get_special_color_name(*p), "", 0);
3094 }
3095 } else {
3096 color = atoi(p);
3097 sprintf(seq, "color:%d=", color);
3098 config_protocol_set(vt_parser, seq, 0);
3099 }
3100 }
3101 }
3102 }
3103
set_selection(vt_parser_t * vt_parser,u_char * encoded)3104 static void set_selection(vt_parser_t *vt_parser, u_char *encoded) {
3105 if (HAS_XTERM_LISTENER(vt_parser, set_selection)) {
3106 u_char *p;
3107 u_char *targets;
3108 size_t e_len;
3109 size_t d_len;
3110 u_char *decoded;
3111 ef_char_t ch;
3112 vt_char_t *str;
3113 u_int str_len;
3114
3115 if ((p = strchr(encoded, ';'))) {
3116 *p = '\0';
3117 targets = encoded;
3118 encoded = p + 1;
3119 } else {
3120 targets = "s0";
3121 }
3122
3123 if ((e_len = strlen(encoded)) < 4 || !(decoded = alloca(e_len)) ||
3124 (d_len = bl_base64_decode(decoded, encoded, e_len)) == 0 || !(str = vt_str_new(d_len))) {
3125 return;
3126 }
3127
3128 str_len = 0;
3129 (*vt_parser->cc_parser->set_str)(vt_parser->cc_parser, decoded, d_len);
3130 while ((*vt_parser->cc_parser->next_char)(vt_parser->cc_parser, &ch)) {
3131 vt_char_set(&str[str_len++], ef_char_to_int(&ch), ch.cs, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
3132 }
3133
3134 /*
3135 * It is assumed that screen is not redrawn not in
3136 * vt_parser->config_listener->get, so vt_parser->config_listener->get
3137 * is not held between stop_vt100_cmd and start_vt100_cmd.
3138 */
3139 #if 0
3140 stop_vt100_cmd(vt_parser, 0);
3141 #endif
3142
3143 (*vt_parser->xterm_listener->set_selection)(vt_parser->xterm_listener->self, str, str_len,
3144 targets);
3145
3146 #if 0
3147 start_vt100_cmd(vt_parser, 0);
3148 #endif
3149 }
3150 }
3151
destroy_macro(vt_parser_t * vt_parser,int id)3152 static void destroy_macro(vt_parser_t *vt_parser,
3153 int id /* should be less than vt_parser->num_macros */
3154 ) {
3155 if (vt_parser->macros[id].is_sixel) {
3156 unlink(vt_parser->macros[id].str);
3157 vt_parser->macros[id].is_sixel = 0;
3158 vt_parser->macros[id].sixel_num++;
3159 }
3160
3161 free(vt_parser->macros[id].str);
3162 vt_parser->macros[id].str = NULL;
3163 }
3164
destroy_all_macros(vt_parser_t * vt_parser)3165 static void destroy_all_macros(vt_parser_t *vt_parser) {
3166 u_int count;
3167
3168 for (count = 0; count < vt_parser->num_macros; count++) {
3169 destroy_macro(vt_parser, count);
3170 }
3171
3172 free(vt_parser->macros);
3173 vt_parser->macros = NULL;
3174 vt_parser->num_macros = 0;
3175 }
3176
hex_to_text(u_char * hex)3177 static u_char *hex_to_text(u_char *hex) {
3178 u_char *text;
3179 u_char *p;
3180 size_t len;
3181 size_t count;
3182 int rep_count;
3183 u_char *rep_beg;
3184 int d[2];
3185 int sub_count;
3186
3187 len = strlen(hex) / 2 + 1;
3188 if (!(text = malloc(len))) {
3189 return NULL;
3190 }
3191
3192 count = 0;
3193 rep_count = 1;
3194 rep_beg = NULL;
3195 sub_count = 0;
3196
3197 /* Don't use sscanf() here because it works too slow. */
3198 while (1) {
3199 if ('0' <= *hex && *hex <= '9') {
3200 d[sub_count++] = *hex - '0';
3201 } else {
3202 u_char masked_hex;
3203
3204 masked_hex = (*hex) & 0xcf;
3205 if ('A' <= masked_hex && masked_hex <= 'F') {
3206 d[sub_count++] = masked_hex - 'A' + 10;
3207 } else {
3208 sub_count = 0;
3209
3210 if (*hex == '!') {
3211 rep_beg = NULL;
3212
3213 if ((p = strchr(hex + 1, ';'))) {
3214 *p = '\0';
3215 if ((rep_count = atoi(hex + 1)) > 1) {
3216 rep_beg = text + count;
3217 }
3218 hex = p;
3219 }
3220 } else if (*hex == ';' || *hex == '\0') {
3221 if (rep_beg) {
3222 size_t rep_len;
3223
3224 if ((rep_len = text + count - rep_beg) > 0) {
3225 len += rep_len * (rep_count - 1);
3226 if (!(p = realloc(text, len))) {
3227 free(text);
3228
3229 return NULL;
3230 }
3231 rep_beg += (p - text);
3232 text = p;
3233
3234 while (--rep_count > 0) {
3235 strncpy(text + count, rep_beg, rep_len);
3236 count += rep_len;
3237 }
3238 }
3239
3240 rep_beg = NULL;
3241 }
3242
3243 if (*hex == '\0') {
3244 goto end;
3245 }
3246 }
3247 }
3248 }
3249
3250 if (sub_count == 2) {
3251 text[count++] = (d[0] << 4) + d[1];
3252 sub_count = 0;
3253 }
3254
3255 hex++;
3256 }
3257
3258 end:
3259 text[count] = '\0';
3260
3261 return text;
3262 }
3263
3264 #define MAX_NUM_OF_MACRO 1024
3265 #define MAX_DIGIT_OF_MACRO 4
3266
define_macro(vt_parser_t * vt_parser,u_char * param,u_char * data)3267 static void define_macro(vt_parser_t *vt_parser, u_char *param, u_char *data) {
3268 u_char *p;
3269 int ps[3] = {0, 0, 0};
3270 int num = 0;
3271
3272 for (p = param; *p != 'z'; p++) {
3273 if ((*p == ';' || *p == '!') && num < 3) {
3274 *p = '\0';
3275 ps[num++] = atoi(param);
3276 param = p + 1;
3277 }
3278 }
3279
3280 if (ps[0] >= MAX_NUM_OF_MACRO) {
3281 return;
3282 }
3283
3284 if (ps[1] == 1) {
3285 destroy_all_macros(vt_parser);
3286 }
3287
3288 if (ps[0] >= vt_parser->num_macros) {
3289 void *p;
3290
3291 if (*data == '\0' ||
3292 !(p = realloc(vt_parser->macros, (ps[0] + 1) * sizeof(*vt_parser->macros)))) {
3293 return;
3294 }
3295
3296 memset((vt_parser->macros = p) + vt_parser->num_macros, 0,
3297 (ps[0] + 1 - vt_parser->num_macros) * sizeof(*vt_parser->macros));
3298 vt_parser->num_macros = ps[0] + 1;
3299 } else {
3300 destroy_macro(vt_parser, ps[0]);
3301
3302 if (*data == '\0') {
3303 return;
3304 }
3305 }
3306
3307 if (ps[2] == 1) {
3308 p = vt_parser->macros[ps[0]].str = hex_to_text(data);
3309
3310 #ifndef NO_IMAGE
3311 if (p && (*p == 0x90 || (*(p++) == '\x1b' && *p == 'P'))) {
3312 for (p++; *p == ';' || ('0' <= *p && *p <= '9'); p++)
3313 ;
3314
3315 if (*p == 'q' && (strrchr(p, 0x9c) || ((p = strrchr(p, '\\')) && *(p - 1) == '\x1b'))) {
3316 char prefix[5 + MAX_DIGIT_OF_MACRO + 1 + DIGIT_STR_LEN(vt_parser->macros[0].sixel_num) +
3317 2];
3318 char *path;
3319
3320 sprintf(prefix, "macro%d_%d_", ps[0], vt_parser->macros[ps[0]].sixel_num);
3321
3322 if ((path =
3323 get_home_file_path(prefix, vt_pty_get_slave_name(vt_parser->pty) + 5, "six"))) {
3324 FILE *fp;
3325
3326 if ((fp = fopen(path, "w"))) {
3327 fwrite(vt_parser->macros[ps[0]].str, 1, strlen(vt_parser->macros[ps[0]].str), fp);
3328 fclose(fp);
3329
3330 free(vt_parser->macros[ps[0]].str);
3331 vt_parser->macros[ps[0]].str = path;
3332 vt_parser->macros[ps[0]].is_sixel = 1;
3333
3334 #ifdef DEBUG
3335 bl_debug_printf(BL_DEBUG_TAG " Register %s to macro %d\n", path, ps[0]);
3336 #endif
3337 }
3338 }
3339 }
3340 }
3341 #endif
3342 } else {
3343 vt_parser->macros[ps[0]].str = strdup(data);
3344 }
3345 }
3346
3347 static int write_loopback(vt_parser_t *vt_parser, const u_char *buf, size_t len,
3348 int enable_local_echo, int is_visual);
3349
invoke_macro(vt_parser_t * vt_parser,int id)3350 static void invoke_macro(vt_parser_t *vt_parser, int id) {
3351 if (id < vt_parser->num_macros && vt_parser->macros[id].str) {
3352 #ifndef NO_IMAGE
3353 if (vt_parser->macros[id].is_sixel) {
3354 show_picture(vt_parser, vt_parser->macros[id].str, 0, 0, 0, 0, 0, 0, 0, 3);
3355 } else
3356 #endif
3357 {
3358 write_loopback(vt_parser, vt_parser->macros[id].str,
3359 strlen(vt_parser->macros[id].str), 0, 0);
3360 }
3361 }
3362 }
3363
response_termcap(vt_pty_t * pty,u_char * key,u_char * value)3364 static int response_termcap(vt_pty_t *pty, u_char *key, u_char *value) {
3365 u_char *response;
3366
3367 if ((response = alloca(5 + strlen(key) + 1 + strlen(value) * 2 + 3))) {
3368 u_char *dst;
3369
3370 sprintf(response, "\x1bP1+r%s=", key);
3371 for (dst = response + strlen(response); *value; value++, dst += 2) {
3372 dst[0] = (value[0] >> 4) & 0xf;
3373 dst[0] = (dst[0] > 9) ? (dst[0] + 'A' - 10) : (dst[0] + '0');
3374 dst[1] = value[0] & 0xf;
3375 dst[1] = (dst[1] > 9) ? (dst[1] + 'A' - 10) : (dst[1] + '0');
3376 }
3377 strcpy(dst, "\x1b\\");
3378
3379 vt_write_to_pty(pty, response, strlen(response));
3380
3381 return 1;
3382 } else {
3383 return 0;
3384 }
3385 }
3386
3387 #define TO_INT(a) (((a) | 0x20) - ((a) <= '9' ? '0' : ('a' - 10)))
3388
report_termcap(vt_parser_t * vt_parser,u_char * key)3389 static void report_termcap(vt_parser_t *vt_parser, u_char *key) {
3390 u_char *deckey;
3391 u_char *src;
3392 u_char *dst;
3393
3394 if ((deckey = alloca(strlen(key) / 2 + 1))) {
3395 struct {
3396 u_char *tckey;
3397 u_char *tikey;
3398 int16_t spkey; /* vt_special_key_t */
3399 int16_t modcode;
3400
3401 } db[] = {
3402 {"%1", "khlp", SPKEY_F15, 0},
3403 {"#1", "kHLP", SPKEY_F15, 2},
3404 {"@0", "kfnd", SPKEY_FIND, 0},
3405 {"*0", "kFND", SPKEY_FIND, 2},
3406 {"*6", "kslt", SPKEY_SELECT, 0},
3407 {"#6", "kSLT", SPKEY_SELECT, 2},
3408
3409 {"kh", "khome", SPKEY_HOME, 0},
3410 {"#2", "kHOM", SPKEY_HOME, 2},
3411 {"@7", "kend", SPKEY_END, 0},
3412 {"*7", "kEND", SPKEY_END, 2},
3413
3414 {"kl", "kcub1", SPKEY_LEFT, 0},
3415 {"kr", "kcuf1", SPKEY_RIGHT, 0},
3416 {"ku", "kcuu1", SPKEY_UP, 0},
3417 {"kd", "kcud1", SPKEY_DOWN, 0},
3418
3419 {"#4", "kLFT", SPKEY_LEFT, 2},
3420 {"%i", "kRIT", SPKEY_RIGHT, 2},
3421 {"kF", "kind", SPKEY_DOWN, 2},
3422 {"kR", "kri", SPKEY_UP, 2},
3423
3424 {"k1", "kf1", SPKEY_F1, 0},
3425 {"k2", "kf2", SPKEY_F2, 0},
3426 {"k3", "kf3", SPKEY_F3, 0},
3427 {"k4", "kf4", SPKEY_F4, 0},
3428 {"k5", "kf5", SPKEY_F5, 0},
3429 {"k6", "kf6", SPKEY_F6, 0},
3430 {"k7", "kf7", SPKEY_F7, 0},
3431 {"k8", "kf8", SPKEY_F8, 0},
3432 {"k9", "kf9", SPKEY_F9, 0},
3433 {"k;", "kf10", SPKEY_F10, 0},
3434
3435 {"F1", "kf11", SPKEY_F11, 0},
3436 {"F2", "kf12", SPKEY_F12, 0},
3437 {"F3", "kf13", SPKEY_F13, 0},
3438 {"F4", "kf14", SPKEY_F14, 0},
3439 {"F5", "kf15", SPKEY_F15, 0},
3440 {"F6", "kf16", SPKEY_F16, 0},
3441 {"F7", "kf17", SPKEY_F17, 0},
3442 {"F8", "kf18", SPKEY_F18, 0},
3443 {"F9", "kf19", SPKEY_F19, 0},
3444 {"FA", "kf20", SPKEY_F20, 0},
3445 {"FB", "kf21", SPKEY_F21, 0},
3446 {"FC", "kf22", SPKEY_F22, 0},
3447 {"FD", "kf23", SPKEY_F23, 0},
3448 {"FE", "kf24", SPKEY_F24, 0},
3449 {"FF", "kf25", SPKEY_F25, 0},
3450 {"FG", "kf26", SPKEY_F26, 0},
3451 {"FH", "kf27", SPKEY_F27, 0},
3452 {"FI", "kf28", SPKEY_F28, 0},
3453 {"FJ", "kf29", SPKEY_F29, 0},
3454 {"FK", "kf30", SPKEY_F30, 0},
3455 {"FL", "kf31", SPKEY_F31, 0},
3456 {"FM", "kf32", SPKEY_F32, 0},
3457 {"FN", "kf33", SPKEY_F33, 0},
3458 {"FO", "kf34", SPKEY_F34, 0},
3459 {"FP", "kf35", SPKEY_F35, 0},
3460 {"FQ", "kf36", SPKEY_F36, 0},
3461 {"FR", "kf37", SPKEY_F37, 0},
3462
3463 {"K1", "ka1", SPKEY_KP_HOME, 0},
3464 {"K4", "kc1", SPKEY_KP_END, 0},
3465 {"K3", "ka3", SPKEY_KP_PRIOR, 0},
3466 {"K5", "kc3", SPKEY_KP_NEXT, 0},
3467 {"kB", "kcbt", SPKEY_ISO_LEFT_TAB, 0},
3468 /* { "kC" , "kclr" , SPKEY_CLEAR , 0 } , */
3469 {"kD", "kdch1", SPKEY_DELETE, 0},
3470 {"kI", "kich1", SPKEY_INSERT, 0},
3471
3472 {"kN", "knp", SPKEY_NEXT, 0},
3473 {"kP", "kpp", SPKEY_PRIOR, 0},
3474 {"%c", "kNXT", SPKEY_NEXT, 2},
3475 {"%e", "kPRV", SPKEY_PRIOR, 2},
3476
3477 /* { "&8" , "kund" , SPKEY_UNDO , 0 } , */
3478 {"kb", "kbs", SPKEY_BACKSPACE, 0},
3479
3480 {"Co", "colors", -1, 0},
3481 {"TN", "name", -2, 0},
3482 };
3483 int idx;
3484 u_char *value;
3485
3486 for (src = key, dst = deckey; src[0] && src[1]; src += 2) {
3487 *(dst++) = TO_INT(src[0]) * 16 + TO_INT(src[1]);
3488 }
3489 *dst = '\0';
3490
3491 value = NULL;
3492
3493 for (idx = 0; idx < sizeof(db) / sizeof(db[0]); idx++) {
3494 if (strcmp(deckey, db[idx].tckey) == 0 || strcmp(deckey, db[idx].tikey) == 0) {
3495 if (db[idx].spkey == -1) {
3496 value = "256";
3497 } else if (db[idx].spkey == -2) {
3498 value = "mlterm";
3499 } else {
3500 value = vt_termcap_special_key_to_seq(
3501 vt_parser->termcap, db[idx].spkey, db[idx].modcode,
3502 /* vt_parser->is_app_keypad */ 0, IS_APP_CURSOR_KEYS(vt_parser),
3503 /* IS_APP_ESCAPE(vt_parser) */ 0,
3504 vt_parser->modify_cursor_keys, vt_parser->modify_function_keys);
3505 }
3506
3507 break;
3508 }
3509 }
3510
3511 if (value && response_termcap(vt_parser->pty, key, value)) {
3512 return;
3513 }
3514 }
3515
3516 vt_write_to_pty(vt_parser->pty, "\x1bP0+r\x1b\\", 7);
3517 }
3518
report_char_attr_status(vt_parser_t * vt_parser)3519 static void report_char_attr_status(vt_parser_t *vt_parser) {
3520 char color[10]; /* ";38;5;XXX" (256 color) */
3521
3522 vt_write_to_pty(vt_parser->pty, "\x1bP1$r0", 6);
3523
3524 if (vt_parser->is_bold) {
3525 vt_write_to_pty(vt_parser->pty, ";1", 2);
3526 }
3527
3528 if (vt_parser->is_italic) {
3529 vt_write_to_pty(vt_parser->pty, ";3", 2);
3530 }
3531
3532 if (vt_parser->line_style & LS_UNDERLINE_SINGLE) {
3533 vt_write_to_pty(vt_parser->pty, ";4", 2);
3534 }
3535
3536 if (vt_parser->is_blinking) {
3537 vt_write_to_pty(vt_parser->pty, ";5", 2);
3538 }
3539
3540 if (vt_parser->is_reversed) {
3541 vt_write_to_pty(vt_parser->pty, ";7", 2);
3542 }
3543
3544 if (vt_parser->is_invisible) {
3545 vt_write_to_pty(vt_parser->pty, ":8", 2);
3546 }
3547
3548 if (vt_parser->line_style & LS_CROSSED_OUT) {
3549 vt_write_to_pty(vt_parser->pty, ";9", 2);
3550 }
3551
3552 if (vt_parser->line_style & LS_UNDERLINE_DOUBLE) {
3553 vt_write_to_pty(vt_parser->pty, ";21", 3);
3554 }
3555
3556 if (vt_parser->line_style & LS_OVERLINE) {
3557 vt_write_to_pty(vt_parser->pty, ":53", 3);
3558 }
3559
3560 color[0] = ';';
3561 if (IS_VTSYS_BASE_COLOR(vt_parser->fg_color)) {
3562 color[1] = '3';
3563 color[2] = '0' + vt_parser->fg_color;
3564 } else if (IS_VTSYS_COLOR(vt_parser->fg_color)) {
3565 color[1] = '9';
3566 color[2] = '0' + (vt_parser->fg_color - 8);
3567 } else if (IS_VTSYS256_COLOR(vt_parser->fg_color)) {
3568 sprintf(color + 1, "38;5;%d", vt_parser->fg_color);
3569 } else {
3570 goto bg_color;
3571 }
3572 vt_write_to_pty(vt_parser->pty, color, strlen(color));
3573
3574 bg_color:
3575 if (IS_VTSYS_BASE_COLOR(vt_parser->bg_color)) {
3576 color[1] = '4';
3577 color[2] = '0' + vt_parser->bg_color;
3578 } else if (IS_VTSYS_COLOR(vt_parser->bg_color)) {
3579 color[1] = '1';
3580 color[2] = '0';
3581 color[3] = '0' + (vt_parser->bg_color - 8);
3582 } else if (IS_VTSYS256_COLOR(vt_parser->bg_color)) {
3583 sprintf(color, ";48;5;%d", vt_parser->bg_color);
3584 } else {
3585 goto end;
3586 }
3587 vt_write_to_pty(vt_parser->pty, color, strlen(color));
3588
3589 end:
3590 vt_write_to_pty(vt_parser->pty, "m\x1b\\", 3);
3591 }
3592
report_status(vt_parser_t * vt_parser,u_char * key)3593 static void report_status(vt_parser_t *vt_parser, u_char *key) {
3594 u_char *val;
3595 u_char digits[DIGIT_STR_LEN(int)*3 + 3];
3596 u_char *seq;
3597
3598 if (strcmp(key, "\"q") == 0) {
3599 /* DECSCA */
3600 val = vt_parser->is_protected ? "1" : "0"; /* Both 0 and 2 => is_protected = 0 */
3601 } else if (strcmp(key, "\"p") == 0) {
3602 /* DECSCL */
3603 val = "63;1";
3604 } else if (strcmp(key, "r") == 0) {
3605 /* DECSTBM */
3606 val = digits;
3607 sprintf(val, "%d;%d", vt_parser->screen->edit->vmargin_beg + 1,
3608 vt_parser->screen->edit->vmargin_end + 1);
3609 } else if (strcmp(key, "s") == 0) {
3610 /* DECSLRM */
3611 val = digits;
3612 sprintf(val, "%d;%d", vt_parser->screen->edit->hmargin_beg + 1,
3613 vt_parser->screen->edit->hmargin_end + 1);
3614 } else if (strcmp(key, " q") == 0) {
3615 /* DECSCUR */
3616 char vals[] = {'2', '4', '6', '\0', '1', '3', '5'};
3617 digits[0] = vals[vt_parser->cursor_style];
3618 digits[1] = '\0';
3619 val = digits;
3620 } else if (strcmp(key, "$}") == 0) {
3621 /* DECSASD */
3622 val = vt_status_line_is_focused(vt_parser->screen) ? "1" : "0";
3623 } else if (strcmp(key, "$~") == 0) {
3624 /* DECSSDT */
3625 val = vt_screen_has_status_line(vt_parser->screen) ? "2" : "0";
3626 } else if (strcmp(key, "*x") == 0) {
3627 /* DECSACE */
3628 val = vt_screen_is_using_rect_attr_select(vt_parser->screen) ? "2" : "1";
3629 } else if (strcmp(key, "){") == 0) {
3630 /* DECSTGLT */
3631 if (vt_parser->use_ansi_colors) {
3632 val = "0";
3633 } else if (vt_parser->alt_colors.flags) {
3634 val = "1";
3635 } else {
3636 val = "2";
3637 }
3638 } else if (strcmp(key, "$|") == 0) {
3639 /* DECSCPP */
3640 val = digits;
3641 sprintf(val, "%d", vt_screen_get_logical_cols(vt_parser->screen));
3642 } else if (strcmp(key, "t") == 0 || strcmp(key, "*|") == 0) {
3643 /* DECSLPP/DECSNLS */
3644 val = digits;
3645 sprintf(val, "%d", vt_screen_get_logical_rows(vt_parser->screen));
3646 } else if (strcmp(key, "m") == 0) {
3647 /* SGR */
3648 report_char_attr_status(vt_parser);
3649 return;
3650 } else {
3651 u_int ps = atoi(key);
3652
3653 key += (strlen(key) - 2);
3654
3655 if (strcmp(key, ",|") == 0) {
3656 /* DECAC */
3657 u_int8_t red;
3658 u_int8_t green;
3659 u_int8_t blue;
3660 vt_color_t colors[] = { VT_FG_COLOR, VT_BG_COLOR } ;
3661 u_int count;
3662
3663 if (ps == 2) {
3664 /* Window Frame */
3665 goto error_validreq;
3666 }
3667
3668 vt_color_force_linear_search(1);
3669 for (count = 0; count < sizeof(colors) / sizeof(colors[0]); count++) {
3670 if (!HAS_XTERM_LISTENER(vt_parser, get_rgb) ||
3671 !(*vt_parser->xterm_listener->get_rgb)(vt_parser->xterm_listener->self, &red, &green,
3672 &blue, colors[count])) {
3673 goto error_validreq;
3674 }
3675 colors[count] = vt_get_closest_color(red, green, blue);
3676 }
3677 vt_color_force_linear_search(0);
3678
3679 val = digits;
3680 sprintf(val, "1;%d;%d", colors[0], colors[1]);
3681 } else if (strcmp(key, ",}") == 0) {
3682 /* DECATC */
3683 int idx;
3684 if (ps <= 15 && (vt_parser->alt_colors.flags & (1 << (idx = alt_color_idxs[ps])))) {
3685 val = digits;
3686 sprintf(val, "%d;%d;%d", ps, vt_parser->alt_colors.fg[idx], vt_parser->alt_colors.bg[idx]);
3687 } else {
3688 goto error_validreq;
3689 }
3690 } else {
3691 goto error_invalidreq;
3692 }
3693 }
3694
3695 /*
3696 * XXX
3697 * xterm returns 1 for vaild request while 0 for invalid request.
3698 * VT520/525 manual says 0 for vaild request while 1 for invalid request,
3699 * but it's wrong. (https://twitter.com/ttdoda/status/911125737242992645)
3700 */
3701
3702 if ((seq = alloca(7 + strlen(val) + strlen(key) + 1))) {
3703 sprintf(seq, "\x1bP1$r%s%s\x1b\\", val, key);
3704 vt_write_to_pty(vt_parser->pty, seq, strlen(seq));
3705 }
3706
3707 return;
3708
3709 error_validreq:
3710 vt_write_to_pty(vt_parser->pty, "\x1bP1$r\x1b\\", 7);
3711 return;
3712
3713 error_invalidreq:
3714 vt_write_to_pty(vt_parser->pty, "\x1bP0$r\x1b\\", 7);
3715 }
3716
clear_line_all(vt_parser_t * vt_parser)3717 static void clear_line_all(vt_parser_t *vt_parser) {
3718 vt_screen_clear_line_to_left(vt_parser->screen);
3719 vt_screen_clear_line_to_right(vt_parser->screen);
3720 }
3721
clear_display_all(vt_parser_t * vt_parser)3722 static void clear_display_all(vt_parser_t *vt_parser) {
3723 vt_screen_clear_below(vt_parser->screen);
3724 vt_screen_clear_above(vt_parser->screen);
3725 vt_screen_clear_size_attr(vt_parser->screen);
3726 }
3727
vtmode_num_to_idx(int mode)3728 static int vtmode_num_to_idx(int mode) {
3729 int idx;
3730
3731 for (idx = 0; idx < VTMODE_NUM; idx++) {
3732 if (vtmodes[idx] == mode) {
3733 return idx;
3734 }
3735 }
3736
3737 return -1;
3738 }
3739
get_vtmode(vt_parser_t * vt_parser,int mode)3740 static int get_vtmode(vt_parser_t *vt_parser, int mode) {
3741 int idx;
3742
3743 /* XXX These can be changed via OSC 5379 instead of DEC Private Mode Set. */
3744 if (mode == 8428) {
3745 return (vt_parser->col_size_of_width_a == 1) ? 1 : 2;
3746 } else if (mode == 117) {
3747 return vt_screen_is_using_bce(vt_parser->screen) ? 1 : 2;
3748 } else if (mode == VTMODE(33)) {
3749 return (vt_parser->cursor_style & CS_BLINK) ? 2 : 1;
3750 } else
3751 /* XXX DECBKM affects *all* terms sharing vt_termcap, so vtmode_flags is not reliable. */
3752 if (mode == 67) {
3753 return strcmp(vt_termcap_special_key_to_seq(vt_parser->termcap, SPKEY_BACKSPACE,
3754 0, 0, 0, 0, 0, 0), "\x08") == 0 ? 1 : 2;
3755 }
3756
3757 if ((idx = vtmode_num_to_idx(mode)) != -1) {
3758 if (GET_VTMODE_FLAG(vt_parser, idx)) {
3759 return 1; /* set */
3760 } else {
3761 return 2; /* reset */
3762 }
3763 }
3764
3765 if (mode == 8 /* DECARM (auto repeat) */ ||
3766 mode == 64 /* DECPCCM (page cursor-coupling mode) */ ||
3767 mode == 98 /* DECARSM (change lines per screen automatically by DECSLPP) */ ||
3768 mode == 102 /* DECNULM (always dicard NUL character) */ ||
3769 mode == 114 /* DECATCUM (alternate text color underline mode) */ ||
3770 mode == 115 /* DECATCBM (alternate text color blink mode) */ ||
3771 mode == 19 /* DECPEX (Ignore DECSTBM in MC and DECMC) */) {
3772 return 3; /* permanently set */
3773 } else if (mode == 4 /* DECSCLM (smooth scroll) */ || mode == 9 /* X10 mouse report */ ||
3774 mode == 38 /* Tek */ || mode == 45 /* reverse wraparound */ ||
3775 mode == 1001 /* highlight mouse tracking */ ||
3776 mode == 1011 /* scroll to bottom on key press */ ||
3777 /*
3778 * GATM, SRTM, VEM, HEM, PUM, FEAM, FETM, MATM, TTM, SATM, TSM, EBM are
3779 * permanently reset on VT510.
3780 * (https://vt100.net/docs/vt510-rm/DECRQM.html)
3781 *
3782 * ERM => http://nanno.dip.jp/softlib/man/rlogin/ctrlcode.html#ERM
3783 */
3784 mode == VTMODE(1) /* GATM */ ||
3785 (VTMODE(5) <= mode && mode <= VTMODE(7)) /* SRTM, ERM, VEM */||
3786 mode == VTMODE(10) /* HEM */ ||
3787 mode == VTMODE(11) /* PUM */ ||
3788 /* FEAM, FETM, MATM, TTM, SATM, TSM, EBM */
3789 (VTMODE(13) <= mode && mode <= VTMODE(19)) ||
3790 mode == VTMODE(18) /* ISM */) {
3791 return 4; /* permanently reset */
3792 }
3793
3794 return 0; /* not recognized */
3795 }
3796
set_vtmode(vt_parser_t * vt_parser,int mode,int flag)3797 static void set_vtmode(vt_parser_t *vt_parser, int mode, int flag) {
3798 int idx;
3799
3800 #ifdef DEBUG
3801 if (VTMODE_NUM != sizeof(vtmodes) / sizeof(vtmodes[0])) {
3802 bl_debug_printf(BL_DEBUG_TAG "vtmode table is broken.\n");
3803 }
3804 #endif
3805
3806 if ((idx = vtmode_num_to_idx(mode)) == -1) {
3807 #ifdef DEBUG
3808 debug_print_unknown("ESC [%s %d l\n", mode >= VTMODE(0) ? "" : " ?",
3809 mode >= VTMODE(0) ? mode - VTMODE(0) : mode);
3810 #endif
3811
3812 return;
3813 }
3814
3815 if (flag) {
3816 vt_parser->vtmode_flags[DIV32(idx)] |= (SHIFT_FLAG(idx));
3817 } else {
3818 vt_parser->vtmode_flags[DIV32(idx)] &= ~(SHIFT_FLAG(idx));
3819 }
3820
3821 switch (idx) {
3822 case DECMODE_1:
3823 /* DECCKM */
3824 break;
3825
3826 case DECMODE_2:
3827 #ifdef USE_VT52
3828 if (!(vt_parser->is_vt52_mode = (flag ? 0 : 1))) {
3829 /*
3830 * USASCII should be designated for G0-G3 here, but it is temporized by
3831 * using init_encoding_parser() etc for now.
3832 */
3833 init_encoding_parser(vt_parser);
3834 }
3835 #endif
3836 break;
3837
3838 case DECMODE_3:
3839 /* DECCOLM */
3840 if (ALLOW_DECCOLM(vt_parser)) {
3841 /* XTERM compatibility [#1048321] */
3842 if (!KEEP_SCREEN_ON_DECCOLM(vt_parser)) {
3843 clear_display_all(vt_parser);
3844 vt_screen_goto(vt_parser->screen, 0, 0);
3845 }
3846 resize(vt_parser, flag ? 132 : 80, -1, 1);
3847 }
3848 break;
3849
3850 #if 0
3851 case DECMODE_4:
3852 /* DECSCLM smooth scrolling */
3853 break;
3854 #endif
3855
3856 case DECMODE_5:
3857 /* DECSCNM */
3858 reverse_video(vt_parser, flag);
3859 break;
3860
3861 case DECMODE_6:
3862 /* DECOM */
3863 if (flag) {
3864 vt_screen_set_relative_origin(vt_parser->screen, 1);
3865 } else {
3866 vt_screen_set_relative_origin(vt_parser->screen, 0);
3867 }
3868
3869 /*
3870 * cursor position is reset
3871 * (the same behavior of xterm 4.0.3, kterm 6.2.0 or so)
3872 */
3873 vt_screen_goto(vt_parser->screen, 0, 0);
3874 break;
3875
3876 case DECMODE_7:
3877 /* DECAWM */
3878 vt_screen_set_auto_wrap(vt_parser->screen, flag);
3879 break;
3880
3881 #if 0
3882 case DECMODE_8:
3883 /* DECARM auto repeat */
3884 break;
3885
3886 case DECMODE_9:
3887 /* X10 mouse reporting */
3888 break;
3889
3890 case DECMODE_12:
3891 /*
3892 * XT_CBLINK
3893 * If cursor blinking is enabled, restart blinking.
3894 */
3895 break;
3896 #endif
3897
3898 case DECMODE_25:
3899 /* DECTCEM */
3900 vt_parser->is_visible_cursor = flag;
3901 break;
3902
3903 #if 0
3904 case DECMODE_35:
3905 /* shift keys */
3906 break;
3907 #endif
3908
3909 case DECMODE_40:
3910 if (flag) {
3911 /* Compatible behavior with rlogin. (Not compatible with xterm) */
3912 set_vtmode(vt_parser, 3, GET_VTMODE_FLAG2(vt_parser, DECMODE_3));
3913 }
3914 break;
3915
3916 case DECMODE_47:
3917 if (use_alt_buffer) {
3918 if (flag) {
3919 vt_screen_use_alternative_edit(vt_parser->screen);
3920 } else {
3921 vt_screen_use_normal_edit(vt_parser->screen);
3922 }
3923 }
3924 break;
3925
3926 case DECMODE_66:
3927 /* DECNKM */
3928 vt_parser->is_app_keypad = flag;
3929 break;
3930
3931 case DECMODE_67:
3932 /* DECBKM have back space */
3933 /* XXX Affects all terms sharing vt_termcap */
3934 vt_termcap_set_key_seq(vt_parser->termcap, SPKEY_BACKSPACE, flag ? "\x08" : "\x7f");
3935 break;
3936
3937 case DECMODE_69:
3938 /* DECLRMM */
3939 vt_screen_set_use_hmargin(vt_parser->screen, flag);
3940 break;
3941
3942 case DECMODE_80:
3943 /* DECSDM */
3944 vt_parser->sixel_scrolling = (flag ? 0 : 1);
3945 break;
3946
3947 case DECMODE_95:
3948 /* DECNCSM */
3949 break;
3950
3951 case DECMODE_116:
3952 /* DECBBSM */
3953 break;
3954
3955 case DECMODE_117:
3956 /* DECECM */
3957 vt_screen_set_use_bce(vt_parser->screen, (flag ? 0 : 1));
3958 break;
3959
3960 case DECMODE_1000: /* MOUSE_REPORT */
3961 case DECMODE_1002: /* BUTTON_EVENT */
3962 case DECMODE_1003: /* ANY_EVENT */
3963 set_mouse_report(vt_parser, flag ? (MOUSE_REPORT + idx - DECMODE_1000) : 0);
3964 break;
3965
3966 #if 0
3967 case DECMODE_1001:
3968 /* X11 mouse highlighting */
3969 break;
3970 #endif
3971
3972 case DECMODE_1004:
3973 vt_parser->want_focus_event = flag;
3974 break;
3975
3976 case DECMODE_1005: /* UTF8 */
3977 case DECMODE_1006: /* SGR */
3978 case DECMODE_1015: /* URXVT */
3979 if (flag) {
3980 vt_parser->ext_mouse_mode = EXTENDED_MOUSE_REPORT_UTF8 + idx - DECMODE_1005;
3981 } else {
3982 vt_parser->ext_mouse_mode = 0;
3983 }
3984 break;
3985
3986 case DECMODE_1010:
3987 /* scroll to bottom on tty output */
3988 config_protocol_set_simple(vt_parser, "exit_backscroll_by_pty", flag ? "true" : "false", 0);
3989 break;
3990
3991 #if 0
3992 case DECMODE_1011:
3993 /* scroll to bottom on key press (always enabled) */
3994 break;
3995 #endif
3996
3997 case DECMODE_1034:
3998 if (get_vtmode(vt_parser, 1036) == 2 /* reset */) {
3999 config_protocol_set_simple(vt_parser, "mod_meta_mode", flag ? "8bit" : "none", 0);
4000 }
4001 break;
4002
4003 case DECMODE_1036:
4004 config_protocol_set_simple(vt_parser, "mod_meta_mode",
4005 flag ? "esc" :
4006 (get_vtmode(vt_parser, 1034) == 1 ? "8bit" : "none"),
4007 0);
4008 break;
4009
4010 case DECMODE_1042:
4011 config_protocol_set_simple(vt_parser, "use_urgent_bell", flag ? "true" : "false", 0);
4012 break;
4013
4014 case DECMODE_1047:
4015 if (use_alt_buffer) {
4016 if (flag) {
4017 vt_screen_use_alternative_edit(vt_parser->screen);
4018 } else {
4019 if (vt_screen_is_alternative_edit(vt_parser->screen)) {
4020 clear_display_all(vt_parser);
4021 vt_screen_use_normal_edit(vt_parser->screen);
4022 }
4023 }
4024 }
4025 break;
4026
4027 case DECMODE_1048:
4028 if (use_alt_buffer) {
4029 if (flag) {
4030 save_cursor(vt_parser);
4031 } else {
4032 restore_cursor(vt_parser);
4033 }
4034 }
4035 break;
4036
4037 case DECMODE_1049:
4038 if (use_alt_buffer) {
4039 if (flag) {
4040 if (!vt_screen_is_alternative_edit(vt_parser->screen)) {
4041 save_cursor(vt_parser);
4042 vt_screen_use_alternative_edit(vt_parser->screen);
4043 clear_display_all(vt_parser);
4044 }
4045 } else {
4046 if (vt_screen_is_alternative_edit(vt_parser->screen)) {
4047 vt_screen_use_normal_edit(vt_parser->screen);
4048 restore_cursor(vt_parser);
4049 }
4050 }
4051 }
4052 break;
4053
4054 case DECMODE_2004:
4055 vt_parser->is_bracketed_paste_mode = flag;
4056 break;
4057
4058 case DECMODE_7727:
4059 break;
4060
4061 case DECMODE_8428:
4062 /* RLogin original */
4063 vt_parser->col_size_of_width_a = (flag ? 1 : 2);
4064 break;
4065
4066 case DECMODE_8452:
4067 /* RLogin original */
4068 break;
4069
4070 case DECMODE_8800:
4071 if (flag) {
4072 vt_parser->unicode_policy |= USE_UNICODE_DRCS;
4073 } else {
4074 vt_parser->unicode_policy &= ~USE_UNICODE_DRCS;
4075 }
4076 break;
4077
4078 case VTMODE_2:
4079 /* KAM */
4080 if (!HAS_XTERM_LISTENER(vt_parser, lock_keyboard)) {
4081 if (flag) {
4082 vt_parser->vtmode_flags[DIV32(VTMODE_2)] &= ~(SHIFT_FLAG(VTMODE_2)); /* unset flag */
4083 }
4084 } else {
4085 (*vt_parser->xterm_listener->lock_keyboard)(vt_parser->xterm_listener->self, flag);
4086 }
4087 break;
4088
4089 case VTMODE_4:
4090 /* IRM */
4091 if (flag) {
4092 /* insert mode */
4093 vt_parser->w_buf.output_func = vt_screen_insert_chars;
4094 } else {
4095 /* replace mode */
4096 vt_parser->w_buf.output_func = vt_screen_overwrite_chars;
4097 }
4098 break;
4099
4100 case VTMODE_12:
4101 /* SRM */
4102 break;
4103
4104 case VTMODE_20:
4105 /* LNM */
4106 break;
4107
4108 case VTMODE_33:
4109 /* WYSTCURM */
4110 if (flag) {
4111 vt_parser->cursor_style &= ~CS_BLINK;
4112 } else {
4113 vt_parser->cursor_style |= CS_BLINK;
4114 }
4115 break;
4116
4117 case VTMODE_34:
4118 /* WYULCURM */
4119 if (flag) {
4120 vt_parser->cursor_style |= CS_UNDERLINE;
4121 } else {
4122 vt_parser->cursor_style &= ~CS_UNDERLINE;
4123 }
4124 break;
4125 }
4126 }
4127
4128 /* Options configurable by ~/.mlterm/main are not reset. */
soft_reset(vt_parser_t * vt_parser)4129 static void soft_reset(vt_parser_t *vt_parser) {
4130 /*
4131 * XXX
4132 * Following options is not reset for now.
4133 * DECNRCM, DECAUPSS, DECKPM, DECRLM, DECPCTERM
4134 * (see https://vt100.net/docs/vt510-rm/DECSTR.html)
4135 */
4136
4137 /* "CSI m" (SGR) */
4138 change_char_attr(vt_parser, 0);
4139
4140 init_encoding_parser(vt_parser);
4141
4142 /* DECSC */
4143 (vt_screen_is_alternative_edit(vt_parser->screen) ? &vt_parser->saved_alternate
4144 : &vt_parser->saved_normal)->is_saved = 0;
4145
4146 /* DECSCA */
4147 vt_parser->is_protected = 0;
4148
4149 /* CSI < r, CSI < s, CSI < t (compatible with TeraTerm) */
4150 vt_parser->im_is_active = 0;
4151
4152 set_vtmode(vt_parser, 1, 0); /* DECCKM */
4153 /* auto_wrap == 1 (compatible with xterm, not with VT220) */
4154 set_vtmode(vt_parser, 7, 1); /* DECAWM */
4155 set_vtmode(vt_parser, 25, 1); /* DECTCEM */
4156 set_vtmode(vt_parser, 66, 0); /* DECNKM */
4157 set_vtmode(vt_parser, 1000, 0); /* compatible with xterm */
4158 set_vtmode(vt_parser, 1002, 0); /* compatible with xterm */
4159 set_vtmode(vt_parser, 1003, 0); /* compatible with xterm */
4160 set_vtmode(vt_parser, 1005, 0); /* compatible with xterm */
4161 set_vtmode(vt_parser, 1006, 0); /* compatible with xterm */
4162 set_vtmode(vt_parser, 1015, 0); /* compatible with xterm */
4163 set_vtmode(vt_parser, 2004, 0); /* compatible with xterm */
4164 set_vtmode(vt_parser, 7727, 0); /* compatible with xterm */
4165 set_vtmode(vt_parser, VTMODE(2), 0); /* KAM */
4166 set_vtmode(vt_parser, VTMODE(4), 0); /* IRM */
4167
4168 /* DECOM */
4169 #if 0
4170 set_vtmode(vt_parser, 6, 0);
4171 #else
4172 vt_screen_set_relative_origin(vt_parser->screen, 0);
4173 vt_parser->vtmode_flags[DIV32(DECMODE_6)] &= ~(SHIFT_FLAG(DECMODE_6));
4174 #endif
4175
4176 /*
4177 * DECSLRM is reset but DECLRMM is as it is.
4178 * (Compatible with xterm, not described in vt510 manual.)
4179 */
4180 vt_screen_set_hmargin(vt_parser->screen, -1, -1);
4181
4182 /* "CSI r" (DECSTBM) */
4183 vt_screen_set_vmargin(vt_parser->screen, -1, -1);
4184
4185 /* DECSC => Home position */
4186 vt_screen_saved_cursor_to_home(vt_parser->screen);
4187
4188 /* DECSASD */
4189 vt_focus_main_screen(vt_parser->screen);
4190 }
4191
full_reset(vt_parser_t * vt_parser)4192 static void full_reset(vt_parser_t *vt_parser) {
4193 vt_screen_use_normal_edit(vt_parser->screen);
4194 vt_screen_goto_page(vt_parser->screen, 0);
4195 set_vtmode(vt_parser, 3, 0); /* DECCOLM */
4196 soft_reset(vt_parser); /* XXX insufficient */
4197 vt_screen_goto(vt_parser->screen, 0, 0);
4198 vt_screen_set_tab_size(vt_parser->screen, 8);
4199 clear_display_all(vt_parser); /* XXX off-screen pages are not cleared */
4200 destroy_all_macros(vt_parser);
4201 destroy_drcs(vt_parser->drcs);
4202
4203 /* Compatible with xterm (CSI > T / CSI > t) */
4204 vt_parser->set_title_using_hex = vt_parser->get_title_using_hex =
4205 vt_parser->set_title_using_utf8 = vt_parser->get_title_using_utf8 = 0;
4206 }
4207
send_device_status(vt_parser_t * vt_parser,int num,int id)4208 static void send_device_status(vt_parser_t *vt_parser, int num, int id) {
4209 char *seq;
4210 char amb[] = "\x1b[?884Xn";
4211
4212 if (num == 6) {
4213 /* XCPR */
4214 if ((seq = alloca(6 + DIGIT_STR_LEN(int)+1))) {
4215 sprintf(seq, "\x1b[?%d;%d;%dR", vt_screen_cursor_logical_row(vt_parser->screen) + 1,
4216 vt_screen_cursor_logical_col(vt_parser->screen) + 1,
4217 vt_screen_get_page_id(vt_parser->screen) + 1);
4218 } else {
4219 return;
4220 }
4221 } else if (num == 15) {
4222 seq = "\x1b[?13n"; /* No printer */
4223 } else if (num == 25) {
4224 seq = "\x1b[?21n"; /* UDKs are locked */
4225 } else if (num == 26) {
4226 seq = "\x1b[?27;1;0;0n"; /* North American, Keyboard ready */
4227 } else if (num == 53 || num == 55) {
4228 seq = "\x1b[?50n"; /* Locator ready */
4229 } else if (num == 56) {
4230 seq = "\x1b[?57;1n"; /* Locator exists */
4231 } else if (num == 62) {
4232 seq = "\x1b[0*{"; /* Macro Space (Pn = [num of bytes] / 16 (rounded down) */
4233 } else if (num == 63) {
4234 /* checksum = 0 */
4235 if ((seq = alloca(10+DIGIT_STR_LEN(int)+1))) {
4236 sprintf(seq, "\x1bP%d!~0000\x1b\\", id);
4237 } else {
4238 seq = "\x1bP0!~0000\x1b\\";
4239 }
4240 } else if (num == 75) {
4241 seq = "\x1b[?70n"; /* Ready */
4242 } else if (num == 85) {
4243 seq = "\x1b[?83n"; /* Not multiple-session */
4244 } else if (num == 8840) {
4245 /* "CSI ? 8840 n" (TNREPTAMB) */
4246
4247 amb[6] = vt_parser->col_size_of_width_a + 0x30;
4248 seq = amb;
4249 } else {
4250 return;
4251 }
4252
4253 vt_write_to_pty(vt_parser->pty, seq, strlen(seq));
4254 }
4255
send_device_attributes(vt_pty_t * pty,int rank)4256 static void send_device_attributes(vt_pty_t *pty, int rank) {
4257 char *seq;
4258
4259 if (rank == 1) {
4260 if (primary_da && (seq = alloca(4 + strlen(primary_da) + 1))) {
4261 sprintf(seq, "\x1b[?%sc", primary_da);
4262 } else {
4263 /*
4264 * 1 132-columns
4265 * 2 Printer
4266 * 3 ReGIS graphics
4267 * 4 Sixel graphics
4268 * 6 Selective erase
4269 * 7 Soft character set (DRCS)
4270 * 15 Technical character set
4271 * 18 Windowing capability
4272 * 22 Color
4273 * 29 ANSI text locator (i.e., DEC Locator mode)
4274 */
4275 #ifndef NO_IMAGE
4276 seq = "\x1b[?63;1;2;3;4;6;7;15;18;22;29c";
4277 #else
4278 seq = "\x1b[?63;1;2;6;7;15;18;22;29c";
4279 #endif
4280 }
4281 } else if (rank == 2) {
4282 if (secondary_da && (seq = alloca(4 + strlen(secondary_da) + 1))) {
4283 sprintf(seq, "\x1b[>%sc", secondary_da);
4284 } else {
4285 /*
4286 * >=96: vim sets ttymouse=xterm2
4287 * >=141: vim uses tcap-query.
4288 * >=277: vim uses sgr mouse tracking.
4289 * >=279: xterm supports DECSLRM/DECLRMM.
4290 */
4291 seq = "\x1b[>24;279;0c";
4292 }
4293 } else if (rank == 3) {
4294 seq = "\x1bP!|000000\x1b\\";
4295 } else {
4296 return;
4297 }
4298
4299 vt_write_to_pty(pty, seq, strlen(seq));
4300 }
4301
send_display_extent(vt_pty_t * pty,u_int cols,u_int rows,int vmargin,int hmargin,int page)4302 static void send_display_extent(vt_pty_t *pty, u_int cols, u_int rows, int vmargin,
4303 int hmargin, int page) {
4304 char seq[DIGIT_STR_LEN(int) * 5 + 1];
4305
4306 sprintf(seq, "\x1b[%d;%d;%d;%d;%d\"w", rows, cols, hmargin, vmargin, page);
4307
4308 vt_write_to_pty(pty, seq, strlen(seq));
4309 }
4310
set_use_status_line(vt_parser_t * vt_parser,int ps)4311 static void set_use_status_line(vt_parser_t *vt_parser, int ps) {
4312 u_int width;
4313 u_int height;
4314
4315 if (ps <= 1) {
4316 vt_screen_set_use_status_line(vt_parser->screen, 0);
4317 } else if (ps == 2) {
4318 vt_screen_set_use_status_line(vt_parser->screen, 1);
4319 } else {
4320 return;
4321 }
4322
4323 if (!HAS_XTERM_LISTENER(vt_parser, get_window_size)) {
4324 width = height = 0;
4325 } else {
4326 (*vt_parser->xterm_listener->get_window_size)(vt_parser->xterm_listener->self,
4327 &width, &height);
4328 }
4329
4330 vt_set_pty_winsize(vt_parser->pty, vt_screen_get_logical_cols(vt_parser->screen),
4331 vt_screen_get_logical_rows(vt_parser->screen), width, height);
4332 }
4333
4334 /*
4335 * For string outside escape sequences.
4336 */
increment_str(u_char ** str,size_t * left)4337 static int increment_str(u_char **str, size_t *left) {
4338 if (--(*left) == 0) {
4339 return 0;
4340 }
4341
4342 (*str)++;
4343
4344 return 1;
4345 }
4346
4347 /*
4348 * For string inside escape sequences.
4349 */
inc_str_in_esc_seq(vt_screen_t * screen,u_char ** str_p,size_t * left,int want_ctrl)4350 static int inc_str_in_esc_seq(vt_screen_t *screen, u_char **str_p, size_t *left, int want_ctrl) {
4351 while (1) {
4352 if (increment_str(str_p, left) == 0) {
4353 return 0;
4354 }
4355
4356 if (**str_p < 0x20 || 0x7e < **str_p) {
4357 /*
4358 * cursor-control characters inside ESC sequences
4359 */
4360 if (CTL_LF <= **str_p && **str_p <= CTL_FF) {
4361 vt_screen_line_feed(screen);
4362 /* XXX AUTO_CR(vt_parser) is ignored for now. */
4363 } else if (**str_p == CTL_CR) {
4364 vt_screen_goto_beg_of_line(screen);
4365 } else if (**str_p == CTL_BS) {
4366 vt_screen_go_back(screen, 1, 0);
4367 } else if (want_ctrl) {
4368 return 1;
4369 } else {
4370 #ifdef DEBUG
4371 bl_warn_printf(BL_DEBUG_TAG " Ignored 0x%x inside escape sequences.\n", **str_p);
4372 #endif
4373 }
4374 } else {
4375 return 1;
4376 }
4377 }
4378 }
4379
4380 /*
4381 * Set use_c1=0 for 0x9c not to be regarded as ST if str can be encoded by utf8.
4382 * (UTF-8 uses 0x80-0x9f as printable characters.)
4383 */
get_pt_in_esc_seq(u_char ** str,size_t * left,int use_c1,int bel_terminate)4384 static char *get_pt_in_esc_seq(
4385 u_char **str, size_t *left,
4386 int use_c1, /* OSC is terminated by not only ST(ESC \) but also 0x9c. */
4387 int bel_terminate /* OSC is terminated by not only ST(ESC \) but also BEL. */
4388 ) {
4389 u_char *pt;
4390
4391 pt = *str;
4392
4393 while (1) {
4394 if ((bel_terminate && **str == CTL_BEL) || (use_c1 && **str == 0x9c)) {
4395 **str = '\0';
4396
4397 break;
4398 }
4399
4400 if (**str == CTL_ESC) {
4401 if (!increment_str(str, left)) {
4402 return NULL;
4403 }
4404
4405 if (**str == '\\') {
4406 *((*str) - 1) = '\0';
4407
4408 break;
4409 }
4410
4411 /*
4412 * Reset position ahead of unprintable character for compat with xterm.
4413 * e.g.) "\x1bP\x1b[A" is parsed as "\x1b[A"
4414 */
4415 (*str) -= 2;
4416 (*left) += 2;
4417
4418 return NULL;
4419 }
4420
4421 if (!increment_str(str, left)) {
4422 return NULL;
4423 }
4424 }
4425
4426 return pt;
4427 }
4428
4429 #ifdef USE_VT52
parse_vt52_escape_sequence(vt_parser_t * vt_parser)4430 inline static int parse_vt52_escape_sequence(
4431 vt_parser_t *vt_parser /* vt_parser->r_buf.left must be more than 0 */
4432 ) {
4433 u_char *str_p;
4434 size_t left;
4435
4436 str_p = CURRENT_STR_P(vt_parser);
4437 left = vt_parser->r_buf.left;
4438
4439 if (!inc_str_in_esc_seq(vt_parser->screen, &str_p, &left, 0)) {
4440 return 0;
4441 }
4442
4443 if (*str_p == 'A') {
4444 vt_screen_go_upward(vt_parser->screen, 1);
4445 } else if (*str_p == 'B') {
4446 vt_screen_go_downward(vt_parser->screen, 1);
4447 } else if (*str_p == 'C') {
4448 vt_screen_go_forward(vt_parser->screen, 1, 0);
4449 } else if (*str_p == 'D') {
4450 vt_screen_go_back(vt_parser->screen, 1, 0);
4451 } else if (*str_p == 'F') {
4452 /* Enter graphics mode */
4453 } else if (*str_p == 'G') {
4454 /* Exit graphics mode */
4455 } else if (*str_p == 'H') {
4456 vt_screen_goto(vt_parser->screen, 0, 0);
4457 } else if (*str_p == 'I') {
4458 if (vt_screen_cursor_logical_row(vt_parser->screen) == 0) {
4459 vt_screen_scroll_downward(vt_parser->screen, 1);
4460 } else {
4461 vt_screen_go_upward(vt_parser->screen, 1);
4462 }
4463 } else if (*str_p == 'J') {
4464 vt_screen_clear_below(vt_parser->screen);
4465 } else if (*str_p == 'K') {
4466 vt_screen_clear_line_to_right(vt_parser->screen);
4467 } else if (*str_p == 'Y') {
4468 int row;
4469 int col;
4470
4471 if (!inc_str_in_esc_seq(vt_parser->screen, &str_p, &left, 0)) {
4472 return 0;
4473 }
4474
4475 if (*str_p < ' ') {
4476 goto end;
4477 }
4478
4479 row = *str_p - ' ';
4480
4481 if (!inc_str_in_esc_seq(vt_parser->screen, &str_p, &left, 0)) {
4482 return 0;
4483 }
4484
4485 if (*str_p < ' ') {
4486 goto end;
4487 }
4488
4489 col = *str_p - ' ';
4490
4491 vt_screen_goto(vt_parser->screen, col, row);
4492 } else if (*str_p == 'Z') {
4493 char msg[] = "\x1b/Z";
4494
4495 vt_write_to_pty(vt_parser->pty, msg, sizeof(msg) - 1);
4496 } else if (*str_p == '=') {
4497 /* Enter altenate keypad mode */
4498 } else if (*str_p == '>') {
4499 /* Exit altenate keypad mode */
4500 } else if (*str_p == '<') {
4501 vt_parser->is_vt52_mode = 0;
4502 } else {
4503 /* not VT52 control sequence */
4504
4505 return 1;
4506 }
4507
4508 end:
4509 vt_parser->r_buf.left = left - 1;
4510
4511 return 1;
4512 }
4513 #endif
4514
4515 /*
4516 * Parse escape/control sequence. Note that *any* valid format sequence
4517 * is parsed even if mlterm doesn't support it.
4518 *
4519 * Return value:
4520 * 0 => vt_parser->r_buf.left == 0
4521 * 1 => Finished parsing. (If current vt_parser->r_buf.chars is not escape
4522 *sequence,
4523 * return without doing anthing.)
4524 */
parse_vt100_escape_sequence(vt_parser_t * vt_parser)4525 inline static int parse_vt100_escape_sequence(
4526 vt_parser_t *vt_parser /* vt_parser->r_buf.left must be more than 0 */
4527 ) {
4528 u_char *str_p;
4529 size_t left;
4530
4531 #if 0
4532 if (vt_parser->r_buf.left == 0) {
4533 /* end of string */
4534
4535 return 1;
4536 }
4537 #endif
4538
4539 str_p = CURRENT_STR_P(vt_parser);
4540 left = vt_parser->r_buf.left;
4541
4542 if (*str_p == CTL_ESC) {
4543 #ifdef ESCSEQ_DEBUG
4544 bl_msg_printf("RECEIVED ESCAPE SEQUENCE(current left = %d: ESC", left);
4545 #endif
4546
4547 #ifdef USE_VT52
4548 if (vt_parser->is_vt52_mode) {
4549 return parse_vt52_escape_sequence(vt_parser);
4550 }
4551 #endif
4552
4553 if (!inc_str_in_esc_seq(vt_parser->screen, &str_p, &left, 0)) {
4554 return 0;
4555 }
4556
4557 if (*str_p == '2') {
4558 /* "ESC 2" DECCAHT */
4559 vt_screen_clear_all_tab_stops(vt_parser->screen);
4560 } else if (*str_p == '6') {
4561 /* "ESC 6" DECBI */
4562
4563 vt_screen_go_back(vt_parser->screen, 1, 1);
4564 } else if (*str_p == '7') {
4565 /* "ESC 7" save cursor (DECSC) */
4566
4567 save_cursor(vt_parser);
4568 } else if (*str_p == '8') {
4569 /* "ESC 8" restore cursor (DECRC) */
4570
4571 restore_cursor(vt_parser);
4572 } else if (*str_p == '9') {
4573 /* "ESC 9" DECFI */
4574
4575 vt_screen_go_forward(vt_parser->screen, 1, 1);
4576 } else if (*str_p == '=') {
4577 /* "ESC =" application keypad (DECKPAM) */
4578
4579 vt_parser->is_app_keypad = 1;
4580 } else if (*str_p == '>') {
4581 /* "ESC >" normal keypad (DECKPNM) */
4582
4583 vt_parser->is_app_keypad = 0;
4584 } else if (*str_p == 'D') {
4585 /* "ESC D" index(scroll up) (IND) */
4586
4587 vt_screen_index(vt_parser->screen);
4588 } else if (*str_p == 'E') {
4589 /* "ESC E" next line (NEL) */
4590
4591 vt_screen_line_feed(vt_parser->screen);
4592 vt_screen_goto_beg_of_line(vt_parser->screen);
4593 }
4594 #if 0
4595 else if (*str_p == 'F') {
4596 /* "ESC F" cursor to lower left corner of screen */
4597 }
4598 #endif
4599 else if (*str_p == 'H' || *str_p == '1') {
4600 /* "ESC H" (HTS) / "ESC 1" (DECHTS) set tab */
4601
4602 vt_screen_set_tab_stop(vt_parser->screen);
4603 } else if (*str_p == 'I') {
4604 /* "ESC I" (HTJ) */
4605 vt_screen_forward_tabs(vt_parser->screen, 1);
4606 }
4607 #if 0
4608 else if (*str_p == 'K') {
4609 /* "ESC K" (PLD) Partial Line Down */
4610 } else if (*str_p == 'L') {
4611 /* "ESC L" (PLU) Partial Line Up */
4612 }
4613 #endif
4614 else if (*str_p == 'M') {
4615 /* "ESC M" reverse index(scroll down) */
4616
4617 vt_screen_reverse_index(vt_parser->screen);
4618 } else if (*str_p == 'Z') {
4619 /* "ESC Z" return terminal id (Obsolete form of CSI c) */
4620
4621 send_device_attributes(vt_parser->pty, 1);
4622 } else if (*str_p == 'c') {
4623 /* "ESC c" full reset (RIS) */
4624
4625 full_reset(vt_parser);
4626 }
4627 #if 0
4628 else if (*str_p == 'l') {
4629 /* "ESC l" memory lock */
4630 }
4631 #endif
4632 #if 0
4633 else if (*str_p == 'm') {
4634 /* "ESC m" memory unlock */
4635 }
4636 #endif
4637 else if (*str_p == '[') {
4638 /*
4639 * "ESC [" (CSI)
4640 * CSI P.....P I.....I F
4641 * 060-077 040-057 100-176
4642 */
4643
4644 #define MAX_NUM_OF_PS 10
4645
4646 u_char para_ch = '\0';
4647 u_char intmed_ch = '\0';
4648 int ps[MAX_NUM_OF_PS];
4649 int num;
4650
4651 num = 0;
4652 while (1) {
4653 if (!inc_str_in_esc_seq(vt_parser->screen, &str_p, &left, 0)) {
4654 return 0;
4655 }
4656
4657 if (*str_p == ';') {
4658 /*
4659 * "CSI ; n" is regarded as "CSI -1 ; n"
4660 */
4661 if (num < MAX_NUM_OF_PS) {
4662 ps[num++] = -1;
4663 }
4664 } else if (0x3c <= *str_p && *str_p <= 0x3f) {
4665 /* parameter character except numeric, ':' and ';' (< = > ?). */
4666 if (para_ch == '\0') {
4667 para_ch = *str_p;
4668 }
4669 } else {
4670 if ('0' <= *str_p && *str_p <= '9') {
4671 u_char digit[DIGIT_STR_LEN(int)+1];
4672 int count;
4673
4674 if (*str_p == '0') {
4675 /* 000000001 -> 01 */
4676 while (left > 1 && *(str_p + 1) == '0') {
4677 str_p++;
4678 left--;
4679 }
4680 }
4681
4682 digit[0] = *str_p;
4683
4684 for (count = 1; count < DIGIT_STR_LEN(int); count++) {
4685 if (!inc_str_in_esc_seq(vt_parser->screen, &str_p, &left, 0)) {
4686 return 0;
4687 }
4688
4689 if (*str_p < '0' || '9' < *str_p) {
4690 break;
4691 }
4692
4693 digit[count] = *str_p;
4694 }
4695
4696 digit[count] = '\0';
4697 if (num < MAX_NUM_OF_PS) {
4698 ps[num++] = atoi(digit);
4699 #ifdef MAX_PS_DIGIT
4700 if (ps[num - 1] > MAX_PS_DIGIT) {
4701 ps[num - 1] = MAX_PS_DIGIT;
4702 }
4703 #endif
4704 }
4705 }
4706
4707 if (*str_p < 0x30 || 0x3f < *str_p) {
4708 /* Is not a parameter character(0x30-0x3f). */
4709
4710 /*
4711 * "CSI 0 n" is *not* regarded as "CSI 0 ; -1 n"
4712 * "CSI n" is regarded as "CSI -1 n"
4713 * "CSI 0 ; n" is regarded as "CSI 0 ; -1 n"
4714 * "CSI ; n" which has been already regarded as
4715 * "CSI -1 ; n" is regarded as "CSI -1 ; -1 n"
4716 */
4717 if (num == 0 || (*(str_p - 1) == ';' && num < MAX_NUM_OF_PS)) {
4718 ps[num++] = -1;
4719 }
4720
4721 /* num is always greater than 0 */
4722
4723 break;
4724 }
4725 }
4726 }
4727
4728 /*
4729 * Intermediate(0x20-0x2f) characters.
4730 * (Unexpected paremeter(0x30-0x3f) characters are also ignored.)
4731 */
4732 while (0x20 <= *str_p && *str_p <= 0x3f) {
4733 if (*str_p <= 0x2f && intmed_ch == '\0') {
4734 intmed_ch = *str_p;
4735 }
4736
4737 if (!inc_str_in_esc_seq(vt_parser->screen, &str_p, &left, 0)) {
4738 return 0;
4739 }
4740 }
4741
4742 if (para_ch == '?') {
4743 if (intmed_ch == '$') {
4744 if (*str_p == 'p' && num > 0) {
4745 /* "CSI ? $ p" DECRQM */
4746
4747 char seq[3 + DIGIT_STR_LEN(u_int) + 5];
4748 sprintf(seq, "\x1b[?%d;%d$y", ps[0],
4749 (ps[0] >= VTMODE(0)) ? 0 : get_vtmode(vt_parser, ps[0]));
4750 vt_write_to_pty(vt_parser->pty, seq, strlen(seq));
4751 }
4752 } else if (*str_p == 'h') {
4753 /* "CSI ? h" DEC Private Mode Set (DECSET) */
4754 int count;
4755
4756 for (count = 0; count < num; count++) {
4757 if (ps[count] < VTMODE(0)) {
4758 set_vtmode(vt_parser, ps[count], 1);
4759 }
4760 }
4761 } else if (*str_p == 'i') {
4762 /* "CSI ? i" (DECMC) */
4763
4764 if (ps[0] <= 0 || ps[0] == 10) {
4765 snapshot(vt_parser, VT_UTF8, vt_pty_get_slave_name(vt_parser->pty) + 5 /* skip /dev/ */,
4766 WCA_SCREEN);
4767 } else if (ps[0] == 1) {
4768 snapshot(vt_parser, VT_UTF8, vt_pty_get_slave_name(vt_parser->pty) + 5 /* skip /dev/ */,
4769 WCA_CURSOR_LINE);
4770 } else if (ps[0] == 11) {
4771 snapshot(vt_parser, VT_UTF8, vt_pty_get_slave_name(vt_parser->pty) + 5 /* skip /dev/ */,
4772 WCA_ALL);
4773 }
4774 } else if (*str_p == 'l') {
4775 /* "CSI ? l" DEC Private Mode Reset (DECRST) */
4776 int count;
4777
4778 for (count = 0; count < num; count++) {
4779 if (ps[count] < VTMODE(0)) {
4780 set_vtmode(vt_parser, ps[count], 0);
4781 }
4782 }
4783 } else if (*str_p == 'r') {
4784 /* "CSI ? r" Restore DEC Private Mode (xterm) */
4785 int count;
4786
4787 for (count = 0; count < num; count++) {
4788 if (ps[count] < VTMODE(0)) {
4789 int idx;
4790 if ((idx = vtmode_num_to_idx(ps[count])) != -1) {
4791 set_vtmode(vt_parser, ps[count], GET_SAVED_VTMODE_FLAG2(vt_parser, idx));
4792 }
4793 }
4794 }
4795 } else if (*str_p == 's') {
4796 /* "CSI ? s" Save DEC Private Mode (xterm) */
4797 int count;
4798
4799 for (count = 0; count < num; count++) {
4800 if (ps[count] < VTMODE(0)) {
4801 int idx;
4802 if ((idx = vtmode_num_to_idx(ps[count])) != -1) {
4803 if (GET_VTMODE_FLAG(vt_parser, idx)) {
4804 vt_parser->saved_vtmode_flags[DIV32(idx)] |= (SHIFT_FLAG(idx));
4805 } else {
4806 vt_parser->saved_vtmode_flags[DIV32(idx)] &= ~(SHIFT_FLAG(idx));
4807 }
4808 }
4809 }
4810 }
4811 } else if (*str_p == 'n') {
4812 /* "CSI ? n" Device Status Report (DSR) */
4813
4814 send_device_status(vt_parser, ps[0], num == 2 ? ps[1] : 0);
4815 } else if (*str_p == 'J') {
4816 /* "CSI ? J" DECSED (Selective Erase Display) */
4817 vt_protect_store_t *save;
4818
4819 if (ps[0] <= 0) {
4820 save = vt_screen_save_protected_chars(vt_parser->screen,
4821 -1 /* cursor row */,
4822 vt_screen_get_logical_rows(vt_parser->screen) - 1,
4823 0);
4824 vt_screen_clear_below(vt_parser->screen);
4825 vt_screen_restore_protected_chars(vt_parser->screen, save);
4826 } else if (ps[0] == 1) {
4827 save = vt_screen_save_protected_chars(vt_parser->screen, 0,
4828 -1 /* cursor row */, 0);
4829 vt_screen_clear_above(vt_parser->screen);
4830 vt_screen_restore_protected_chars(vt_parser->screen, save);
4831 } else if (ps[0] == 2) {
4832 save = vt_screen_save_protected_chars(vt_parser->screen, 0,
4833 vt_screen_get_logical_rows(vt_parser->screen) - 1,
4834 0);
4835 clear_display_all(vt_parser);
4836 vt_screen_restore_protected_chars(vt_parser->screen, save);
4837 }
4838 } else if (*str_p == 'K') {
4839 /* "CSI ? K" DECSEL (Selective Erase Line) */
4840 vt_protect_store_t *save;
4841
4842 save = vt_screen_save_protected_chars(vt_parser->screen,
4843 -1 /* cursor row */,
4844 -1 /* cursor row */, 0);
4845 if (ps[0] <= 0) {
4846 vt_screen_clear_line_to_right(vt_parser->screen);
4847 } else if (ps[0] == 1) {
4848 vt_screen_clear_line_to_left(vt_parser->screen);
4849 } else if (ps[0] == 2) {
4850 clear_line_all(vt_parser);
4851 }
4852 vt_screen_restore_protected_chars(vt_parser->screen, save);
4853 } else if (*str_p == 'S') {
4854 /*
4855 * "CSI ? Pi;Pa;Pv S" (Xterm original)
4856 * The number of palettes mlterm supports is 1024 alone.
4857 */
4858 char *seq;
4859
4860 if (num == 3 && ps[0] == 1 &&
4861 (ps[1] == 1 /* read */ || ps[1] == 2 /* reset to default */ ||
4862 ps[1] == 3 /* set (ps[2] is ignored) */ ||
4863 ps[1] == 4 /* read the max allowd value */)) {
4864 seq = "\x1b[?1;0;1024S";
4865 } else {
4866 seq = "\x1b[?1;3;0S";
4867 }
4868 vt_write_to_pty(vt_parser->pty, seq, strlen(seq));
4869 } else if (*str_p == 'W') {
4870 /* "CSI ? W" DECST8C */
4871
4872 vt_screen_set_tab_size(vt_parser->screen, 8);
4873 }
4874 #if 0
4875 else if (*str_p == 'r') {
4876 /* "CSI ? r" Restore DEC Private Mode */
4877 }
4878 #endif
4879 #if 0
4880 else if (*str_p == 's') {
4881 /* "CSI ? s" Save DEC Private Mode */
4882 }
4883 #endif
4884 /* Other final character */
4885 else if (0x40 <= *str_p && *str_p <= 0x7e) {
4886 #ifdef DEBUG
4887 debug_print_unknown("ESC [ ? %c\n", *str_p);
4888 #endif
4889 } else {
4890 /* not VT100 control sequence. */
4891
4892 #ifdef ESCSEQ_DEBUG
4893 bl_msg_printf("=> not VT100 control sequence.\n");
4894 #endif
4895
4896 return 1;
4897 }
4898 } else if (para_ch == '<') {
4899 /* Teraterm compatible IME control sequence */
4900
4901 if (*str_p == 'r') {
4902 /* Restore IME state */
4903 if (vt_parser->im_is_active != im_is_active(vt_parser)) {
4904 switch_im_mode(vt_parser);
4905 }
4906 } else if (*str_p == 's') {
4907 /* Save IME state */
4908
4909 vt_parser->im_is_active = im_is_active(vt_parser);
4910 } else if (*str_p == 't') {
4911 /* ps[0] = 0 (Close), ps[0] = 1 (Open) */
4912
4913 if (ps[0] != im_is_active(vt_parser)) {
4914 switch_im_mode(vt_parser);
4915 }
4916 }
4917 } else if (para_ch == '>') {
4918 if (*str_p == 'c') {
4919 /* "CSI > c" Secondary DA (DA2) */
4920
4921 send_device_attributes(vt_parser->pty, 2);
4922 } else if (*str_p == 'm') {
4923 /* "CSI > m" */
4924
4925 if (ps[0] == -1) {
4926 /* reset to initial value. */
4927 set_modkey_mode(vt_parser, 1, 2);
4928 set_modkey_mode(vt_parser, 2, 2);
4929 set_modkey_mode(vt_parser, 4, 0);
4930 } else {
4931 if (num == 1 || ps[1] == -1) {
4932 if (ps[0] == 1 || /* modifyCursorKeys */
4933 ps[0] == 2) /* modifyFunctionKeys */
4934 {
4935 /* The default is 2. */
4936 ps[1] = 2;
4937 } else /* if( ps[0] == 4) */
4938 {
4939 /*
4940 * modifyOtherKeys
4941 * The default is 0.
4942 */
4943 ps[1] = 0;
4944 }
4945 }
4946
4947 set_modkey_mode(vt_parser, ps[0], ps[1]);
4948 }
4949 } else if (*str_p == 'n') {
4950 /* "CSI > n" */
4951
4952 if (num == 1) {
4953 if (ps[0] == -1) {
4954 ps[0] = 2;
4955 }
4956
4957 /* -1: don't send modifier key code. */
4958 set_modkey_mode(vt_parser, ps[0], -1);
4959 }
4960 } else if (*str_p == 'p') {
4961 /* "CSI > p" pointer mode */
4962
4963 vt_parser->hide_pointer_mode = ps[0];
4964 } else if (*str_p == 't') {
4965 /* "CSI > t" */
4966
4967 int count;
4968 for (count = 0; count < num; count++) {
4969 if (ps[count] == 0) {
4970 vt_parser->set_title_using_hex = 1;
4971 } else if (ps[count] == 1) {
4972 vt_parser->get_title_using_hex = 1;
4973 } else if (ps[count] == 2) {
4974 vt_parser->set_title_using_utf8 = 1;
4975 } else if (ps[count] == 3) {
4976 vt_parser->get_title_using_utf8 = 1;
4977 }
4978 }
4979 } else if (*str_p == 'T') {
4980 /* "CSI > T" */
4981
4982 int count;
4983 for (count = 0; count < num; count++) {
4984 if (ps[count] == 0) {
4985 vt_parser->set_title_using_hex = 0;
4986 } else if (ps[count] == 1) {
4987 vt_parser->get_title_using_hex = 0;
4988 } else if (ps[count] == 2) {
4989 vt_parser->set_title_using_utf8 = 0;
4990 } else if (ps[count] == 3) {
4991 vt_parser->get_title_using_utf8 = 0;
4992 }
4993 }
4994 } else {
4995 /*
4996 * "CSI > c"
4997 */
4998 }
4999 } else if (para_ch == '=') {
5000 if (*str_p == 'c') {
5001 /* "CSI = c" Tertiary DA (DA3) */
5002
5003 send_device_attributes(vt_parser->pty, 3);
5004 }
5005 } else if (intmed_ch == '!') {
5006 if (*str_p == 'p') {
5007 /* "CSI ! p" Soft Terminal Reset (DECSTR) */
5008
5009 soft_reset(vt_parser);
5010 }
5011 } else if (intmed_ch == '$') {
5012 if (*str_p == 'p') {
5013 /* "CSI $ p" DECRQM */
5014
5015 if (num > 0) {
5016 char seq[2 + DIGIT_STR_LEN(u_int) + 5];
5017 sprintf(seq, "\x1b[%d;%d$y", ps[0], get_vtmode(vt_parser, VTMODE(ps[0])));
5018 vt_write_to_pty(vt_parser->pty, seq, strlen(seq));
5019 }
5020 } else if (*str_p == '|') {
5021 /* "CSI $ |" DECSCPP */
5022
5023 /*
5024 * DECSCPP doesns't clear screen, reset scroll regions or moves the cursor
5025 * as does DECCOLM.
5026 */
5027
5028 if (ps[0] <= 0 || ps[0] == 80) {
5029 resize(vt_parser, 80, -1, 1);
5030 } else if (ps[0] == 132) {
5031 resize(vt_parser, 132, -1, 1);
5032 }
5033 } else if (*str_p == '}') {
5034 /* "CSI $ }" DECSASD */
5035
5036 if (ps[0] <= 0) {
5037 vt_focus_main_screen(vt_parser->screen);
5038 } else if (ps[0] == 1) {
5039 vt_focus_status_line(vt_parser->screen);
5040 }
5041 } else if (*str_p == '~') {
5042 /* "CSI $ ~" DECSSDT */
5043
5044 set_use_status_line(vt_parser, ps[0]);
5045 } else if (*str_p == 'u') {
5046 if (ps[0] == 1) {
5047 /* "CSI 1 $ u" DECRQTSR */
5048 vt_write_to_pty(vt_parser->pty, "\x1bP0$s\x1b\\", 7);
5049 } else if (ps[0] == 2) {
5050 if (num == 2) {
5051 /* "CSI 2;Pu $ u" DECCTR */
5052 report_color_table(vt_parser, ps[1]);
5053 }
5054 }
5055 } else if (*str_p == 'w') {
5056 /* "CSI $ w" DECRQPSR */
5057 if (num == 1) {
5058 report_presentation_state(vt_parser, ps[0]);
5059 }
5060 } else {
5061 int count;
5062
5063 if (*str_p == 'x') {
5064 /* DECFRA: Move Pc to the end */
5065 int tmp;
5066
5067 tmp = ps[0];
5068 memmove(ps, ps + 1, sizeof(ps[0]) * 4);
5069 ps[4] = tmp;
5070 num--;
5071 }
5072
5073 /* Set the default values to the 0-3 parameters. */
5074 for (count = 0; count < 4; count++) {
5075 if (count >= num || ps[count] <= 0) {
5076 if (count == 2) {
5077 ps[count] = vt_screen_get_logical_rows(vt_parser->screen);
5078 } else if (count == 3) {
5079 ps[count] = vt_screen_get_logical_cols(vt_parser->screen);
5080 } else {
5081 ps[count] = 1;
5082 }
5083 }
5084 }
5085
5086 if (ps[3] >= ps[1] && ps[2] >= ps[0]) {
5087 if (*str_p == 'z') {
5088 /* "CSI ... $ z" DECERA */
5089 vt_screen_erase_area(vt_parser->screen, ps[1] - 1, ps[0] - 1, ps[3] - ps[1] + 1,
5090 ps[2] - ps[0] + 1);
5091 } else if (*str_p == '{') {
5092 /* "CSI ... $ {" DECSERA */
5093 vt_protect_store_t *save;
5094 save = vt_screen_save_protected_chars(vt_parser->screen, ps[0] - 1, ps[2] - 1, 1);
5095 vt_screen_erase_area(vt_parser->screen, ps[1] - 1, ps[0] - 1, ps[3] - ps[1] + 1,
5096 ps[2] - ps[0] + 1);
5097 vt_screen_restore_protected_chars(vt_parser->screen, save);
5098 } else if (*str_p == 'v' && (num == 5 || num >= 8)) {
5099 /* "CSI ... $ v" DECCRA */
5100 if (num == 5) {
5101 ps[5] = ps[6] = ps[7] = 1; /* default values of xterm */
5102 } else {
5103 for (count = 4; count < 8; count++) {
5104 if (ps[count] <= 0) {
5105 ps[count] = 1;
5106 }
5107 }
5108 }
5109 vt_screen_copy_area(vt_parser->screen, ps[1] - 1, ps[0] - 1, ps[3] - ps[1] + 1,
5110 ps[2] - ps[0] + 1, ps[4] - 1, ps[6] - 1, ps[5] - 1, ps[7] - 1);
5111 } else if (*str_p == 'x') {
5112 /* "CSI ... $ x" DECFRA */
5113 if (!iscntrl(ps[4])) {
5114 vt_screen_fill_area(vt_parser->screen, ps[4], vt_parser->is_protected,
5115 ps[1] - 1, ps[0] - 1, ps[3] - ps[1] + 1, ps[2] - ps[0] + 1);
5116 }
5117 } else if (*str_p == 'r') {
5118 /* "CSI Pt;Pl;Pb;Pr;...$r" DECCARA */
5119
5120 for (count = 4; count < num; count++) {
5121 vt_screen_change_attr_area(vt_parser->screen, ps[1] - 1, ps[0] - 1,
5122 ps[3] - ps[1] + 1, ps[2] - ps[0] + 1, ps[count]);
5123 }
5124 } else if (*str_p == 't') {
5125 /* "CSI Pt;Pl;Pb;Pr;...$t" DECRARA */
5126
5127 for (count = 4; count < num; count++) {
5128 vt_screen_reverse_attr_area(vt_parser->screen, ps[1] - 1, ps[0] - 1,
5129 ps[3] - ps[1] + 1, ps[2] - ps[0] + 1, ps[count]);
5130 }
5131 }
5132 }
5133 }
5134 } else if (intmed_ch == ' ') {
5135 if (*str_p == 'q') {
5136 /* "CSI SP q" DECSCUSR */
5137
5138 if (ps[0] < 2) {
5139 vt_parser->cursor_style = CS_BLOCK|CS_BLINK;
5140 } else if (ps[0] == 2) {
5141 vt_parser->cursor_style = CS_BLOCK;
5142 } else if (ps[0] == 3) {
5143 vt_parser->cursor_style = CS_UNDERLINE|CS_BLINK;
5144 } else if (ps[0] == 4) {
5145 vt_parser->cursor_style = CS_UNDERLINE;
5146 } else if (ps[0] == 5) {
5147 vt_parser->cursor_style = CS_BAR|CS_BLINK;
5148 } else if (ps[0] == 6) {
5149 vt_parser->cursor_style = CS_BAR;
5150 }
5151 } else {
5152 if (ps[0] <= 0) {
5153 ps[0] = 1;
5154 }
5155
5156 if (*str_p == '@') {
5157 /* CSI SP @ (SL) */
5158 vt_screen_scroll_leftward(vt_parser->screen, ps[0]);
5159 } else if (*str_p == 'A') {
5160 /* CSI SP A (SR) */
5161 vt_screen_scroll_rightward(vt_parser->screen, ps[0]);
5162 } else if (*str_p == 'P') {
5163 /* CSI SP P (PPA) */
5164 vt_screen_goto_page(vt_parser->screen, ps[0] - 1);
5165 } else if (*str_p == 'Q') {
5166 /* CSI SP Q (PPR) */
5167 vt_screen_goto_next_page(vt_parser->screen, ps[0]);
5168 } else if (*str_p == 'R') {
5169 /* CSI SP R (PPB) */
5170 vt_screen_goto_prev_page(vt_parser->screen, ps[0]);
5171 } else {
5172 /*
5173 * "CSI SP t"(DECSWBV), "CSI SP u"(DECSMBV)
5174 */
5175 }
5176 }
5177 } else if (intmed_ch == '*') {
5178 if (ps[0] == -1) {
5179 ps[0] = 0;
5180 }
5181
5182 if (*str_p == 'z') {
5183 /* "CSI Pn * z" DECINVM */
5184
5185 invoke_macro(vt_parser, ps[0]);
5186 } else if (*str_p == 'x') {
5187 /* "CSI Pn * x " DECSACE */
5188
5189 vt_screen_set_use_rect_attr_select(vt_parser->screen, ps[0] == 2);
5190 } else if (*str_p == '|') {
5191 /* "CSI Pn * |" DECSNLS */
5192 resize(vt_parser, -1, ps[0], 1);
5193 } else if (*str_p == 'y') {
5194 /* "CSI Pn * y" DECRQCRA */
5195 if (num >= 1) {
5196 u_int16_t checksum;
5197 char seq[6+DIGIT_STR_LEN(ps[0])+4+1];
5198
5199 if (ps[1] == 0) {
5200 #if 0
5201 /* Ignore following parameters (https://vt100.net/docs/vt510-rm/DECRQCRA.html) */
5202 num = 1;
5203 #else
5204 /* Compatible with xterm */
5205 ps[1] = 1;
5206 #endif
5207 }
5208
5209 switch(num) {
5210 case 1:
5211 case 2:
5212 ps[2] = 1;
5213
5214 case 3:
5215 ps[3] = 1;
5216
5217 case 4:
5218 ps[4] = vt_screen_get_rows(vt_parser->screen);
5219
5220 case 5:
5221 ps[5] = vt_screen_get_cols(vt_parser->screen);
5222 }
5223
5224 if (num == 1) {
5225 int page;
5226
5227 checksum = 0;
5228 for (page = 0; page <= MAX_PAGE_ID; page++) {
5229 int i = vt_screen_get_checksum(vt_parser->screen, ps[3] - 1, ps[2] - 1,
5230 ps[5] - ps[3] + 1, ps[4] - ps[2] + 1, page);
5231 checksum += i;
5232 }
5233 } else {
5234 checksum = vt_screen_get_checksum(vt_parser->screen, ps[3] - 1, ps[2] - 1,
5235 ps[5] - ps[3] + 1, ps[4] - ps[2] + 1, ps[1] - 1);
5236 }
5237
5238 sprintf(seq, "\x1bP%d!~%.4x\x1b\\", ps[0], checksum);
5239 vt_write_to_pty(vt_parser->pty, seq, strlen(seq));
5240 }
5241 }
5242 } else if (intmed_ch == '\'') {
5243 if (*str_p == '|') {
5244 /* "CSI ' |" DECRQLP */
5245
5246 request_locator(vt_parser);
5247 } else if (*str_p == '{') {
5248 /* "CSI Pn ' {" DECSLE */
5249 int count;
5250
5251 for (count = 0; count < num; count++) {
5252 if (ps[count] == 1) {
5253 vt_parser->locator_mode |= LOCATOR_BUTTON_DOWN;
5254 } else if (ps[count] == 2) {
5255 vt_parser->locator_mode &= ~LOCATOR_BUTTON_DOWN;
5256 } else if (ps[count] == 3) {
5257 vt_parser->locator_mode |= LOCATOR_BUTTON_UP;
5258 } else if (ps[count] == 4) {
5259 vt_parser->locator_mode &= ~LOCATOR_BUTTON_UP;
5260 } else {
5261 vt_parser->locator_mode &= ~(LOCATOR_BUTTON_UP | LOCATOR_BUTTON_DOWN);
5262 }
5263 }
5264 } else if (*str_p == '}') {
5265 /* "CSI ' }" DECIC */
5266
5267 if (ps[0] <= 0) {
5268 ps[0] = 1;
5269 }
5270
5271 vt_screen_scroll_rightward_from_cursor(vt_parser->screen, ps[0]);
5272 } else if (*str_p == '~') {
5273 /* "CSI ' ~" DECDC */
5274
5275 if (ps[0] <= 0) {
5276 ps[0] = 1;
5277 }
5278
5279 vt_screen_scroll_leftward_from_cursor(vt_parser->screen, ps[0]);
5280 } else if (*str_p == 'w') {
5281 /* "CSI ' w" DECEFR Filter Rectangle */
5282
5283 if (num == 4) {
5284 #if 0
5285 if (top > ps[0] || left > ps[1] || bottom < ps[2] || right < ps[3]) {
5286 /*
5287 * XXX
5288 * An outside rectangle event should
5289 * be sent immediately.
5290 */
5291 }
5292 #endif
5293
5294 vt_parser->loc_filter.top = ps[0];
5295 vt_parser->loc_filter.left = ps[1];
5296 vt_parser->loc_filter.bottom = ps[2];
5297 vt_parser->loc_filter.right = ps[3];
5298 }
5299
5300 vt_parser->locator_mode |= LOCATOR_FILTER_RECT;
5301 } else if (*str_p == 'z') {
5302 /* "CSI ' z" DECELR */
5303
5304 vt_parser->locator_mode &= ~LOCATOR_FILTER_RECT;
5305 memset(&vt_parser->loc_filter, 0, sizeof(vt_parser->loc_filter));
5306 if (ps[0] <= 0) {
5307 if (vt_parser->mouse_mode >= LOCATOR_CHARCELL_REPORT) {
5308 set_mouse_report(vt_parser, 0);
5309 }
5310 } else {
5311 vt_parser->locator_mode |= ps[0] == 2 ? LOCATOR_ONESHOT : 0;
5312
5313 set_mouse_report(vt_parser, (num == 1 || ps[1] <= 0 || ps[1] == 2)
5314 ? LOCATOR_CHARCELL_REPORT
5315 : LOCATOR_PIXEL_REPORT);
5316 }
5317 }
5318 } else if (intmed_ch == '\"') {
5319 if (*str_p == 'v') {
5320 /* "CSI " v" DECRQDE */
5321
5322 send_display_extent(vt_parser->pty, vt_screen_get_logical_cols(vt_parser->screen),
5323 vt_screen_get_logical_rows(vt_parser->screen),
5324 vt_parser->screen->edit->hmargin_beg + 1,
5325 vt_parser->screen->edit->vmargin_beg + 1,
5326 vt_screen_get_page_id(vt_parser->screen) + 1);
5327 } else if (*str_p == 'q') {
5328 /* "CSI " q" DECSCA */
5329
5330 if (ps[0] <= 0 || ps[0] == 2) {
5331 vt_parser->is_protected = 0;
5332 } else if (ps[0] == 1) {
5333 vt_parser->is_protected = 1;
5334 }
5335 } else {
5336 /* "CSI " p"(DECSCL) etc */
5337 }
5338 } else if (intmed_ch == ',') {
5339 if (*str_p == '|') {
5340 /* "CSI Ps1;Ps2;Ps3,|" (DECAC) */
5341
5342 if (num == 3 && ps[0] == 1 && ((u_int)ps[1]) <= 255 && ((u_int)ps[2]) <= 255) {
5343 config_protocol_set_simple(vt_parser, "fg_color", vt_get_color_name(ps[1]), 0);
5344 config_protocol_set_simple(vt_parser, "bg_color", vt_get_color_name(ps[2]), 1);
5345 }
5346 } else if (*str_p == '}') {
5347 /* "CSI Ps1;Ps2;Ps3,}" (DECATC) */
5348
5349 if (num == 3 && ((u_int)ps[0]) <= 15 && ((u_int)ps[1]) <= 255 && ((u_int)ps[2] <= 255)) {
5350 int idx = alt_color_idxs[ps[0]];
5351 vt_parser->alt_colors.flags |= (1 << idx);
5352 vt_parser->alt_colors.fg[idx] = ps[1];
5353 vt_parser->alt_colors.bg[idx] = ps[2];
5354 }
5355 }
5356 } else if (intmed_ch == ')') {
5357 if (*str_p == '{') {
5358 /* "CSI ) {" DECSTGLT */
5359 if (ps[0] <= 0) {
5360 vt_parser->use_ansi_colors = 0;
5361 } else if (ps[0] <= 3) {
5362 /*
5363 * ps[0] == 1 or 2 enables "Alternate color", but mlterm always enables it
5364 * if DECATC specifies alternate colors.
5365 */
5366 vt_parser->use_ansi_colors = 1;
5367 }
5368 }
5369 } else if (intmed_ch == '+') {
5370 if (*str_p == 'p') {
5371 /* "CSI + p" DECSR */
5372
5373 full_reset(vt_parser);
5374
5375 if (ps[0] >= 0) {
5376 char seq[2+DIGIT_STR_LEN(ps[0])+3];
5377
5378 sprintf(seq, "\x1b[%d*q", ps[0]);
5379 vt_write_to_pty(vt_parser->pty, seq, strlen(seq));
5380 }
5381 }
5382 }
5383 /* Other para_ch(0x3a-0x3f) or intmed_ch(0x20-0x2f) */
5384 else if (para_ch || intmed_ch) {
5385 #ifdef DEBUG
5386 debug_print_unknown("ESC [ %c %c\n", para_ch, intmed_ch, *str_p);
5387 #endif
5388 } else if (*str_p == '@') {
5389 /* "CSI @" insert blank chars (ICH) */
5390
5391 if (ps[0] <= 0) {
5392 ps[0] = 1;
5393 }
5394
5395 /* inserting ps[0] blank characters. */
5396 vt_screen_insert_blank_chars(vt_parser->screen, ps[0]);
5397 } else if (*str_p == 'A' || *str_p == 'k') {
5398 /* "CSI A" = CUU , "CSI k" = VPB */
5399
5400 if (ps[0] <= 0) {
5401 ps[0] = 1;
5402 }
5403
5404 vt_screen_go_upward(vt_parser->screen, ps[0]);
5405 } else if (*str_p == 'B' || *str_p == 'e') {
5406 /* "CSI B" = CUD , "CSI e" = VPR */
5407
5408 if (ps[0] <= 0) {
5409 ps[0] = 1;
5410 }
5411
5412 vt_screen_go_downward(vt_parser->screen, ps[0]);
5413 } else if (*str_p == 'C' || *str_p == 'a') {
5414 /* "CSI C" = CUF , "CSI a" = HPR */
5415
5416 if (ps[0] <= 0) {
5417 ps[0] = 1;
5418 }
5419
5420 vt_screen_go_forward(vt_parser->screen, ps[0], 0);
5421 } else if (*str_p == 'D' || *str_p == 'j') {
5422 /* "CSI D" = CUB , "CSI j" = HPB */
5423
5424 if (ps[0] <= 0) {
5425 ps[0] = 1;
5426 }
5427
5428 vt_screen_go_back(vt_parser->screen, ps[0], 0);
5429 } else if (*str_p == 'E') {
5430 /* "CSI E" down and goto first column (CNL) */
5431
5432 if (ps[0] <= 0) {
5433 ps[0] = 1;
5434 }
5435
5436 vt_screen_go_downward(vt_parser->screen, ps[0]);
5437 vt_screen_goto_beg_of_line(vt_parser->screen);
5438 } else if (*str_p == 'F') {
5439 /* "CSI F" up and goto first column (CPL) */
5440
5441 if (ps[0] <= 0) {
5442 ps[0] = 1;
5443 }
5444
5445 vt_screen_go_upward(vt_parser->screen, ps[0]);
5446 vt_screen_goto_beg_of_line(vt_parser->screen);
5447 } else if (*str_p == 'G' || *str_p == '`') {
5448 /*
5449 * "CSI G" (CHA), "CSI `" (HPA)
5450 * cursor position absolute.
5451 */
5452
5453 if (ps[0] <= 0) {
5454 ps[0] = 1;
5455 }
5456
5457 vt_screen_go_horizontally(vt_parser->screen, ps[0] - 1);
5458 } else if (*str_p == 'H' || *str_p == 'f') {
5459 /* "CSI H" (CUP) "CSI f" (HVP) */
5460
5461 if (ps[0] <= 0) {
5462 ps[0] = 1;
5463 }
5464
5465 if (num <= 1 || ps[1] <= 0) {
5466 ps[1] = 1;
5467 }
5468
5469 vt_screen_goto(vt_parser->screen, ps[1] - 1, ps[0] - 1);
5470 } else if (*str_p == 'I') {
5471 /* "CSI I" cursor forward tabulation (CHT) */
5472
5473 if (ps[0] == -1) {
5474 /*
5475 * "CSI 0 I" => No tabulation.
5476 * "CSI I" => 1 taburation.
5477 */
5478 ps[0] = 1;
5479 }
5480
5481 vt_screen_forward_tabs(vt_parser->screen, ps[0]);
5482 } else if (*str_p == 'J') {
5483 /* "CSI J" Erase in Display (ED) */
5484
5485 if (ps[0] <= 0) {
5486 vt_screen_clear_below(vt_parser->screen);
5487 } else if (ps[0] == 1) {
5488 vt_screen_clear_above(vt_parser->screen);
5489 } else if (ps[0] == 2) {
5490 clear_display_all(vt_parser);
5491 }
5492 #if 1
5493 /* xterm compatible (Tera Term 4.105 or later also supports) */
5494 else if (ps[0] == 3) {
5495 u_int size = vt_screen_get_log_size(vt_parser->screen);
5496 int unlimited = vt_screen_log_size_is_unlimited(vt_parser->screen);
5497
5498 vt_screen_change_log_size(vt_parser->screen, 0);
5499 if (unlimited) {
5500 vt_screen_unlimit_log_size(vt_parser->screen);
5501 } else {
5502 vt_screen_change_log_size(vt_parser->screen, size);
5503 }
5504 }
5505 #endif
5506 } else if (*str_p == 'K') {
5507 /* "CSI K" Erase in Line (EL) */
5508
5509 if (ps[0] <= 0) {
5510 vt_screen_clear_line_to_right(vt_parser->screen);
5511 } else if (ps[0] == 1) {
5512 vt_screen_clear_line_to_left(vt_parser->screen);
5513 } else if (ps[0] == 2) {
5514 clear_line_all(vt_parser);
5515 }
5516 } else if (*str_p == 'L') {
5517 /* "CSI L" IL */
5518
5519 if (ps[0] <= 0) {
5520 ps[0] = 1;
5521 }
5522
5523 vt_screen_insert_new_lines(vt_parser->screen, ps[0]);
5524 } else if (*str_p == 'M') {
5525 /* "CSI M" DL */
5526
5527 if (ps[0] <= 0) {
5528 ps[0] = 1;
5529 }
5530
5531 vt_screen_delete_lines(vt_parser->screen, ps[0]);
5532 } else if (*str_p == 'P') {
5533 /* "CSI P" delete chars (DCH) */
5534
5535 if (ps[0] <= 0) {
5536 ps[0] = 1;
5537 }
5538
5539 vt_screen_delete_cols(vt_parser->screen, ps[0]);
5540 } else if (*str_p == 'S') {
5541 /* "CSI S" scroll up (SU) */
5542
5543 if (ps[0] <= 0) {
5544 ps[0] = 1;
5545 }
5546
5547 vt_screen_scroll_upward(vt_parser->screen, ps[0]);
5548 } else if (*str_p == 'T') {
5549 /* "CSI T" scroll down (SD) */
5550
5551 if (ps[0] <= 0) {
5552 ps[0] = 1;
5553 }
5554
5555 vt_screen_scroll_downward(vt_parser->screen, ps[0]);
5556 } else if (*str_p == 'U') {
5557 /* "CSI U" (NP) */
5558
5559 if (ps[0] <= 0) {
5560 ps[0] = 1;
5561 }
5562
5563 vt_screen_goto_next_page(vt_parser->screen, ps[0]);
5564 vt_screen_goto_home(vt_parser->screen);
5565 } else if (*str_p == 'V') {
5566 /* "CSI V" (PP) */
5567
5568 if (ps[0] <= 0) {
5569 ps[0] = 1;
5570 }
5571
5572 vt_screen_goto_prev_page(vt_parser->screen, ps[0]);
5573 vt_screen_goto_home(vt_parser->screen);
5574 } else if (*str_p == 'W') {
5575 /* "CSI W" Cursor Tabluation Control (CTC) */
5576
5577 if (ps[0] <= 0) {
5578 vt_screen_set_tab_stop(vt_parser->screen);
5579 } else if (ps[0] == 2) {
5580 vt_screen_clear_tab_stop(vt_parser->screen);
5581 } else if (ps[0] == 4 || ps[0] == 5) {
5582 vt_screen_clear_all_tab_stops(vt_parser->screen);
5583 }
5584 } else if (*str_p == 'X') {
5585 /* "CSI X" erase characters (ECH) */
5586
5587 if (ps[0] <= 0) {
5588 ps[0] = 1;
5589 }
5590
5591 vt_screen_clear_cols(vt_parser->screen, ps[0]);
5592 } else if (*str_p == 'Z') {
5593 /* "CSI Z" cursor backward tabulation (CBT) */
5594
5595 if (ps[0] == -1) {
5596 /*
5597 * "CSI 0 Z" => No tabulation.
5598 * "CSI Z" => 1 taburation.
5599 */
5600 ps[0] = 1;
5601 }
5602
5603 vt_screen_backward_tabs(vt_parser->screen, ps[0]);
5604 } else if (*str_p == 'b') {
5605 /* "CSI b" repeat the preceding graphic character(REP) */
5606
5607 if (vt_parser->w_buf.last_ch) {
5608 int count;
5609
5610 if (ps[0] <= 0) {
5611 ps[0] = 1;
5612 }
5613
5614 for (count = 0; count < ps[0]; count++) {
5615 (*vt_parser->w_buf.output_func)(vt_parser->screen, vt_parser->w_buf.last_ch,
5616 1);
5617 }
5618
5619 vt_parser->w_buf.last_ch = NULL;
5620 }
5621 } else if (*str_p == 'c') {
5622 /* "CSI c" Primary DA (DA1) */
5623
5624 send_device_attributes(vt_parser->pty, 1);
5625 } else if (*str_p == 'd') {
5626 /* "CSI d" line position absolute(VPA) */
5627
5628 if (ps[0] <= 0) {
5629 ps[0] = 1;
5630 }
5631
5632 vt_screen_go_vertically(vt_parser->screen, ps[0] - 1);
5633 } else if (*str_p == 'g') {
5634 /* "CSI g" tab clear (TBC) */
5635
5636 if (ps[0] <= 0) {
5637 vt_screen_clear_tab_stop(vt_parser->screen);
5638 } else if (ps[0] == 3) {
5639 vt_screen_clear_all_tab_stops(vt_parser->screen);
5640 }
5641 } else if (*str_p == 'h') {
5642 /* "CSI h" (SM) */
5643 int count;
5644
5645 for (count = 0; count < num; count++) {
5646 set_vtmode(vt_parser, VTMODE(ps[count]), 1);
5647 }
5648 } else if (*str_p == 'i') {
5649 /* "CSI i" (MC) */
5650
5651 if (ps[0] <= 0) {
5652 snapshot(vt_parser, VT_UTF8, vt_pty_get_slave_name(vt_parser->pty) + 5 /* skip /dev/ */,
5653 WCA_SCREEN);
5654 } else if (ps[0] == 1) {
5655 snapshot(vt_parser, VT_UTF8, vt_pty_get_slave_name(vt_parser->pty) + 5 /* skip /dev/ */,
5656 WCA_CURSOR_LINE);
5657 }
5658 } else if (*str_p == 'l') {
5659 /* "CSI l" (RM) */
5660 int count;
5661
5662 for (count = 0; count < num; count++) {
5663 set_vtmode(vt_parser, VTMODE(ps[count]), 0);
5664 }
5665 } else if (*str_p == 'm') {
5666 /* "CSI m" (SGR) */
5667 int count;
5668
5669 for (count = 0; count < num;) {
5670 int proceed;
5671
5672 if ((proceed = change_char_fine_color(vt_parser, ps + count, num - count))) {
5673 count += proceed;
5674 } else {
5675 if (ps[count] < 0) {
5676 ps[count] = 0;
5677 }
5678
5679 change_char_attr(vt_parser, ps[count++]);
5680 }
5681 }
5682 } else if (*str_p == 'n') {
5683 /* "CSI n" Device Status Report (DSR) */
5684
5685 if (ps[0] == 5) {
5686 /* Operating Status */
5687 vt_write_to_pty(vt_parser->pty, "\x1b[0n", 4);
5688 } else if (ps[0] == 6) {
5689 /* CPR */
5690 char seq[4 + DIGIT_STR_LEN(u_int) * 2 + 1];
5691
5692 sprintf(seq, "\x1b[%d;%dR", vt_screen_cursor_logical_row(vt_parser->screen) + 1,
5693 vt_screen_cursor_logical_col(vt_parser->screen) + 1);
5694
5695 vt_write_to_pty(vt_parser->pty, seq, strlen(seq));
5696 }
5697 } else if (*str_p == 'r') {
5698 /* "CSI r" set scroll region (DECSTBM) */
5699
5700 if (ps[0] < 0) {
5701 ps[0] = 0;
5702 }
5703
5704 if (num <= 1 || ps[1] < 0) {
5705 ps[1] = 0;
5706 }
5707
5708 vt_screen_set_vmargin(vt_parser->screen, ps[0] - 1, ps[1] - 1);
5709 vt_screen_goto(vt_parser->screen, 0, 0);
5710 } else if (*str_p == 's') {
5711 /* "CSI s" SCOSC or DECSLRM */
5712
5713 if (num <= 1 || ps[1] <= 0) {
5714 ps[1] = vt_screen_get_logical_cols(vt_parser->screen);
5715 }
5716
5717 if (vt_screen_set_hmargin(vt_parser->screen, ps[0] <= 0 ? 0 : ps[0] - 1, ps[1] - 1)) {
5718 vt_screen_goto(vt_parser->screen, 0, 0);
5719 } else if (num == 1 && ps[0] == -1) {
5720 save_cursor(vt_parser);
5721 }
5722 } else if (*str_p == 't') {
5723 /* "CSI t" */
5724
5725 if (ps[0] == 4 || ps[0] == 8) {
5726 if (num == 2) {
5727 ps[2] = -1;
5728 num = 3;
5729 }
5730
5731 if (num == 3) {
5732 resize(vt_parser, ps[2], ps[1], ps[0] == 8);
5733 }
5734 } else if (ps[0] == 9) {
5735 if (num == 2 && 0 <= ps[1] && ps[1] <= 3) {
5736 int flag;
5737
5738 if (ps[1] >= 2) {
5739 flag = ps[1]; /* MAXIMIZE VERTICALLY or HORIZONTALLY */
5740 } else {
5741 flag = (ps[1] == 0 ? 1 /* UNMAXIMIZE */ : 4 /* MAXIMIZE FULL */);
5742 }
5743
5744 set_maximize(vt_parser, flag);
5745 }
5746 } else if (ps[0] == 10) {
5747 /* XXX full screen is not supported for now. */
5748 } else if (ps[0] == 7) {
5749 char cmd[] = "update_all";
5750 config_protocol_set(vt_parser, cmd, 0);
5751 } else if (ps[0] == 11) {
5752 vt_write_to_pty(vt_parser->pty, "\x1b[1t", 4); /* XXX always non-iconified */
5753 } else if (ps[0] == 13) {
5754 vt_write_to_pty(vt_parser->pty, "\x1b[3;0;0t", 8);
5755 } else if (ps[0] == 14) {
5756 report_window_size(vt_parser, 0);
5757 } else if (ps[0] == 15) {
5758 report_display_size(vt_parser, 0);
5759 } else if (ps[0] == 16) {
5760 report_cell_size(vt_parser);
5761 } else if (ps[0] == 18) {
5762 report_window_size(vt_parser, 1);
5763 } else if (ps[0] == 19) {
5764 report_display_size(vt_parser, 1);
5765 } else if (ps[0] == 20) {
5766 report_window_or_icon_name(vt_parser, 0);
5767 } else if (ps[0] == 21) {
5768 report_window_or_icon_name(vt_parser, 1);
5769 } else if (ps[0] >= 24) {
5770 /*
5771 * "CSI Pn t" DECSLPP
5772 * This changes not only the number of lines but also
5773 * the number of pages, but mlterm doesn't change the latter.
5774 */
5775 resize(vt_parser, -1, ps[0], 1);
5776 } else if (num == 2) {
5777 if (ps[0] == 22) {
5778 /*
5779 * XXX
5780 * If Icon and window title are pushed by ps[1] = 0 and either of them is poped,
5781 * the other should be poped.
5782 * But it is not supported for now.
5783 * esctest: XtermWinopsTests.test_XtermWinops_PushIconAndWindow_PopIcon and
5784 * XtermWinopsTests.test_XtermWinops_PushIconAndWindow_PopWindow fails by this.
5785 */
5786 if (ps[1] == 0 || ps[1] == 1) {
5787 push_to_saved_names(&vt_parser->saved_icon_names, vt_parser->icon_name);
5788 }
5789
5790 if (ps[1] == 0 || ps[1] == 2) {
5791 push_to_saved_names(&vt_parser->saved_win_names, vt_parser->win_name);
5792 }
5793 } else if (ps[0] == 23) {
5794 if ((ps[1] == 0 || ps[1] == 1) && vt_parser->saved_icon_names.num > 0) {
5795 set_icon_name(vt_parser, pop_from_saved_names(&vt_parser->saved_icon_names));
5796 }
5797
5798 if ((ps[1] == 0 || ps[1] == 2) && vt_parser->saved_win_names.num > 0) {
5799 set_window_name(vt_parser, pop_from_saved_names(&vt_parser->saved_win_names));
5800 }
5801 }
5802 }
5803 } else if (*str_p == 'u') {
5804 /* "CSI u" (SCORC) */
5805
5806 restore_cursor(vt_parser);
5807 } else if (*str_p == 'x') {
5808 /* "CSI x" request terminal parameters (DECREQTPARM) */
5809
5810 /* XXX the same as rxvt */
5811
5812 if (ps[0] < 0) {
5813 ps[0] = 0;
5814 }
5815
5816 if (ps[0] == 0 || ps[0] == 1) {
5817 char seq[] = "\x1b[X;1;1;112;112;1;0x";
5818
5819 /* '+ 0x30' lets int to char */
5820 seq[2] = ps[0] + 2 + 0x30;
5821
5822 vt_write_to_pty(vt_parser->pty, seq, sizeof(seq) - 1);
5823 }
5824 }
5825 #if 0
5826 else if (*str_p == '^') {
5827 /* "CSI ^" initiate hilite mouse tracking. */
5828 }
5829 #endif
5830 /* Other final character */
5831 else if (0x40 <= *str_p && *str_p <= 0x7e) {
5832 #ifdef DEBUG
5833 debug_print_unknown("ESC [ %c\n", *str_p);
5834 #endif
5835 } else {
5836 /* not VT100 control sequence. */
5837
5838 #ifdef ESCSEQ_DEBUG
5839 bl_msg_printf("=> not VT100 control sequence.\n");
5840 #endif
5841
5842 return 1;
5843 }
5844 } else if (*str_p == ']') {
5845 /* "ESC ]" (OSC) */
5846
5847 char digit[DIGIT_STR_LEN(int)+1];
5848 int count;
5849 int ps;
5850 u_char *pt;
5851
5852 if (!inc_str_in_esc_seq(vt_parser->screen, &str_p, &left, 0)) {
5853 return 0;
5854 }
5855
5856 for (count = 0; count < DIGIT_STR_LEN(int); count++) {
5857 if ('0' <= *str_p && *str_p <= '9') {
5858 digit[count] = *str_p;
5859
5860 if (!inc_str_in_esc_seq(vt_parser->screen, &str_p, &left, 0)) {
5861 return 0;
5862 }
5863 } else {
5864 break;
5865 }
5866 }
5867
5868 if (count > 0 && *str_p == ';') {
5869 digit[count] = '\0';
5870
5871 /* if digit is illegal , ps is set 0. */
5872 ps = atoi(digit);
5873 #ifdef MAX_PS_DIGIT
5874 if (ps > MAX_PS_DIGIT) {
5875 ps = MAX_PS_DIGIT;
5876 }
5877 #endif
5878
5879 if (!inc_str_in_esc_seq(vt_parser->screen, &str_p, &left, 1)) {
5880 return 0;
5881 }
5882 } else {
5883 /* Illegal OSC format */
5884 ps = -1;
5885 }
5886
5887 pt = str_p;
5888
5889 /*
5890 * Skip string which was already parsed.
5891 * +1 in case str_p[left - vt_parser->r_buf.new_len] points
5892 * "\\" of "\x1b\\".
5893 */
5894 if (left > vt_parser->r_buf.new_len + 1) {
5895 str_p += (left - vt_parser->r_buf.new_len - 1);
5896 left = vt_parser->r_buf.new_len + 1;
5897 }
5898
5899 if (!get_pt_in_esc_seq(&str_p, &left, 0, 1)) {
5900 if (left == 0) {
5901 return 0;
5902 }
5903 #ifdef DEBUG
5904 else {
5905 debug_print_unknown("ESC ] %d ; ???\n", ps);
5906 }
5907 #endif
5908 } else if (ps == 0) {
5909 /* "OSC 0" change icon name and window title */
5910
5911 if (*pt != '\0') {
5912 if ((pt = parse_title(vt_parser, strdup(pt)))) {
5913 set_window_name(vt_parser, pt);
5914 set_icon_name(vt_parser, strdup(pt));
5915 }
5916 }
5917 } else if (ps == 1) {
5918 /* "OSC 1" change icon name */
5919
5920 if (*pt != '\0') {
5921 if ((pt = parse_title(vt_parser, strdup(pt)))) {
5922 set_icon_name(vt_parser, pt);
5923 }
5924 }
5925 } else if (ps == 2) {
5926 /* "OSC 2" change window title */
5927
5928 if (*pt != '\0') {
5929 if ((pt = parse_title(vt_parser, strdup(pt)))) {
5930 set_window_name(vt_parser, pt);
5931 }
5932 }
5933 } else if (ps == 4) {
5934 /* "OSC 4" change 256 color */
5935
5936 change_color_rgb(vt_parser, pt);
5937 } else if (ps == 5) {
5938 /* "OSC 5" change colorBD/colorUL */
5939
5940 change_special_color(vt_parser, pt);
5941 } else if (ps == 10) {
5942 /* "OSC 10" fg color */
5943
5944 change_fgbg_color(vt_parser, 10, pt);
5945 } else if (ps == 11) {
5946 /* "OSC 11" bg color */
5947
5948 change_fgbg_color(vt_parser, 11, pt);
5949 } else if (ps == 12) {
5950 /* "OSC 12" cursor bg color */
5951
5952 if (strcmp(pt, "?") != 0) /* ?:query rgb */ {
5953 /* XXX do nothing for now .*/
5954 } else {
5955 config_protocol_set_simple(vt_parser, "cursor_bg_color", pt, 1);
5956 }
5957 } else if (ps == 20) {
5958 /* "OSC 20" (Eterm compatible) */
5959
5960 /* edit commands */
5961 char *p;
5962
5963 /* XXX discard all adjust./op. settings.*/
5964 /* XXX may break multi-byte char string. */
5965 if ((p = strchr(pt, ';'))) {
5966 *p = '\0';
5967 }
5968 if ((p = strchr(pt, ':'))) {
5969 *p = '\0';
5970 }
5971
5972 if (*pt == '\0') {
5973 /*
5974 * Do not change current edit but
5975 * alter diaplay setting.
5976 * XXX nothing can be done for now.
5977 */
5978
5979 return 0;
5980 }
5981
5982 config_protocol_set_simple(vt_parser, "wall_picture", pt, 1);
5983 }
5984 #if 0
5985 else if (ps == 46) {
5986 /* "OSC 46" change log file */
5987 } else if (ps == 50) {
5988 /* "OSC 50" set font */
5989 }
5990 #endif
5991 else if (ps == 52) {
5992 set_selection(vt_parser, pt);
5993 } else if (ps == 104) {
5994 reset_color_rgb(vt_parser, pt, 0);
5995 } else if (ps == 105) {
5996 reset_color_rgb(vt_parser, pt, 1);
5997 }
5998 #if 0
5999 else if (ps == 110) {
6000 config_protocol_set_simple(vt_parser, "fg_color", "black", 1);
6001 } else if (ps == 111) {
6002 config_protocol_set_simple(vt_parser, "bg_color", "white", 1);
6003 } else if (ps == 112) {
6004 config_protocol_set_simple(vt_parser, "cursor_bg_color", "black", 1);
6005 }
6006 #endif
6007 #ifdef SUPPORT_ITERM2_OSC1337
6008 else if (ps == 1337) {
6009 if (strcmp(pt, "SetMark") == 0) {
6010 vt_line_t *line;
6011
6012 if ((line = vt_screen_get_cursor_line(vt_parser->screen))) {
6013 line->mark = 1;
6014 }
6015 } else {
6016 iterm2_proprietary_set(vt_parser, pt);
6017 }
6018 }
6019 #endif
6020 else if (ps == 5379) {
6021 /* "OSC 5379" set */
6022
6023 config_protocol_set(vt_parser, pt, 0);
6024 } else if (ps == 5380) {
6025 /* "OSC 5380" get */
6026
6027 config_protocol_get(vt_parser, pt, 0, NULL);
6028 } else if (ps == 5381) {
6029 /* "OSC 5381" get(menu) */
6030
6031 config_protocol_get(vt_parser, pt, 1, NULL);
6032 } else if (ps == 5383) {
6033 /* "OSC 5383" set&save */
6034
6035 config_protocol_set(vt_parser, pt, 1);
6036 }
6037 #ifdef DEBUG
6038 else if (ps == -1) {
6039 debug_print_unknown("ESC ] %s\n", pt);
6040 } else {
6041 debug_print_unknown("ESC ] %d ; %s\n", ps, pt);
6042 }
6043 #endif
6044 } else if (*str_p == 'P') {
6045 /* "ESC P" DCS */
6046
6047 u_char *dcs_beg;
6048 #ifndef NO_IMAGE
6049 char *path;
6050 #endif
6051
6052 while (1) {
6053 /* ESC P ... */
6054 dcs_beg = str_p - 1;
6055 break;
6056
6057 parse_dcs:
6058 /* 0x90 ... */
6059 dcs_beg = str_p;
6060 break;
6061 }
6062
6063 do {
6064 if (!increment_str(&str_p, &left)) {
6065 return 0;
6066 }
6067 } while (*str_p == ';' || ('0' <= *str_p && *str_p <= '9'));
6068
6069 #ifndef NO_IMAGE
6070 if (/* sixel */
6071 (*str_p == 'q' &&
6072 (path = get_home_file_path("", vt_pty_get_slave_name(vt_parser->pty) + 5, "six"))) ||
6073 /* ReGIS */
6074 (*str_p == 'p' &&
6075 (path = get_home_file_path("", vt_pty_get_slave_name(vt_parser->pty) + 5, "rgs")))) {
6076 if (!save_sixel_or_regis(vt_parser, path, dcs_beg, &str_p, &left)) {
6077 return 0;
6078 }
6079
6080 if (strcmp(path + strlen(path) - 4, ".six") == 0) {
6081 show_picture(vt_parser, path, 0, 0, 0, 0, 0, 0, 0,
6082 (!vt_parser->sixel_scrolling &&
6083 check_sixel_anim(vt_parser->screen, str_p, left)) ? 2 : 1);
6084 } else {
6085 /* ReGIS */
6086 int orig_flag;
6087
6088 orig_flag = vt_parser->sixel_scrolling;
6089 vt_parser->sixel_scrolling = 0;
6090 show_picture(vt_parser, path, 0, 0, 0, 0, 0, 0, 0,
6091 1 /* is_sixel (vt_parser->sixel_scrolling is applied) */);
6092 vt_parser->sixel_scrolling = orig_flag;
6093 }
6094
6095 free(path);
6096 } else
6097 #endif /* NO_IMAGE */
6098 if (*str_p == '{') {
6099 /* DECDLD */
6100
6101 u_char *param;
6102 ef_charset_t cs;
6103 int num;
6104 u_char *p;
6105 int ps[9];
6106 int idx;
6107 int is_end;
6108 u_int col_width;
6109 u_int line_height;
6110
6111 if (*dcs_beg == '\x1b') {
6112 param = dcs_beg + 2;
6113 } else /* if( *dcs_beg == '\x90') */ {
6114 param = dcs_beg + 1;
6115 }
6116
6117 for (num = 0; num < 9; num++) {
6118 u_char c;
6119
6120 p = param;
6121
6122 while ('0' <= *param && *param <= '9') {
6123 param++;
6124 }
6125
6126 c = *param;
6127 if (c != ';' && c != '{') {
6128 break;
6129 }
6130 *param = '\0';
6131 ps[num] = *p ? atoi(p) : 0;
6132 *(param++) = c; /* restore in case of restarting to parse from the begining. */
6133 }
6134
6135 if (num != 8) {
6136 if (!get_pt_in_esc_seq(&str_p, &left, 1, 0)) {
6137 return 0;
6138 }
6139 } else {
6140 char *path;
6141
6142 if (!increment_str(&str_p, &left)) {
6143 return 0;
6144 }
6145
6146 if (*str_p == ' ') {
6147 /* ESC ( SP Ft */
6148 if (!increment_str(&str_p, &left)) {
6149 return 0;
6150 }
6151 }
6152
6153 idx = ps[1];
6154
6155 if (0x30 <= *str_p && *str_p <= 0x7e) {
6156 /* Ft */
6157 if (ps[7] == 0) {
6158 cs = CS94SB_ID(*str_p);
6159 } else {
6160 cs = CS96SB_ID(*str_p);
6161 }
6162
6163 if (ps[3] <= 4 || ps[3] >= 255) {
6164 col_width = 15;
6165 } else {
6166 col_width = ps[3];
6167 }
6168
6169 if (ps[6] == 0 || ps[6] >= 255) {
6170 line_height = 12;
6171 } else {
6172 line_height = ps[6];
6173 }
6174 } else {
6175 cs = UNKNOWN_CS;
6176 col_width = line_height = 0;
6177 }
6178
6179 #ifndef NO_IMAGE
6180 if (ps[5] == 3 && cs != UNKNOWN_CS &&
6181 (path = get_home_file_path("", vt_pty_get_slave_name(vt_parser->pty) + 5,
6182 "six"))) {
6183 /* DRCS Sixel */
6184 u_char *orig_drcs_header;
6185 size_t drcs_header_len = str_p - dcs_beg + 1;
6186 u_char *orig_sixel_size = NULL;
6187 size_t sixel_size_len = 0;
6188 int tmp;
6189 int pix_width = 0;
6190 int pix_height = 0;
6191
6192 orig_drcs_header = alloca(drcs_header_len);
6193 memcpy(orig_drcs_header, dcs_beg, drcs_header_len);
6194
6195 dcs_beg = str_p - 1;
6196
6197 /* skip sixel header parameters */
6198 do {
6199 if (!increment_str(&str_p, &left)) {
6200 free(path);
6201
6202 return 0;
6203 }
6204 } while (*str_p == ';' || ('0' <= *str_p && *str_p <= '9'));
6205
6206 if (*str_p != 'q') {
6207 dcs_beg--;
6208 dcs_beg[0] = '\x1b';
6209 dcs_beg[1] = 'P';
6210 dcs_beg[2] = 'q';
6211 str_p--; /* str_p points 'q' */
6212 left++;
6213 } else {
6214 dcs_beg[0] = '\x1b';
6215 dcs_beg[1] = 'P';
6216
6217 if (left == 0) {
6218 return 0;
6219 }
6220 }
6221
6222 /*
6223 * Read width and height of sixel graphics from "Pan;Pad;Ph;Pv.
6224 * If failed, it is impossible to scale image pieces according to Pcmw and Pcmh.
6225 */
6226 if (str_p[1] == '"' && !check_cell_size(vt_parser, col_width, line_height)) {
6227 if (left < 2) { /* XXX */
6228 return 0;
6229 }
6230
6231 if (sscanf(str_p + 2, "%d;%d;%d;%d", &tmp, &tmp, &pix_width, &pix_height) == 4 &&
6232 pix_width > 0 && pix_height > 0) {
6233 sixel_size_len = 1; /* q */
6234 while (left > ++sixel_size_len &&
6235 '0' <= str_p[sixel_size_len] && str_p[sixel_size_len] <= ';');
6236 orig_sixel_size = alloca(sixel_size_len);
6237 memcpy(orig_sixel_size, str_p, sixel_size_len);
6238
6239 if (str_p[sixel_size_len] == 'q') {
6240 /*
6241 * Starting DRCS Sixel: q"Pan;Pad;Ph;Pv#...
6242 * Continuing DRCS Sixel: q"Pan;Pad;Ph;Pv\0q...
6243 */
6244 str_p += sixel_size_len;
6245 left -= sixel_size_len;
6246 }
6247 }
6248 }
6249
6250 if (!save_sixel_or_regis(vt_parser, path, dcs_beg, &str_p, &left)) {
6251 /*
6252 * q"Pan;Pad;Ph;Pvq\0...
6253 * ^^^^^^
6254 */
6255 memmove(vt_parser->r_buf.chars + drcs_header_len + sixel_size_len,
6256 vt_parser->r_buf.chars + 2 /* ESC P */,
6257 vt_parser->r_buf.filled_len - 2);
6258 /*
6259 * q"Pan;Pad;Ph;Pvq\0...
6260 * ^^^^^^^^^^^^^^^
6261 */
6262 memcpy(vt_parser->r_buf.chars + drcs_header_len, orig_sixel_size, sixel_size_len);
6263 memcpy(vt_parser->r_buf.chars, orig_drcs_header, drcs_header_len);
6264 vt_parser->r_buf.filled_len += (drcs_header_len - 2 + sixel_size_len);
6265 vt_parser->r_buf.left += (drcs_header_len - 2 + sixel_size_len);
6266
6267 return 0;
6268 }
6269
6270 define_drcs_picture(vt_parser, path, cs, idx, pix_width, pix_height,
6271 col_width, line_height);
6272
6273 free(path);
6274 } else
6275 #endif
6276 {
6277 u_char *pt = str_p;
6278 vt_drcs_font_t *font;
6279
6280 if (!get_pt_in_esc_seq(&str_p, &left, 1, 0)) {
6281 return 0;
6282 }
6283
6284 if (cs == UNKNOWN_CS) {
6285 if (ps[2] == 2) {
6286 destroy_drcs(vt_parser->drcs);
6287 }
6288 } else {
6289 if (ps[2] == 0) {
6290 vt_drcs_final(vt_parser->drcs, cs);
6291 } else if (ps[2] == 2) {
6292 vt_drcs_final_full(vt_parser->drcs);
6293 }
6294
6295 if (!vt_parser->drcs) {
6296 vt_parser->drcs = vt_drcs_new();
6297 }
6298
6299 font = vt_drcs_get_font(vt_parser->drcs, cs, 1);
6300
6301 while (1) {
6302 p = ++pt;
6303
6304 while (*pt == '/' || ('?' <= *pt && *pt <= '~')) {
6305 pt++;
6306 }
6307
6308 if (*pt) {
6309 *pt = '\0';
6310 is_end = 0;
6311 } else {
6312 is_end = 1;
6313 }
6314
6315 if (*p) {
6316 if (strlen(p) == (col_width + 1) * ((line_height + 5) / 6) - 1) {
6317 vt_drcs_add_glyph(font, idx, p, col_width, line_height);
6318 }
6319 #ifdef DEBUG
6320 else {
6321 bl_debug_printf(BL_DEBUG_TAG "DRCS illegal size %s\n", p);
6322 }
6323 #endif
6324
6325 idx++;
6326 }
6327
6328 if (is_end) {
6329 break;
6330 }
6331 }
6332 }
6333 }
6334 }
6335 } else {
6336 u_char *macro;
6337 u_char *tckey;
6338 u_char *status;
6339 u_char *present;
6340
6341 macro = tckey = status = present = NULL;
6342
6343 if ((*str_p == '!' && *(str_p + 1) == 'z') ||
6344 ((*str_p == '+' || *str_p == '$') && *(str_p + 1) == 'q') ||
6345 (*str_p == '$' && *(str_p + 1) == 't')) {
6346 if (left <= 2) {
6347 left = 0;
6348
6349 return 0;
6350 }
6351
6352 str_p += 2;
6353 left -= 2;
6354
6355 if (*(str_p - 1) == 'z' /* && *(str_p - 2) == '!' */) {
6356 /* DECDMAC */
6357 macro = str_p;
6358 } else if (*(str_p - 1) == 'q') {
6359 if (*(str_p - 2) == '$') {
6360 /* DECRQSS */
6361 status = str_p;
6362 } else {
6363 /* Termcap query */
6364 tckey = str_p;
6365 }
6366 } else /* if (*(str_p - 1) == t && *(str_p - 2) == '$') */ {
6367 /* DECRSPS */
6368 present = str_p;
6369 }
6370 } else {
6371 if (!increment_str(&str_p, &left)) {
6372 return 0;
6373 }
6374 }
6375
6376 /*
6377 * +1 in case str_p[left - vt_parser->r_buf.new_len] points
6378 * "\\" of "\x1b\\".
6379 */
6380 if (left > vt_parser->r_buf.new_len + 1) {
6381 str_p += (left - vt_parser->r_buf.new_len - 1);
6382 left = vt_parser->r_buf.new_len + 1;
6383 }
6384
6385 if (get_pt_in_esc_seq(&str_p, &left, 1, 0)) {
6386 if (macro) {
6387 define_macro(vt_parser, dcs_beg + (*dcs_beg == '\x1b' ? 2 : 1), macro);
6388 } else if (status) {
6389 report_status(vt_parser, status);
6390 } else if (tckey) {
6391 report_termcap(vt_parser, tckey);
6392 } else if (present) {
6393 set_presentation_state(vt_parser, present);
6394 }
6395 } else if (left == 0) {
6396 return 0;
6397 }
6398 }
6399 } else if (*str_p == 'X' || *str_p == '^' || *str_p == '_') {
6400 /*
6401 * "ESC X" SOS
6402 * "ESC ^" PM
6403 * "ESC _" APC
6404 */
6405 if (!inc_str_in_esc_seq(vt_parser->screen, &str_p, &left, 0)) {
6406 return 0;
6407 }
6408
6409 /* +1 in case str_p[left - new_len] points "\\" of "\x1b\\". */
6410 if (left > vt_parser->r_buf.new_len + 1) {
6411 str_p += (left - vt_parser->r_buf.new_len - 1);
6412 left = vt_parser->r_buf.new_len + 1;
6413 }
6414
6415 if (!get_pt_in_esc_seq(&str_p, &left, 1, 0) && left == 0) {
6416 return 0;
6417 }
6418 }
6419 /* Other final character */
6420 else if (0x30 <= *str_p && *str_p <= 0x7e) {
6421 #ifdef DEBUG
6422 debug_print_unknown("ESC %c\n", *str_p);
6423 #endif
6424 }
6425 /* intermediate character */
6426 else if (0x20 <= *str_p && *str_p <= 0x2f) {
6427 /*
6428 * ESC I.....I F
6429 * 033 040-057 060-176
6430 */
6431 u_int ic_num;
6432
6433 ic_num = 0;
6434
6435 /* In case more than one intermediate(0x20-0x2f) chars. */
6436 do {
6437 ic_num++;
6438
6439 if (!inc_str_in_esc_seq(vt_parser->screen, &str_p, &left, 0)) {
6440 return 0;
6441 }
6442 } while (0x20 <= *str_p && *str_p <= 0x2f);
6443
6444 if (ic_num == 1 || ic_num == 2) {
6445 if (ic_num == 1 && *(str_p - 1) == '#') {
6446 if ('3' <= *str_p && *str_p <= '6') {
6447 vt_line_t *line;
6448
6449 line = vt_screen_get_cursor_line(vt_parser->screen);
6450 if (*str_p == '3') {
6451 /*
6452 * "ESC # 3" DEC double-height line,
6453 * top half (DECDHL)
6454 */
6455 vt_line_set_size_attr(line, DOUBLE_HEIGHT_TOP);
6456 } else if (*str_p == '4') {
6457 /*
6458 * "ESC # 4" DEC double-height line,
6459 * bottom half (DECDHL)
6460 */
6461 vt_line_set_size_attr(line, DOUBLE_HEIGHT_BOTTOM);
6462 } else if (*str_p == '5') {
6463 /*
6464 * "ESC # 5" DEC single-with line (DECSWL)
6465 */
6466 vt_line_set_size_attr(line, 0);
6467 } else /* if( *str_p == '6') */
6468 {
6469 /*
6470 * "ESC # 6" DEC double-with line (DECDWL)
6471 */
6472 vt_line_set_size_attr(line, DOUBLE_WIDTH);
6473 }
6474 } else if (*str_p == '8') {
6475 /* "ESC # 8" DEC screen alignment test (DECALN) */
6476
6477 vt_screen_set_vmargin(vt_parser->screen, -1, -1);
6478 vt_screen_set_use_hmargin(vt_parser->screen, 0);
6479 vt_screen_goto(vt_parser->screen, 0, 0);
6480
6481 vt_screen_fill_area(vt_parser->screen, 'E', vt_parser->is_protected, 0, 0,
6482 vt_screen_get_logical_cols(vt_parser->screen),
6483 vt_screen_get_logical_rows(vt_parser->screen));
6484 }
6485 } else if (*(str_p - ic_num) == '(' || *(str_p - ic_num) == '$') {
6486 /*
6487 * "ESC ("(Registered CS),
6488 * "ESC ( SP"(DRCS) or "ESC $"
6489 * See vt_convert_to_internal_ch() about CS94MB_ID.
6490 */
6491
6492 if (IS_ENCODING_BASED_ON_ISO2022(vt_parser->encoding)) {
6493 /* ESC ( will be processed in mef. */
6494 return 1;
6495 }
6496
6497 vt_parser->g0 = (*(str_p - ic_num) == '$') ? CS94MB_ID(*str_p) : CS94SB_ID(*str_p);
6498
6499 if (!vt_parser->is_so) {
6500 vt_parser->gl = vt_parser->g0;
6501 }
6502 } else if (*(str_p - ic_num) == ')') {
6503 /* "ESC )"(Registered CS) or "ESC ( SP"(DRCS) */
6504
6505 if (IS_ENCODING_BASED_ON_ISO2022(vt_parser->encoding)) {
6506 /* ESC ) will be processed in mef. */
6507 return 1;
6508 }
6509
6510 vt_parser->g1 = (*(str_p - ic_num) == '$') ? CS94MB_ID(*str_p) : CS94SB_ID(*str_p);
6511
6512 if (vt_parser->is_so) {
6513 vt_parser->gl = vt_parser->g1;
6514 }
6515 } else if (*(str_p - ic_num) == '-') {
6516 /* "ESC -"(Registered CS) or "ESC - SP"(DRCS) */
6517
6518 if (IS_ENCODING_BASED_ON_ISO2022(vt_parser->encoding)) {
6519 /* ESC ) will be processed in mef. */
6520 return 1;
6521 }
6522
6523 vt_parser->g1 = CS96SB_ID(*str_p);
6524
6525 if (vt_parser->is_so) {
6526 vt_parser->gl = vt_parser->g1;
6527 }
6528 } else {
6529 /*
6530 * "ESC SP F", "ESC SP G", "ESC SP L", "ESC SP M",
6531 * "ESC SP N" etc ...
6532 */
6533 }
6534 }
6535 } else {
6536 /* not VT100 control sequence. */
6537
6538 #ifdef ESCSEQ_DEBUG
6539 bl_msg_printf("=> not VT100 control sequence.\n");
6540 #endif
6541
6542 return 1;
6543 }
6544
6545 #ifdef ESCSEQ_DEBUG
6546 bl_msg_printf("\n");
6547 #endif
6548 } else if (*str_p == CTL_SI) {
6549 if (IS_ENCODING_BASED_ON_ISO2022(vt_parser->encoding)) {
6550 /* SI will be processed in mef. */
6551 return 1;
6552 }
6553
6554 #ifdef ESCSEQ_DEBUG
6555 bl_debug_printf(BL_DEBUG_TAG " receiving SI\n");
6556 #endif
6557
6558 vt_parser->gl = vt_parser->g0;
6559 vt_parser->is_so = 0;
6560 } else if (*str_p == CTL_SO) {
6561 if (IS_ENCODING_BASED_ON_ISO2022(vt_parser->encoding)) {
6562 /* SO will be processed in mef. */
6563 return 1;
6564 }
6565
6566 #ifdef ESCSEQ_DEBUG
6567 bl_debug_printf(BL_DEBUG_TAG " receiving SO\n");
6568 #endif
6569
6570 vt_parser->gl = vt_parser->g1;
6571 vt_parser->is_so = 1;
6572 } else if (CTL_LF <= *str_p && *str_p <= CTL_FF) {
6573 #ifdef ESCSEQ_DEBUG
6574 bl_debug_printf(BL_DEBUG_TAG " receiving LF\n");
6575 #endif
6576
6577 vt_screen_line_feed(vt_parser->screen);
6578 if (AUTO_CR(vt_parser)) {
6579 vt_screen_goto_beg_of_line(vt_parser->screen);
6580 }
6581 } else if (*str_p == CTL_CR) {
6582 #ifdef ESCSEQ_DEBUG
6583 bl_debug_printf(BL_DEBUG_TAG " receiving CR\n");
6584 #endif
6585
6586 vt_screen_goto_beg_of_line(vt_parser->screen);
6587 } else if (*str_p == CTL_TAB) {
6588 #ifdef ESCSEQ_DEBUG
6589 bl_debug_printf(BL_DEBUG_TAG " receiving TAB\n");
6590 #endif
6591
6592 vt_screen_forward_tabs(vt_parser->screen, 1);
6593 } else if (*str_p == CTL_BS) {
6594 #ifdef ESCSEQ_DEBUG
6595 bl_debug_printf(BL_DEBUG_TAG " receiving BS\n");
6596 #endif
6597
6598 vt_screen_go_back(vt_parser->screen, 1, 0);
6599 } else if (*str_p == CTL_BEL) {
6600 #ifdef ESCSEQ_DEBUG
6601 bl_debug_printf(BL_DEBUG_TAG " receiving BEL\n");
6602 #endif
6603
6604 if (HAS_XTERM_LISTENER(vt_parser, bel)) {
6605 stop_vt100_cmd(vt_parser, 0);
6606 (*vt_parser->xterm_listener->bel)(vt_parser->xterm_listener->self);
6607 /*
6608 * XXX
6609 * start_vt100_cmd( ... , *1*) erases cursor which
6610 * xterm_listener::bell drew if bell mode is visual.
6611 */
6612 start_vt100_cmd(vt_parser, 1);
6613 }
6614 } else if (*str_p == 0x90) {
6615 goto parse_dcs;
6616 } else if (*str_p == 0x18) {
6617 if (vt_parser->r_buf.left < 3) {
6618 return 0;
6619 }
6620
6621 if (memcmp(str_p + 1, "B01", 3) == 0) {
6622 vt_parser->is_zmodem_ready = 1; /* rz */
6623 }
6624 #if 0
6625 else if (memcmp(str_p + 1, "B00", 3) == 0) {
6626 vt_parser->is_zmodem_ready = 2; /* sz */
6627 }
6628 #endif
6629 } else {
6630 /* not VT100 control sequence */
6631
6632 return 1;
6633 }
6634
6635 #ifdef EDIT_DEBUG
6636 vt_edit_dump(vt_parser->screen->edit);
6637 #endif
6638
6639 vt_parser->r_buf.left = left - 1;
6640
6641 return 1;
6642 }
6643
parse_vt100_sequence(vt_parser_t * vt_parser)6644 static int parse_vt100_sequence(vt_parser_t *vt_parser) {
6645 ef_char_t ch;
6646 size_t prev_left;
6647
6648 while (1) {
6649 prev_left = vt_parser->r_buf.left;
6650
6651 /*
6652 * parsing character encoding.
6653 */
6654 (*vt_parser->cc_parser->set_str)(vt_parser->cc_parser, CURRENT_STR_P(vt_parser),
6655 vt_parser->r_buf.left);
6656 while ((*vt_parser->cc_parser->next_char)(vt_parser->cc_parser, &ch)) {
6657 int ret;
6658 ef_charset_t orig_cs;
6659
6660 orig_cs = ch.cs;
6661 ret = vt_convert_to_internal_ch(vt_parser, &ch);
6662
6663 if (ret == 1) {
6664 if (vt_parser->gl != US_ASCII && orig_cs == US_ASCII) {
6665 orig_cs = vt_parser->gl;
6666 }
6667
6668 if (vt_parser->cs != orig_cs) {
6669 vt_parser->cs = orig_cs;
6670 }
6671
6672 #if !defined(NO_DYNAMIC_LOAD_CTL) || defined(USE_IND)
6673 if (IS_ISCII(ch.cs) && ch.size == 2) {
6674 ch.size = 1;
6675 put_char(vt_parser, ef_char_to_int(&ch), ch.cs, ch.property);
6676 ch.ch[0] = ch.ch[1];
6677 /* nukta is always combined. */
6678 ch.property |= EF_COMBINING;
6679 }
6680 #endif
6681
6682 put_char(vt_parser, ef_char_to_int(&ch), ch.cs, ch.property);
6683
6684 vt_parser->r_buf.left = vt_parser->cc_parser->left;
6685 } else if (ret == -1) {
6686 /*
6687 * This is a control sequence (C0 or C1), so
6688 * reparsing this char in vt100_escape_sequence() ...
6689 */
6690
6691 vt_parser->cc_parser->left++;
6692 vt_parser->cc_parser->is_eos = 0;
6693
6694 break;
6695 }
6696 }
6697
6698 vt_parser->r_buf.left = vt_parser->cc_parser->left;
6699
6700 flush_buffer(vt_parser);
6701
6702 if (vt_parser->cc_parser->is_eos) {
6703 /* expect more input */
6704 break;
6705 }
6706
6707 /*
6708 * parsing other vt100 sequences.
6709 * (vt_parser->w_buf is always flushed here.)
6710 */
6711
6712 if (!parse_vt100_escape_sequence(vt_parser)) {
6713 /* expect more input */
6714 break;
6715 }
6716
6717 #ifdef EDIT_ROUGH_DEBUG
6718 vt_edit_dump(vt_parser->screen->edit);
6719 #endif
6720
6721 if (vt_parser->r_buf.left == prev_left) {
6722 #ifdef DEBUG
6723 bl_debug_printf(BL_DEBUG_TAG " unrecognized sequence[%.2x] is received , ignored...\n",
6724 *CURRENT_STR_P(vt_parser));
6725 #endif
6726
6727 vt_parser->r_buf.left--;
6728 }
6729
6730 if (vt_parser->r_buf.left == 0) {
6731 break;
6732 }
6733 }
6734
6735 /*
6736 * If only one window is shown on screen, it is not necessary to process
6737 * pending events for other windows.
6738 * But multiple windows can be shown even on framebuffer now, so it is
6739 * commented out.
6740 */
6741 #if 0
6742 if (vt_parser->yield) {
6743 vt_parser->yield = 0;
6744
6745 return 0;
6746 }
6747 #endif
6748
6749 return 1;
6750 }
6751
write_loopback(vt_parser_t * vt_parser,const u_char * buf,size_t len,int enable_local_echo,int is_visual)6752 static int write_loopback(vt_parser_t *vt_parser, const u_char *buf, size_t len,
6753 int enable_local_echo,
6754 int is_visual /* 1: stop_vt100_cmd(1), -1: stop_vt100_cmd(0) */
6755 ) {
6756 char *orig_buf;
6757 size_t orig_left;
6758
6759 if (!vt_parser->pty || /* vt_term_write_loopback() in open_pty_intern() in ui_screen_manager.c can
6760 * be called when vt_parser->pty is NULL */
6761 vt_pty_get_master_fd(vt_parser->pty) != -1) {
6762 if (vt_parser->r_buf.len < len && !change_read_buffer_size(&vt_parser->r_buf, len)) {
6763 return 0;
6764 }
6765
6766 if ((orig_left = vt_parser->r_buf.left) > 0) {
6767 if (!(orig_buf = alloca(orig_left))) {
6768 return 0;
6769 }
6770
6771 memcpy(orig_buf, CURRENT_STR_P(vt_parser), orig_left);
6772 }
6773
6774 memcpy(vt_parser->r_buf.chars, buf, len);
6775 vt_parser->r_buf.filled_len = vt_parser->r_buf.left = vt_parser->r_buf.new_len = len;
6776 } else {
6777 /* for vterm compatible library */
6778
6779 if (vt_parser->r_buf.len < len + vt_parser->r_buf.left &&
6780 !change_read_buffer_size(&vt_parser->r_buf, len + vt_parser->r_buf.left)) {
6781 return 0;
6782 }
6783
6784 memmove(vt_parser->r_buf.chars,
6785 vt_parser->r_buf.chars + vt_parser->r_buf.filled_len - vt_parser->r_buf.left,
6786 vt_parser->r_buf.left);
6787 memcpy(vt_parser->r_buf.chars + vt_parser->r_buf.left, buf, len);
6788 vt_parser->r_buf.filled_len = (vt_parser->r_buf.left += len);
6789 vt_parser->r_buf.new_len = len;
6790 orig_left = 0;
6791 }
6792
6793 if (is_visual) {
6794 start_vt100_cmd(vt_parser, 1);
6795 }
6796
6797 if (enable_local_echo) {
6798 vt_screen_enable_local_echo(vt_parser->screen);
6799 }
6800
6801 /*
6802 * bidi and visual-indian is always stopped from here.
6803 * If you want to call {start|stop}_vt100_cmd (where vt_xterm_event_listener
6804 * is called),
6805 * the second argument of it shoule be 0.
6806 */
6807 parse_vt100_sequence(vt_parser);
6808
6809 if (is_visual) {
6810 stop_vt100_cmd(vt_parser, is_visual > 0);
6811 }
6812
6813 if (orig_left > 0) {
6814 memcpy(vt_parser->r_buf.chars, orig_buf, orig_left);
6815 vt_parser->r_buf.filled_len = vt_parser->r_buf.left = orig_left;
6816 }
6817
6818 return 1;
6819 }
6820
local_echo(vt_parser_t * vt_parser,const u_char * buf,size_t len)6821 static void local_echo(vt_parser_t *vt_parser, const u_char *buf, size_t len) {
6822 size_t count;
6823
6824 if (len == 1) {
6825 if (vt_parser->prev_local_echo_char == buf[0]) {
6826 vt_screen_local_echo_wait(vt_parser->screen, 0);
6827 vt_parse_vt100_sequence(vt_parser);
6828
6829 return;
6830 } else {
6831 vt_parser->prev_local_echo_char = buf[0];
6832 }
6833 } else {
6834 vt_parser->prev_local_echo_char = 0;
6835 }
6836
6837 for (count = 0; count < len; count++) {
6838 if (buf[count] < 0x20) {
6839 vt_screen_local_echo_wait(vt_parser->screen, 0);
6840 vt_parse_vt100_sequence(vt_parser);
6841
6842 return;
6843 }
6844 }
6845
6846 vt_parse_vt100_sequence(vt_parser);
6847
6848 if (!(vt_parser->line_style & LS_UNDERLINE)) {
6849 char *new_buf;
6850 size_t new_len;
6851
6852 if ((new_buf = alloca((new_len = 4 + len + 5)))) {
6853 memcpy(new_buf, "\x1b[4m", 4);
6854 memcpy(new_buf + 4, buf, len);
6855 memcpy(new_buf + 4 + len, "\x1b[24m", 5);
6856 buf = new_buf;
6857 len = new_len;
6858 }
6859 }
6860
6861 write_loopback(vt_parser, buf, len, 1, 1);
6862 }
6863
is_transferring_data(vt_parser_t * vt_parser)6864 static int is_transferring_data(vt_parser_t *vt_parser) {
6865 int progress_cur;
6866 int progress_len;
6867 int state;
6868 vt_char_t *bar;
6869
6870 if ((state = vt_transfer_get_state(&progress_cur, &progress_len)) >= 0 &&
6871 (bar = alloca(sizeof(vt_char_t) * (progress_len + 2)))) {
6872 int count;
6873
6874 start_vt100_cmd(vt_parser, 1);
6875
6876 if (progress_cur == 0) {
6877 char *msg;
6878 char *p1;
6879 char *p2;
6880 size_t len;
6881 size_t pre_len;
6882
6883 if (vt_parser->is_transferring_data == 0x1) {
6884 pre_len = 5;
6885 p1 = "Send ";
6886 p2 = send_file ? send_file : "";
6887 } else {
6888 pre_len = 8;
6889 p1 = "Save in ";
6890 p2 = recv_dir ? recv_dir : "~/.mlterm/recv";
6891 }
6892
6893 len = 10 + pre_len + strlen(p2);
6894 if ((msg = alloca(len + 1))) {
6895 memcpy(msg, "\r\nZMODEM: ", 10);
6896 memcpy(msg + 10, p1, pre_len);
6897 strcpy(msg + 10 + pre_len, p2);
6898 }
6899 write_loopback(vt_parser, msg, len, 0, 0);
6900 vt_screen_line_feed(vt_parser->screen);
6901 }
6902
6903 vt_screen_goto_beg_of_line(vt_parser->screen);
6904 vt_screen_clear_line_to_right(vt_parser->screen);
6905
6906 vt_str_init(bar, progress_len + 2);
6907 vt_char_set(bar, '|', US_ASCII, 0, 0, 0, VT_FG_COLOR, VT_BG_COLOR, 0, 0, 0, 0, 0);
6908
6909 for (count = 0; count < progress_cur; count++) {
6910 vt_char_set(bar + 1 + count, '*', US_ASCII, 0, 0, 0, VT_FG_COLOR, VT_BG_COLOR, 0, 0, 0, 0, 0);
6911 }
6912 for (; count < progress_len; count++) {
6913 vt_char_set(bar + 1 + count, ' ', US_ASCII, 0, 0, 0, VT_FG_COLOR, VT_BG_COLOR, 0, 0, 0, 0, 0);
6914 }
6915 vt_char_set(bar + 1 + progress_len, '|', US_ASCII, 0, 0, 0, VT_FG_COLOR, VT_BG_COLOR,
6916 0, 0, 0, 0, 0);
6917
6918 vt_screen_overwrite_chars(vt_parser->screen, bar, progress_len + 2);
6919
6920 if (state == 0) {
6921 vt_screen_line_feed(vt_parser->screen);
6922 vt_screen_goto_beg_of_line(vt_parser->screen);
6923
6924 stop_vt100_cmd(vt_parser, 1);
6925
6926 vt_parser->is_transferring_data = 0;
6927
6928 return 0;
6929 }
6930
6931 stop_vt100_cmd(vt_parser, 1);
6932 }
6933
6934 return 1;
6935 }
6936
6937 /* sending or receiving data via zmodem */
transfer_data(vt_parser_t * vt_parser)6938 static void transfer_data(vt_parser_t *vt_parser) {
6939 receive_bytes(vt_parser);
6940
6941 do {
6942 u_char input[4096];
6943 u_char output[(2 * (1024 + 4 + 1)) + 1];
6944 u_int len = 0;
6945 size_t copy_len;
6946
6947 if ((copy_len = vt_parser->r_buf.left) > sizeof(input) - 1) {
6948 copy_len = sizeof(input) - 1;
6949 }
6950
6951 memcpy(input, CURRENT_STR_P(vt_parser), copy_len);
6952 input[copy_len] = '\0';
6953
6954 if ((vt_parser->r_buf.left -= copy_len) > 0) {
6955 memmove(vt_parser->r_buf.chars, CURRENT_STR_P(vt_parser), vt_parser->r_buf.left);
6956 vt_parser->r_buf.filled_len = vt_parser->r_buf.left;
6957 }
6958
6959 vt_transfer_data(input, copy_len, output, &len, sizeof(output));
6960
6961 if (len > 0) {
6962 vt_write_to_pty(vt_parser->pty, output, len);
6963 }
6964 } while (is_transferring_data(vt_parser) && receive_bytes(vt_parser) > 0);
6965 }
6966
6967 /* This function assumes vt_pty_is_loopback(vt_parser->pty) is false if do_zcan is true. */
transfer_cancel(vt_parser_t * vt_parser,int do_zcan)6968 static void transfer_cancel(vt_parser_t *vt_parser, int do_zcan) {
6969 if (vt_parser->is_transferring_data) {
6970 vt_parser->is_transferring_data = 0;
6971 vt_parser->r_buf.left = 0;
6972 vt_transfer_cancel();
6973 }
6974 #if 0
6975 else if (vt_parser->is_zmodem_ready == 0) {
6976 return;
6977 }
6978 #endif
6979
6980 vt_parser->is_zmodem_ready = 0;
6981
6982 if (do_zcan) {
6983 vt_write_to_pty(vt_parser->pty,
6984 "**\x18\x18\x18\x18\x18\x18\x18\x18"
6985 "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08", 20);
6986 }
6987 }
6988
convert_to_locale_encoding(char * str,ef_parser_t * parser,vt_char_encoding_t encoding)6989 static char *convert_to_locale_encoding(char *str, ef_parser_t *parser,
6990 vt_char_encoding_t encoding) {
6991 vt_char_encoding_t locale_encoding;
6992 char *new_str;
6993 size_t len = strlen(str);
6994
6995 if ((locale_encoding = vt_get_char_encoding(bl_get_codeset())) == VT_UNKNOWN_ENCODING) {
6996 locale_encoding = encoding;
6997 }
6998
6999 if (locale_encoding == encoding || (new_str = alloca(len * 2 + 1)) == NULL) {
7000 new_str = str;
7001 } else {
7002 if (parser) {
7003 (*parser->init)(parser);
7004 (*parser->set_str)(parser, str, len);
7005 new_str[vt_char_encoding_convert_with_parser(new_str, len * 2, locale_encoding,
7006 parser)] = '\0';
7007 } else {
7008 new_str[vt_char_encoding_convert(new_str, len * 2, locale_encoding,
7009 str, len - 5, encoding)] = '\0';
7010 }
7011 }
7012
7013 return strdup(new_str);
7014 }
7015
7016 /* --- global functions --- */
7017
vt_set_use_alt_buffer(int use)7018 void vt_set_use_alt_buffer(int use) { use_alt_buffer = use; }
7019
vt_set_unicode_noconv_areas(char * areas)7020 void vt_set_unicode_noconv_areas(char *areas) {
7021 unicode_noconv_areas =
7022 set_area_to_table(unicode_noconv_areas, &num_unicode_noconv_areas, areas);
7023 }
7024
vt_set_full_width_areas(char * areas)7025 void vt_set_full_width_areas(char *areas) {
7026 full_width_areas = set_area_to_table(full_width_areas, &num_full_width_areas, areas);
7027 }
7028
vt_set_half_width_areas(char * areas)7029 void vt_set_half_width_areas(char *areas) {
7030 half_width_areas = set_area_to_table(half_width_areas, &num_half_width_areas, areas);
7031 }
7032
vt_set_use_ttyrec_format(int use)7033 void vt_set_use_ttyrec_format(int use) { use_ttyrec_format = use; }
7034
7035 #ifdef USE_LIBSSH2
vt_set_use_scp_full(int use)7036 void vt_set_use_scp_full(int use) {
7037 if (use >= 0) {
7038 use_scp_full = use;
7039 } else if (use == -1) {
7040 if (use_scp_full == 0) {
7041 use_scp_full = -1;
7042 } else if (use_scp_full == -1) {
7043 use_scp_full = 0;
7044 }
7045 }
7046 }
7047 #endif
7048
vt_set_recv_dir(const char * dir)7049 void vt_set_recv_dir(const char *dir) {
7050 if (strstr(dir, "..")) {
7051 /* insecure dir name */
7052 bl_msg_printf("%s is insecure dir name.\n", dir);
7053 } else {
7054 free(recv_dir);
7055 recv_dir = strdup(dir);
7056 }
7057 }
7058
vt_set_timeout_read_pty(u_long timeout)7059 void vt_set_timeout_read_pty(u_long timeout) { timeout_read_pty = timeout; }
7060
vt_set_primary_da(char * da)7061 void vt_set_primary_da(char *da) {
7062 free(primary_da);
7063 primary_da = strdup(da);
7064 }
7065
vt_set_secondary_da(char * da)7066 void vt_set_secondary_da(char *da) {
7067 free(secondary_da);
7068 secondary_da = strdup(da);
7069 }
7070
vt_set_local_echo_wait(u_int msec)7071 void vt_set_local_echo_wait(u_int msec) {
7072 local_echo_wait_msec = msec;
7073 }
7074
vt_parser_final(void)7075 void vt_parser_final(void) {
7076 vt_config_proto_final();
7077
7078 free(unicode_noconv_areas);
7079 num_unicode_noconv_areas = 0;
7080
7081 free(full_width_areas);
7082 num_full_width_areas = 0;
7083
7084 free(half_width_areas);
7085 num_half_width_areas = 0;
7086
7087 vt_set_auto_detect_encodings("");
7088 }
7089
vt_parser_new(vt_screen_t * screen,vt_termcap_ptr_t termcap,vt_char_encoding_t encoding,int is_auto_encoding,int use_auto_detect,int logging_vt_seq,vt_unicode_policy_t policy,u_int col_size_a,int use_char_combining,int use_multi_col_char,const char * win_name,const char * icon_name,int use_ansi_colors,vt_alt_color_mode_t alt_color_mode,vt_cursor_style_t cursor_style,int ignore_broadcasted_chars,int use_local_echo)7090 vt_parser_t *vt_parser_new(vt_screen_t *screen, vt_termcap_ptr_t termcap, vt_char_encoding_t encoding,
7091 int is_auto_encoding, int use_auto_detect, int logging_vt_seq,
7092 vt_unicode_policy_t policy, u_int col_size_a, int use_char_combining,
7093 int use_multi_col_char, const char *win_name, const char *icon_name,
7094 int use_ansi_colors, vt_alt_color_mode_t alt_color_mode,
7095 vt_cursor_style_t cursor_style, int ignore_broadcasted_chars, int use_local_echo) {
7096 vt_parser_t *vt_parser;
7097
7098 if ((vt_parser = calloc(1, sizeof(vt_parser_t))) == NULL) {
7099 return NULL;
7100 }
7101
7102 vt_str_init(vt_parser->w_buf.chars, PTY_WR_BUFFER_SIZE);
7103 vt_parser->w_buf.output_func = vt_screen_overwrite_chars;
7104
7105 vt_parser->screen = screen;
7106 vt_parser->termcap = termcap;
7107
7108 vt_parser->log_file = -1;
7109
7110 vt_parser->cs = UNKNOWN_CS;
7111 vt_parser->fg_color = VT_FG_COLOR;
7112 vt_parser->bg_color = VT_BG_COLOR;
7113 vt_parser->use_char_combining = use_char_combining;
7114 vt_parser->use_multi_col_char = use_multi_col_char;
7115 vt_parser->is_auto_encoding = is_auto_encoding;
7116 vt_parser->use_auto_detect = use_auto_detect;
7117 vt_parser->logging_vt_seq = logging_vt_seq;
7118 vt_parser->unicode_policy = policy;
7119 vt_parser->cursor_style = cursor_style;
7120 vt_parser->is_visible_cursor = 1;
7121 vt_parser->hide_pointer_mode = 2; /* Compatible with xterm 344 */
7122
7123 if ((vt_parser->cc_conv = vt_char_encoding_conv_new(encoding)) == NULL) {
7124 goto error;
7125 }
7126
7127 if ((vt_parser->cc_parser = vt_char_encoding_parser_new(encoding)) == NULL) {
7128 goto error;
7129 }
7130
7131 vt_parser->encoding = encoding;
7132
7133 if (win_name) {
7134 vt_parser->win_name = strdup(win_name);
7135 }
7136
7137 if (icon_name) {
7138 vt_parser->icon_name = strdup(icon_name);
7139 }
7140
7141 vt_parser->gl = US_ASCII;
7142 vt_parser->g0 = US_ASCII;
7143 vt_parser->g1 = US_ASCII;
7144
7145 set_col_size_of_width_a(vt_parser, col_size_a);
7146
7147 /* Default value of modify_*_keys except modify_other_keys is 2. */
7148 vt_parser->modify_cursor_keys = 2;
7149 vt_parser->modify_function_keys = 2;
7150
7151 vt_parser->sixel_scrolling = 1;
7152 vt_parser->use_ansi_colors = use_ansi_colors;
7153 vt_parser->alt_color_mode = alt_color_mode;
7154 vt_parser->saved_vtmode_flags[0] = vt_parser->vtmode_flags[0] = INITIAL_VTMODE_FLAGS_0;
7155 vt_parser->saved_vtmode_flags[1] = vt_parser->vtmode_flags[1] = INITIAL_VTMODE_FLAGS_1;
7156 vt_parser->ignore_broadcasted_chars = ignore_broadcasted_chars;
7157 vt_parser->use_local_echo = use_local_echo;
7158
7159 return vt_parser;
7160
7161 error:
7162 if (vt_parser->cc_conv) {
7163 (*vt_parser->cc_conv->destroy)(vt_parser->cc_conv);
7164 }
7165
7166 if (vt_parser->cc_parser) {
7167 (*vt_parser->cc_parser->destroy)(vt_parser->cc_parser);
7168 }
7169
7170 free(vt_parser);
7171
7172 return NULL;
7173 }
7174
vt_parser_destroy(vt_parser_t * vt_parser)7175 int vt_parser_destroy(vt_parser_t *vt_parser) {
7176 vt_str_final(vt_parser->w_buf.chars, PTY_WR_BUFFER_SIZE);
7177 (*vt_parser->cc_parser->destroy)(vt_parser->cc_parser);
7178 (*vt_parser->cc_conv->destroy)(vt_parser->cc_conv);
7179 destroy_drcs(vt_parser->drcs);
7180 destroy_all_macros(vt_parser);
7181 free(vt_parser->sixel_palette);
7182
7183 if (vt_parser->log_file != -1) {
7184 close(vt_parser->log_file);
7185 }
7186
7187 free(vt_parser->r_buf.chars);
7188
7189 free(vt_parser->win_name);
7190 free(vt_parser->icon_name);
7191 free(vt_parser->saved_win_names.names);
7192 free(vt_parser->saved_icon_names.names);
7193
7194 free(vt_parser);
7195
7196 return 1;
7197 }
7198
vt_parser_set_pty(vt_parser_t * vt_parser,vt_pty_t * pty)7199 void vt_parser_set_pty(vt_parser_t *vt_parser, vt_pty_t *pty) {
7200 #ifdef USE_LIBSSH2
7201 /* See set_col_size_of_width_a() */
7202 if (!vt_parser->pty && vt_pty_get_mode(pty) == PTY_MOSH) {
7203 #ifdef USE_WIN32API
7204 char *env = getenv("MOSH_AWIDTH");
7205
7206 if (!env) {
7207 putenv(vt_parser->col_size_of_width_a == 2 ? "MOSH_AWIDTH=2" : "MOSH_AWIDTH=1");
7208 } else {
7209 vt_parser->col_size_of_width_a = (*env == '2' ? 2 : 1);
7210 }
7211 #else
7212 vt_parser->col_size_of_width_a = (wcwidth(0x25a0) == 2) ? 2 : 1;
7213 #endif
7214 }
7215 #endif
7216
7217 vt_parser->pty = pty;
7218 }
7219
vt_parser_set_xterm_listener(vt_parser_t * vt_parser,vt_xterm_event_listener_t * xterm_listener)7220 void vt_parser_set_xterm_listener(vt_parser_t *vt_parser,
7221 vt_xterm_event_listener_t *xterm_listener) {
7222 vt_parser->xterm_listener = xterm_listener;
7223 }
7224
vt_parser_set_config_listener(vt_parser_t * vt_parser,vt_config_event_listener_t * config_listener)7225 void vt_parser_set_config_listener(vt_parser_t *vt_parser,
7226 vt_config_event_listener_t *config_listener) {
7227 vt_parser->config_listener = config_listener;
7228 }
7229
vt_parse_vt100_sequence(vt_parser_t * vt_parser)7230 int vt_parse_vt100_sequence(vt_parser_t *vt_parser) {
7231 clock_t beg;
7232
7233 if (vt_parser->is_transferring_data) {
7234 /* vt_parser->pty is always non-NULL value. */
7235 transfer_data(vt_parser);
7236
7237 return 1;
7238 }
7239
7240 if (vt_screen_local_echo_wait(vt_parser->screen, local_echo_wait_msec)) {
7241 return 1;
7242 }
7243
7244 if (!vt_parser->pty || receive_bytes(vt_parser) == 0) {
7245 return 0;
7246 }
7247
7248 beg = clock();
7249
7250 start_vt100_cmd(vt_parser, 1);
7251
7252 vt_screen_disable_local_echo(vt_parser->screen);
7253
7254 /*
7255 * bidi and visual-indian is always stopped from here.
7256 * If you want to call {start|stop}_vt100_cmd (where vt_xterm_event_listener
7257 * is called),
7258 * the second argument of it shoule be 0.
7259 */
7260
7261 while (parse_vt100_sequence(vt_parser) &&
7262 !vt_parser->is_transferring_data &&
7263 /* (PTY_RD_BUFFER_SIZE / 2) is baseless. */
7264 vt_parser->r_buf.filled_len >= (PTY_RD_BUFFER_SIZE / 2) &&
7265 clock() - beg < timeout_read_pty && receive_bytes(vt_parser))
7266 ;
7267
7268 stop_vt100_cmd(vt_parser, 1);
7269
7270 return 1;
7271 }
7272
vt_parser_write(vt_parser_t * vt_parser,u_char * buf,size_t len)7273 size_t vt_parser_write(vt_parser_t *vt_parser, u_char *buf, size_t len) {
7274 if (vt_parser->is_transferring_data) {
7275 return 0;
7276 }
7277
7278 if (vt_parser->use_local_echo) {
7279 local_echo(vt_parser, buf, len);
7280 }
7281
7282 if (!SEND_RECV_MODE(vt_parser)) {
7283 write_loopback(vt_parser, buf, len, 0, 1);
7284 }
7285
7286 return vt_write_to_pty(vt_parser->pty, buf, len);
7287 }
7288
vt_parser_write_modified_key(vt_parser_t * vt_parser,int key,int modcode)7289 int vt_parser_write_modified_key(vt_parser_t *vt_parser,
7290 int key, /* 0 < key < 0x80 */
7291 int modcode) {
7292 if (vt_parser->is_transferring_data) {
7293 return 0;
7294 }
7295
7296 if (vt_parser->modify_other_keys == 1) {
7297 if ((modcode == 5 /* Control */ || modcode == 6 /* Shift+Control */) &&
7298 (('@' <= key && key <= 0x7e) || ('2' <= key && key <= '8') || key == '/' || key == ' ')) {
7299 return 0;
7300 }
7301 } else if (vt_parser->modify_other_keys != 2) {
7302 return 0;
7303 }
7304
7305 if (!((modcode - 1) == 1 /* is shift */ &&
7306 (('!' <= key && key < 'A') || ('Z' < key && key < 'a') || ('z' < key && key <= '~')))) {
7307 size_t len;
7308
7309 #if 1
7310 char buf[10];
7311
7312 /* formatOtherKeys = 1 */
7313 sprintf(buf, "\x1b[%d;%du", key, modcode);
7314 #else
7315 char buf[12];
7316
7317 /* formatOtherKeys = 0 */
7318 sprintf(buf, "\x1b[27;%d;%d", modcode, key);
7319 #endif
7320
7321 len = strlen(buf);
7322
7323 if (!SEND_RECV_MODE(vt_parser)) {
7324 write_loopback(vt_parser, buf, len, 0, 1);
7325 }
7326
7327 vt_write_to_pty(vt_parser->pty, buf, len);
7328
7329 return 1;
7330 }
7331
7332 return 0;
7333 }
7334
vt_parser_write_special_key(vt_parser_t * vt_parser,vt_special_key_t key,int modcode,int is_numlock)7335 int vt_parser_write_special_key(vt_parser_t *vt_parser, vt_special_key_t key,
7336 int modcode, int is_numlock) {
7337 char *buf;
7338
7339 if (vt_parser->is_transferring_data) {
7340 return 0;
7341 }
7342
7343 if ((buf = vt_termcap_special_key_to_seq(vt_parser->termcap, key, modcode,
7344 (vt_parser->is_app_keypad && !is_numlock),
7345 IS_APP_CURSOR_KEYS(vt_parser), IS_APP_ESCAPE(vt_parser),
7346 vt_parser->modify_cursor_keys, vt_parser->modify_function_keys))) {
7347 size_t len = strlen(buf);
7348
7349 if (!SEND_RECV_MODE(vt_parser)) {
7350 write_loopback(vt_parser, buf, len, 0, 1);
7351 }
7352
7353 vt_write_to_pty(vt_parser->pty, buf, len);
7354
7355 return 1;
7356 } else {
7357 return 0;
7358 }
7359 }
7360
vt_parser_write_loopback(vt_parser_t * vt_parser,const u_char * buf,size_t len)7361 int vt_parser_write_loopback(vt_parser_t *vt_parser, const u_char *buf, size_t len) {
7362 return write_loopback(vt_parser, buf, len, 0, 1);
7363 }
7364
vt_parser_show_message(vt_parser_t * vt_parser,char * msg)7365 int vt_parser_show_message(vt_parser_t *vt_parser, char *msg) {
7366 char *buf;
7367 size_t len;
7368
7369 if (!(buf = alloca((len = 3 + strlen(msg) + 4)))) {
7370 return 0;
7371 }
7372
7373 if (vt_screen_is_local_echo_mode(vt_parser->screen)) {
7374 sprintf(buf, "\r\n%s\x1b[K", msg);
7375
7376 return write_loopback(vt_parser, buf, len - 2, 0, -1);
7377 } else {
7378 sprintf(buf, "\x1b[H%s\x1b[K", msg);
7379
7380 return write_loopback(vt_parser, buf, len - 1, 1, -1);
7381 }
7382 }
7383
7384 #if 1 /* defined(__ANDROID__) || defined(__APPLE__) || defined(USE_SDL2) */
vt_parser_preedit(vt_parser_t * vt_parser,const u_char * buf,size_t len)7385 int vt_parser_preedit(vt_parser_t *vt_parser, const u_char *buf, size_t len) {
7386 if (!(vt_parser->line_style & LS_UNDERLINE)) {
7387 char *new_buf;
7388 size_t new_len;
7389
7390 if ((new_buf = alloca((new_len = 4 + len + 5)))) {
7391 memcpy(new_buf, "\x1b[4m", 4);
7392 memcpy(new_buf + 4, buf, len);
7393 memcpy(new_buf + 4 + len, "\x1b[24m", 5);
7394 buf = new_buf;
7395 len = new_len;
7396 }
7397 }
7398
7399 return write_loopback(vt_parser, buf, len, 1, 1);
7400 }
7401 #endif
7402
vt_parser_change_encoding(vt_parser_t * vt_parser,vt_char_encoding_t encoding)7403 int vt_parser_change_encoding(vt_parser_t *vt_parser, vt_char_encoding_t encoding) {
7404 ef_parser_t *cc_parser;
7405 ef_conv_t *cc_conv;
7406
7407 cc_conv = vt_char_encoding_conv_new(encoding);
7408 cc_parser = vt_char_encoding_parser_new(encoding);
7409
7410 if (cc_parser == NULL || cc_conv == NULL) {
7411 #ifdef DEBUG
7412 bl_warn_printf(BL_DEBUG_TAG " encoding not changed.\n");
7413 #endif
7414 if (cc_parser) {
7415 (*cc_parser->destroy)(cc_parser);
7416 }
7417
7418 if (cc_conv) {
7419 (*cc_conv->destroy)(cc_conv);
7420 }
7421
7422 return 0;
7423 }
7424
7425 #ifdef DEBUG
7426 bl_warn_printf(BL_DEBUG_TAG " encoding changed.\n");
7427 #endif
7428
7429 (*vt_parser->cc_parser->destroy)(vt_parser->cc_parser);
7430 (*vt_parser->cc_conv->destroy)(vt_parser->cc_conv);
7431
7432 vt_parser->encoding = encoding;
7433 vt_parser->cc_parser = cc_parser;
7434 vt_parser->cc_conv = cc_conv;
7435
7436 /* reset */
7437 vt_parser->gl = US_ASCII;
7438 vt_parser->g0 = US_ASCII;
7439 vt_parser->g1 = US_ASCII;
7440 vt_parser->is_so = 0;
7441
7442 vt_parser->is_auto_encoding = 0;
7443
7444 return 1;
7445 }
7446
vt_parser_convert_to(vt_parser_t * vt_parser,u_char * dst,size_t len,ef_parser_t * parser)7447 size_t vt_parser_convert_to(vt_parser_t *vt_parser, u_char *dst, size_t len,
7448 ef_parser_t *parser) {
7449 return (*vt_parser->cc_conv->convert)(vt_parser->cc_conv, dst, len, parser);
7450 }
7451
vt_init_encoding_conv(vt_parser_t * vt_parser)7452 void vt_init_encoding_conv(vt_parser_t *vt_parser) {
7453 (*vt_parser->cc_conv->init)(vt_parser->cc_conv);
7454
7455 /*
7456 * XXX
7457 * this causes unexpected behaviors in some applications(e.g. biew) ,
7458 * but this is necessary , since 0x00 - 0x7f is not necessarily US-ASCII
7459 * in these encodings but key input or selection paste assumes that
7460 * 0x00 - 0x7f should be US-ASCII at the initial state.
7461 */
7462 if (IS_STATEFUL_ENCODING(vt_parser->encoding)) {
7463 init_encoding_parser(vt_parser);
7464 }
7465 }
7466
vt_set_auto_detect_encodings(char * encodings)7467 int vt_set_auto_detect_encodings(char *encodings) {
7468 char *p;
7469 u_int count;
7470
7471 if (num_auto_detect_encodings > 0) {
7472 for (count = 0; count < num_auto_detect_encodings; count++) {
7473 (*auto_detect[count].parser->destroy)(auto_detect[count].parser);
7474 }
7475
7476 free(auto_detect);
7477 num_auto_detect_encodings = 0;
7478 }
7479
7480 free(auto_detect_encodings);
7481
7482 if (*encodings == '\0') {
7483 auto_detect_encodings = NULL;
7484
7485 return 1;
7486 } else {
7487 auto_detect_encodings = strdup(encodings);
7488 }
7489
7490 if (!(auto_detect = malloc(sizeof(*auto_detect) * (bl_count_char_in_str(encodings, ',') + 1)))) {
7491 return 0;
7492 }
7493
7494 while ((p = bl_str_sep(&encodings, ","))) {
7495 if ((auto_detect[num_auto_detect_encodings].encoding = vt_get_char_encoding(p)) !=
7496 VT_UNKNOWN_ENCODING) {
7497 num_auto_detect_encodings++;
7498 }
7499 }
7500
7501 if (num_auto_detect_encodings == 0) {
7502 free(auto_detect);
7503
7504 return 0;
7505 }
7506
7507 for (count = 0; count < num_auto_detect_encodings; count++) {
7508 auto_detect[count].parser = vt_char_encoding_parser_new(auto_detect[count].encoding);
7509 }
7510
7511 return 1;
7512 }
7513
7514 /*
7515 * XXX
7516 * ef_map_ucs4_to_iscii() in ef_ucs4_iscii.h is used directly in
7517 * vt_convert_to_internal_ch(), though it should be used internally in mef
7518 * library
7519 */
7520 int ef_map_ucs4_to_iscii(ef_char_t *non_ucs, u_int32_t ucs4_code);
7521
7522 /*
7523 * Return value
7524 * 1: Succeed
7525 * 0: Error
7526 * -1: Control sequence
7527 */
vt_convert_to_internal_ch(vt_parser_t * vt_parser,ef_char_t * orig_ch)7528 int vt_convert_to_internal_ch(vt_parser_t *vt_parser, ef_char_t *orig_ch) {
7529 ef_char_t ch;
7530
7531 ch = *orig_ch;
7532
7533 /*
7534 * UCS <-> OTHER CS
7535 */
7536 if (ch.cs == ISO10646_UCS4_1) {
7537 u_char decsp;
7538
7539 if ((vt_parser->unicode_policy & NOT_USE_UNICODE_BOXDRAW_FONT) &&
7540 (decsp = vt_convert_ucs_to_decsp(ef_char_to_int(&ch)))) {
7541 ch.ch[0] = decsp;
7542 ch.size = 1;
7543 ch.cs = DEC_SPECIAL;
7544 ch.property = 0;
7545 }
7546 #if 1
7547 /* See https://github.com/saitoha/drcsterm/ */
7548 else if ((vt_parser->unicode_policy & USE_UNICODE_DRCS) &&
7549 vt_convert_unicode_pua_to_drcs(&ch)) {
7550 if (ch.cs == US_ASCII) {
7551 vt_drcs_font_t *font;
7552
7553 if ((font = vt_drcs_get_font(vt_parser->drcs, US_ASCII, 0)) &&
7554 vt_drcs_is_picture(font, ch.ch[0])) {
7555 ch.cs = CS_REVISION_1(US_ASCII);
7556 }
7557 }
7558
7559 /*
7560 * Go to end to skip 'if (ch.ch[0] == 0x7f) { return 0; }' in next block.
7561 * Otherwise, 0x10XX7f doesn't work.
7562 */
7563 goto end_func;
7564 }
7565 #endif
7566 else {
7567 ef_char_t non_ucs;
7568 u_int32_t code = ef_char_to_int(&ch);
7569
7570 ch.property = modify_ucs_property(code, vt_parser->col_size_of_width_a, ch.property);
7571
7572 if (vt_parser->unicode_policy & NOT_USE_UNICODE_FONT) {
7573 /* convert ucs4 to appropriate charset */
7574
7575 if (!is_noconv_unicode(ch.ch) && ef_map_locale_ucs4_to(&non_ucs, &ch) &&
7576 non_ucs.cs != ISO8859_6_R && /* ARABIC */
7577 non_ucs.cs != ISO8859_8_R) /* HEBREW */
7578 {
7579 /* Use width property of unicode (the original charset). */
7580 non_ucs.property = ch.property;
7581 ch = non_ucs;
7582
7583 goto end_block;
7584 }
7585 }
7586
7587 #if !defined(NO_DYNAMIC_LOAD_CTL) || defined(USE_IND)
7588 if ((vt_parser->unicode_policy & CONVERT_UNICODE_TO_ISCII) &&
7589 0x900 <= code && code <= 0xd7f) {
7590 int ret = ef_map_ucs4_to_iscii(&non_ucs, code);
7591
7592 if (!HAS_XTERM_LISTENER(vt_parser,check_iscii_font) ||
7593 /* non_ucs.cs is set if ef_map_ucs4_to_iscii() fails. */
7594 !(*vt_parser->xterm_listener->check_iscii_font)(vt_parser->xterm_listener->self,
7595 non_ucs.cs)) {
7596 goto end_block;
7597 }
7598
7599 if (ret) {
7600 ch.ch[0] = non_ucs.ch[0];
7601 ch.cs = non_ucs.cs;
7602 ch.size = 1;
7603 /* ch.property is not changed. */
7604 } else {
7605 switch (code & 0x07f) {
7606 case 0x0c:
7607 ch.ch[0] = '\xa6';
7608 break;
7609 case 0x3d:
7610 ch.ch[0] = '\xea';
7611 break;
7612 case 0x44:
7613 ch.ch[0] = '\xdf';
7614 break;
7615 case 0x50:
7616 ch.ch[0] = '\xa1';
7617 break;
7618 case 0x58:
7619 ch.ch[0] = '\xb3';
7620 break;
7621 case 0x59:
7622 ch.ch[0] = '\xb4';
7623 break;
7624 case 0x5a:
7625 ch.ch[0] = '\xb5';
7626 break;
7627 case 0x5b:
7628 ch.ch[0] = '\xba';
7629 break;
7630 case 0x5c:
7631 ch.ch[0] = '\xbf';
7632 break;
7633 case 0x5d:
7634 ch.ch[0] = '\xc0';
7635 break;
7636 case 0x5e:
7637 ch.ch[0] = '\xc9';
7638 break;
7639 case 0x60:
7640 ch.ch[0] = '\xaa';
7641 break;
7642 case 0x61:
7643 ch.ch[0] = '\xa7';
7644 break;
7645 case 0x62:
7646 ch.ch[0] = '\xdb';
7647 break;
7648 case 0x63:
7649 ch.ch[0] = '\xdc';
7650 break;
7651 default:
7652 goto end_block;
7653 }
7654
7655 ch.ch[1] = '\xe9';
7656 /* non_ucs.cs is set if ef_map_ucs4_to_iscii() fails. */
7657 ch.cs = non_ucs.cs;
7658 ch.size = 2;
7659 /* ch.property is not changed. */
7660 }
7661 }
7662 #endif
7663
7664 end_block:
7665 ;
7666 }
7667 } else if (ch.cs != US_ASCII) {
7668 if ((vt_parser->unicode_policy & ONLY_USE_UNICODE_FONT) ||
7669 /* XXX converting japanese gaiji to ucs. */
7670 IS_JIS_EXT(ch.cs) ||
7671 /* XXX converting RTL characters to ucs. */
7672 ch.cs == ISO8859_6_R || /* Arabic */
7673 ch.cs == ISO8859_8_R /* Hebrew */
7674 #if 0
7675 /* GB18030_2000 2-byte chars(==GBK) are converted to UCS */
7676 || (encoding == VT_GB18030 && ch.cs == GBK)
7677 #endif
7678 ) {
7679 ef_char_t ucs;
7680
7681 if (ef_map_to_ucs4(&ucs, &ch)) {
7682 u_int32_t code = ef_char_to_int(&ucs);
7683 ef_charset_t orig_cs = ch.cs;
7684
7685 ch = ucs;
7686
7687 /* Use width property of the original charset. */
7688 ch.property = ef_get_ucs_property(code) & ~(EF_FULLWIDTH|EF_AWIDTH);
7689 if (IS_FULLWIDTH_CS(orig_cs)) {
7690 ch.property |= EF_FULLWIDTH;
7691 }
7692 ch.property = modify_ucs_property(code, vt_parser->col_size_of_width_a, ch.property);
7693 }
7694 } else if (IS_FULLWIDTH_CS(ch.cs)) {
7695 ch.property |= EF_FULLWIDTH;
7696 }
7697 }
7698
7699 if (ch.size == 1) {
7700 /* single byte cs */
7701 vt_drcs_font_t *font;
7702
7703 if ((ch.ch[0] == 0x0 || ch.ch[0] == 0x7f) &&
7704 (!(font = vt_drcs_get_font(vt_parser->drcs, US_ASCII, 0)) ||
7705 !(vt_drcs_is_picture(font, ch.ch[0])))) {
7706 /* DECNULM is always set => discarding 0x0 */
7707 #ifdef DEBUG
7708 bl_warn_printf(BL_DEBUG_TAG " 0x0/0x7f sequence is received , ignored...\n");
7709 #endif
7710 return 0;
7711 } else if ((ch.ch[0] & 0x7f) <= 0x1f && ch.cs == US_ASCII) {
7712 /* Control sequence (C0 or C1) */
7713 return -1;
7714 }
7715
7716 if (vt_is_msb_set(ch.cs)) {
7717 SET_MSB(ch.ch[0]);
7718 } else {
7719 u_int16_t ucs;
7720
7721 if (ch.cs == US_ASCII) {
7722 /* XXX prev_ch should not be static. */
7723 static u_char prev_ch;
7724 static ef_charset_t prev_gl = US_ASCII;
7725
7726 if (vt_parser->gl == US_ASCII) {
7727 goto end_func;
7728 }
7729
7730 if (IS_CS94MB(vt_parser->gl)) {
7731 /* iso2022 multi byte characters can be parsed in utf-8 encoding */
7732 if (vt_parser->gl == prev_gl && prev_ch) {
7733 ch.ch[1] = ch.ch[0];
7734 ch.ch[0] = prev_ch;
7735 ch.size = 2;
7736 ch.property = EF_FULLWIDTH;
7737 prev_ch = 0;
7738 prev_gl = US_ASCII;
7739
7740 ch.cs = vt_parser->gl;
7741
7742 goto end_func;
7743 } else {
7744 prev_ch = ch.ch[0];
7745 prev_gl = vt_parser->gl;
7746
7747 return 0;
7748 }
7749 } else {
7750 ch.cs = vt_parser->gl;
7751 }
7752 }
7753
7754 if (ch.cs == DEC_SPECIAL) {
7755 if ((vt_parser->unicode_policy & ONLY_USE_UNICODE_BOXDRAW_FONT)) {
7756 ucs = vt_convert_decsp_to_ucs(ch.ch[0]);
7757 } else {
7758 goto end_func;
7759 }
7760 } else if (ch.cs == DEC_TECHNICAL) {
7761 ucs = vt_convert_dectech_to_ucs(ch.ch[0]);
7762 } else {
7763 goto end_func;
7764 }
7765
7766 if (ucs) {
7767 ef_int_to_bytes(ch.ch, 4, ucs);
7768 ch.size = 4;
7769 ch.cs = ISO10646_UCS4_1;
7770 /* Use modify_ucs_property() to make it possible to aplly full_width_areas setting. */
7771 ch.property = modify_ucs_property(ucs, 0 /* not used */, 0 /* Use original property */);
7772 }
7773 }
7774 } else {
7775 /*
7776 * NON UCS <-> NON UCS
7777 */
7778
7779 /* multi byte cs */
7780
7781 /*
7782 * XXX hack
7783 * how to deal with johab 10-4-4(8-4-4) font ?
7784 * is there any uhc font ?
7785 */
7786
7787 if (ch.cs == JOHAB) {
7788 ef_char_t uhc;
7789
7790 if (ef_map_johab_to_uhc(&uhc, &ch) == 0) {
7791 return 0;
7792 }
7793
7794 ch = uhc;
7795 }
7796
7797 /*
7798 * XXX
7799 * switching option whether this conversion is done should
7800 * be introduced.
7801 */
7802 if (ch.cs == UHC) {
7803 ef_char_t ksc;
7804
7805 if (ef_map_uhc_to_ksc5601_1987(&ksc, &ch) == 0) {
7806 return 0;
7807 }
7808
7809 ch = ksc;
7810 }
7811 }
7812
7813 end_func:
7814 *orig_ch = ch;
7815
7816 return 1;
7817 }
7818
vt_parser_set_alt_color_mode(vt_parser_t * vt_parser,vt_alt_color_mode_t mode)7819 void vt_parser_set_alt_color_mode(vt_parser_t *vt_parser, vt_alt_color_mode_t mode) {
7820 vt_parser->alt_color_mode = mode;
7821 }
7822
vt_set_broadcasting(int flag)7823 void vt_set_broadcasting(int flag) {
7824 is_broadcasting = flag;
7825 }
7826
vt_parser_is_broadcasting(vt_parser_t * vt_parser)7827 int vt_parser_is_broadcasting(vt_parser_t *vt_parser) {
7828 return (is_broadcasting && !vt_parser->ignore_broadcasted_chars);
7829 }
7830
true_or_false(const char * str)7831 int true_or_false(const char *str) {
7832 if (strcmp(str, "true") == 0) {
7833 return 1;
7834 } else if (strcmp(str, "false") == 0) {
7835 return 0;
7836 } else {
7837 return -1;
7838 }
7839 }
7840
vt_parser_get_config(vt_parser_t * vt_parser,vt_pty_t * output,char * key,int to_menu,int * flag)7841 int vt_parser_get_config(
7842 vt_parser_t *vt_parser,
7843 vt_pty_t *output, /* if vt_parser->pty == output, NULL is set */
7844 char *key, int to_menu, int *flag) {
7845 char *value;
7846 char digit[DIGIT_STR_LEN(u_int) + 1];
7847 char cwd[PATH_MAX];
7848
7849 if (strcmp(key, "encoding") == 0) {
7850 value = vt_get_char_encoding_name(vt_parser->encoding);
7851 } else if (strcmp(key, "is_auto_encoding") == 0) {
7852 if (vt_parser->is_auto_encoding) {
7853 value = "true";
7854 } else {
7855 value = "false";
7856 }
7857 } else if (strcmp(key, "word_separators") == 0) {
7858 value = vt_get_word_separators();
7859 } else if (strcmp(key, "regard_uri_as_word") == 0) {
7860 if (vt_get_regard_uri_as_word()) {
7861 value = "true";
7862 } else {
7863 value = "false";
7864 }
7865 } else if (strcmp(key, "use_alt_buffer") == 0) {
7866 if (use_alt_buffer) {
7867 value = "true";
7868 } else {
7869 value = "false";
7870 }
7871 } else if (strcmp(key, "vt_color_mode") == 0) {
7872 value = vt_get_color_mode();
7873 } else if (strcmp(key, "use_ansi_colors") == 0) {
7874 if (vt_parser->use_ansi_colors) {
7875 value = "true";
7876 } else {
7877 value = "false";
7878 }
7879 } else if (strcmp(key, "tabsize") == 0) {
7880 sprintf(digit, "%d", vt_screen_get_tab_size(vt_parser->screen));
7881 value = digit;
7882 } else if (strcmp(key, "logsize") == 0) {
7883 if (vt_screen_log_size_is_unlimited(vt_parser->screen)) {
7884 value = "unlimited";
7885 } else {
7886 sprintf(digit, "%d", vt_screen_get_log_size(vt_parser->screen));
7887 value = digit;
7888 }
7889 } else if (strcmp(key, "static_backscroll_mode") == 0) {
7890 if (vt_get_backscroll_mode(vt_parser->screen) == BSM_STATIC) {
7891 value = "true";
7892 } else {
7893 value = "false";
7894 }
7895 } else if (strcmp(key, "use_combining") == 0) {
7896 if (vt_parser->use_char_combining) {
7897 value = "true";
7898 } else {
7899 value = "false";
7900 }
7901 } else if (strcmp(key, "col_size_of_width_a") == 0) {
7902 if (vt_parser->col_size_of_width_a == 2) {
7903 value = "2";
7904 } else {
7905 value = "1";
7906 }
7907 } else if (strcmp(key, "locale") == 0) {
7908 value = bl_get_locale();
7909 } else if (strcmp(key, "pwd") == 0) {
7910 value = getcwd(cwd, sizeof(cwd));
7911 } else if (strcmp(key, "logging_vt_seq") == 0) {
7912 if (vt_parser->logging_vt_seq) {
7913 value = "true";
7914 } else {
7915 value = "false";
7916 }
7917 } else if (strcmp(key, "vt_seq_format") == 0) {
7918 if (use_ttyrec_format) {
7919 value = "ttyrec";
7920 } else {
7921 value = "raw";
7922 }
7923 } else if (strcmp(key, "rows") == 0) {
7924 sprintf(digit, "%d", vt_screen_get_logical_rows(vt_parser->screen));
7925 value = digit;
7926 } else if (strcmp(key, "cols") == 0) {
7927 sprintf(digit, "%d", vt_screen_get_logical_cols(vt_parser->screen));
7928 value = digit;
7929 } else if (strcmp(key, "not_use_unicode_font") == 0) {
7930 if (vt_parser->unicode_policy & NOT_USE_UNICODE_FONT) {
7931 value = "true";
7932 } else {
7933 value = "false";
7934 }
7935 } else if (strcmp(key, "only_use_unicode_font") == 0) {
7936 if (vt_parser->unicode_policy & ONLY_USE_UNICODE_FONT) {
7937 value = "true";
7938 } else {
7939 value = "false";
7940 }
7941 } else if (strcmp(key, "box_drawing_font") == 0) {
7942 if (vt_parser->unicode_policy & NOT_USE_UNICODE_BOXDRAW_FONT) {
7943 value = "decsp";
7944 } else if (vt_parser->unicode_policy & ONLY_USE_UNICODE_BOXDRAW_FONT) {
7945 value = "unicode";
7946 } else {
7947 value = "noconv";
7948 }
7949 } else if (strcmp(key, "auto_detect_encodings") == 0) {
7950 if ((value = auto_detect_encodings) == NULL) {
7951 value = "";
7952 }
7953 } else if (strcmp(key, "use_auto_detect") == 0) {
7954 if (vt_parser->use_auto_detect) {
7955 value = "true";
7956 } else {
7957 value = "false";
7958 }
7959 } else if (strcmp(key, "allow_scp") == 0) {
7960 #ifdef USE_LIBSSH2
7961 if (use_scp_full) {
7962 value = "true";
7963 } else
7964 #endif
7965 {
7966 value = "false";
7967 }
7968 } else if (strcmp(key, "unicode_noconv_areas") == 0) {
7969 response_area_table(vt_parser->pty, key, unicode_noconv_areas, num_unicode_noconv_areas,
7970 to_menu);
7971
7972 return 1;
7973 } else if (strcmp(key, "unicode_full_width_areas") == 0) {
7974 response_area_table(vt_parser->pty, key, full_width_areas, num_full_width_areas, to_menu);
7975
7976 return 1;
7977 } else if (strcmp(key, "unicode_half_width_areas") == 0) {
7978 response_area_table(vt_parser->pty, key, half_width_areas, num_half_width_areas, to_menu);
7979
7980 return 1;
7981 } else if (strcmp(key, "blink_cursor") == 0) {
7982 if (vt_parser->cursor_style & CS_BLINK) {
7983 value = "true";
7984 } else {
7985 value = "false";
7986 }
7987 } else if (strcmp(key, "ignore_broadcasted_chars") == 0) {
7988 if (vt_parser->ignore_broadcasted_chars) {
7989 value = "true";
7990 } else {
7991 value = "false";
7992 }
7993 } else if (strcmp(key, "broadcast") == 0) {
7994 if (is_broadcasting) {
7995 value = "true";
7996 } else {
7997 value = "false";
7998 }
7999 } else if (strcmp(key, "use_multi_column_char") == 0) {
8000 if (vt_parser->use_multi_col_char) {
8001 value = "true";
8002 } else {
8003 value = "false";
8004 }
8005 } else if (strcmp(key, "old_drcs_sixel") == 0) {
8006 if (old_drcs_sixel) {
8007 value = "true";
8008 } else {
8009 value = "false";
8010 }
8011 } else if (strcmp(key, "send_file") == 0) {
8012 if (send_file) {
8013 value = send_file;
8014 } else {
8015 value = "";
8016 }
8017 } else if (strcmp(key, "receive_directory") == 0) {
8018 if (recv_dir) {
8019 value = recv_dir;
8020 } else {
8021 value = "";
8022 }
8023 } else if (strcmp(key, "local_echo_wait") == 0) {
8024 sprintf(digit, "%d", local_echo_wait_msec);
8025 value = digit;
8026 } else if (strcmp(key, "use_local_echo") == 0) {
8027 if (vt_parser->use_local_echo) {
8028 value = "true";
8029 } else {
8030 value = "false";
8031 }
8032 } else if (strcmp(key, "challenge") == 0) {
8033 value = vt_get_proto_challenge();
8034 if (to_menu < 0) {
8035 to_menu = 0;
8036 }
8037 } else {
8038 /* Continue to process it in x_screen.c */
8039 return 0;
8040 }
8041
8042 if (!output) {
8043 output = vt_parser->pty;
8044 }
8045
8046 /* value is never set NULL above. */
8047 #if 0
8048 if (!value) {
8049 vt_response_config(output, "error", NULL, to_menu);
8050 }
8051 #endif
8052
8053 if (flag) {
8054 *flag = value ? true_or_false(value) : -1;
8055 } else {
8056 vt_response_config(output, key, value, to_menu);
8057 }
8058
8059 return 1;
8060 }
8061
8062 /* Called in visual context */
vt_parser_set_config(vt_parser_t * vt_parser,char * key,char * value)8063 int vt_parser_set_config(vt_parser_t *vt_parser, char *key, char *value) {
8064 if (strcmp(key, "encoding") == 0) {
8065 if (strcmp(value, "auto") == 0) {
8066 vt_parser->is_auto_encoding = strcasecmp(value, "auto") == 0 ? 1 : 0;
8067 }
8068
8069 return 0; /* Continue to process it in x_screen.c */
8070 } else if (strcmp(key, "logging_msg") == 0) {
8071 if (true_or_false(value) > 0) {
8072 bl_set_msg_log_file_name("mlterm/msg.log");
8073 } else {
8074 bl_set_msg_log_file_name(NULL);
8075 }
8076 } else if (strcmp(key, "word_separators") == 0) {
8077 vt_set_word_separators(value);
8078 } else if (strcmp(key, "regard_uri_as_word") == 0) {
8079 int flag;
8080
8081 if ((flag = true_or_false(value)) != -1) {
8082 vt_set_regard_uri_as_word(flag);
8083 }
8084 } else if (strcmp(key, "vt_color_mode") == 0) {
8085 vt_set_color_mode(value);
8086 } else if (strcmp(key, "use_alt_buffer") == 0) {
8087 int flag;
8088
8089 if ((flag = true_or_false(value)) != -1) {
8090 use_alt_buffer = flag;
8091 }
8092 } else if (strcmp(key, "use_ansi_colors") == 0) {
8093 int flag;
8094
8095 if ((flag = true_or_false(value)) != -1) {
8096 vt_parser->use_ansi_colors = flag;
8097 }
8098 } else if (strcmp(key, "unicode_noconv_areas") == 0) {
8099 vt_set_unicode_noconv_areas(value);
8100 } else if (strcmp(key, "unicode_full_width_areas") == 0) {
8101 vt_set_full_width_areas(value);
8102 } else if (strcmp(key, "unicode_half_width_areas") == 0) {
8103 vt_set_half_width_areas(value);
8104 } else if (strcmp(key, "tabsize") == 0) {
8105 u_int tab_size;
8106
8107 if (bl_str_to_uint(&tab_size, value)) {
8108 vt_screen_set_tab_size(vt_parser->screen, tab_size);
8109 }
8110 } else if (strcmp(key, "static_backscroll_mode") == 0) {
8111 vt_bs_mode_t mode;
8112
8113 if (strcmp(value, "true") == 0) {
8114 mode = BSM_STATIC;
8115 } else if (strcmp(value, "false") == 0) {
8116 mode = BSM_DEFAULT;
8117 } else {
8118 return 1;
8119 }
8120
8121 vt_set_backscroll_mode(vt_parser->screen, mode);
8122 } else if (strcmp(key, "use_combining") == 0) {
8123 int flag;
8124
8125 if ((flag = true_or_false(value)) != -1) {
8126 vt_parser->use_char_combining = flag;
8127 }
8128 } else if (strcmp(key, "col_size_of_width_a") == 0) {
8129 u_int size;
8130
8131 if (strcmp(value, "switch") == 0) {
8132 size = vt_parser->col_size_of_width_a == 1 ? 2 : 1;
8133 } else if (!bl_str_to_uint(&size, value)) {
8134 goto end;
8135 }
8136
8137 set_col_size_of_width_a(vt_parser, size);
8138
8139 end:
8140 ;
8141 } else if (strcmp(key, "locale") == 0) {
8142 bl_locale_init(value);
8143 } else if (strcmp(key, "logging_vt_seq") == 0) {
8144 int flag;
8145
8146 if ((flag = true_or_false(value)) != -1) {
8147 vt_parser->logging_vt_seq = flag;
8148 }
8149 } else if (strcmp(key, "vt_seq_format") == 0) {
8150 use_ttyrec_format = (strcmp(value, "ttyrec") == 0);
8151 } else if (strcmp(key, "geometry") == 0) {
8152 u_int cols;
8153 u_int rows;
8154
8155 if (sscanf(value, "%ux%u", &cols, &rows) == 2) {
8156 resize(vt_parser, cols, rows, 1);
8157 }
8158 } else if (strcmp(key, "box_drawing_font") == 0) {
8159 if (strcmp(value, "unicode") == 0) {
8160 vt_parser->unicode_policy &= ~NOT_USE_UNICODE_BOXDRAW_FONT;
8161 vt_parser->unicode_policy |= ONLY_USE_UNICODE_BOXDRAW_FONT;
8162 } else if (strcmp(value, "decsp") == 0) {
8163 vt_parser->unicode_policy &= ~ONLY_USE_UNICODE_BOXDRAW_FONT;
8164 vt_parser->unicode_policy |= NOT_USE_UNICODE_BOXDRAW_FONT;
8165 } else {
8166 vt_parser->unicode_policy &=
8167 (~NOT_USE_UNICODE_BOXDRAW_FONT & ~ONLY_USE_UNICODE_BOXDRAW_FONT);
8168 }
8169 } else if (strcmp(key, "auto_detect_encodings") == 0) {
8170 vt_set_auto_detect_encodings(value);
8171 } else if (strcmp(key, "use_auto_detect") == 0) {
8172 int flag;
8173
8174 if ((flag = true_or_false(value)) != -1) {
8175 vt_parser->use_auto_detect = flag;
8176 }
8177 } else if (strcmp(key, "blink_cursor") == 0) {
8178 if (strcmp(value, "true") == 0) {
8179 vt_parser->cursor_style |= CS_BLINK;
8180 } else {
8181 vt_parser->cursor_style &= ~CS_BLINK;
8182 }
8183 } else if (strcmp(key, "ignore_broadcasted_chars") == 0) {
8184 int flag;
8185
8186 if ((flag = true_or_false(value)) != -1) {
8187 vt_parser->ignore_broadcasted_chars = flag;
8188 }
8189 } else if (strcmp(key, "broadcast") == 0) {
8190 int flag;
8191
8192 if ((flag = true_or_false(value)) != -1) {
8193 is_broadcasting = flag;
8194 }
8195 } else if (strcmp(key, "use_multi_column_char") == 0) {
8196 int flag;
8197
8198 if ((flag = true_or_false(value)) != -1) {
8199 vt_parser->use_multi_col_char = flag;
8200 }
8201 } else if (strcmp(key, "old_drcs_sixel") == 0) {
8202 int flag;
8203
8204 if ((flag = true_or_false(value)) != -1) {
8205 old_drcs_sixel = flag;
8206 }
8207 } else if (strcmp(key, "local_echo_wait") == 0) {
8208 u_int msec;
8209
8210 if (bl_str_to_uint(&msec, value)) {
8211 local_echo_wait_msec = msec;
8212 }
8213 } else if (strcmp(key, "use_local_echo") == 0) {
8214 int flag;
8215
8216 if ((flag = true_or_false(value)) != -1) {
8217 if ((vt_parser->use_local_echo ? 1 : 0) != flag && !(vt_parser->use_local_echo = flag)) {
8218 vt_screen_logical(vt_parser->screen);
8219 vt_screen_disable_local_echo(vt_parser->screen);
8220 vt_screen_visual(vt_parser->screen);
8221 }
8222 }
8223 } else if (strncmp(key, "send_file", 9) == 0) {
8224 if (strstr(value, "..")) {
8225 /* insecure file name */
8226 bl_msg_printf("%s is insecure file name.\n", value);
8227 } else {
8228 if (key[9] == '\0') {
8229 free(send_file);
8230 send_file = convert_to_locale_encoding(value, vt_parser->cc_parser, vt_parser->encoding);
8231 } else if (strcmp(key + 9, "_utf8") == 0) {
8232 /* Hack for set_xdnd_config() in ui_screen.c */
8233 free(send_file);
8234 send_file = convert_to_locale_encoding(value, NULL, VT_UTF8);
8235 }
8236 }
8237 } else {
8238 /* Continue to process it in x_screen.c */
8239 return 0;
8240 }
8241
8242 return 1;
8243 }
8244
8245 /* Called in visual context */
vt_parser_exec_cmd(vt_parser_t * vt_parser,char * cmd)8246 int vt_parser_exec_cmd(vt_parser_t *vt_parser, char *cmd) {
8247 if (strcmp(cmd, "gen_proto_challenge") == 0) {
8248 vt_gen_proto_challenge();
8249 } else if (strcmp(cmd, "full_reset") == 0) {
8250 vt_parser_reset(vt_parser, 0);
8251 } else if (strncmp(cmd, "snapshot", 8) == 0) {
8252 char **argv;
8253 int argc;
8254
8255 if ((argv = bl_argv_alloca(cmd)) && bl_arg_str_to_array(argv, &argc, cmd)) {
8256 vt_char_encoding_t encoding;
8257 char *file;
8258
8259 if (argc >= 3) {
8260 encoding = vt_get_char_encoding(argv[2]);
8261 } else {
8262 encoding = VT_UNKNOWN_ENCODING;
8263 }
8264
8265 if (argc >= 2) {
8266 file = argv[1];
8267 } else {
8268 /* skip /dev/ */
8269 file = vt_pty_get_slave_name(vt_parser->pty) + 5;
8270 }
8271
8272 if (strstr(file, "..")) {
8273 /* insecure file name */
8274 bl_msg_printf("%s is insecure file name.\n", file);
8275 } else {
8276 snapshot(vt_parser, encoding, file, WCA_ALL);
8277 }
8278 }
8279 } else if (strcmp(cmd, "zmodem_start") == 0) {
8280 int count = 0;
8281
8282 while (1) {
8283 if (!vt_pty_is_loopback(vt_parser->pty)) {
8284 if ((send_file || recv_dir || (recv_dir = bl_get_user_rc_path("mlterm/recv"))) &&
8285 vt_transfer_start(send_file, recv_dir, 0,
8286 vt_screen_get_cols(vt_parser->screen) / 2 + 1)) {
8287 vt_parser->is_zmodem_ready = 0;
8288 vt_parser->is_transferring_data = (send_file ? 0x1 : 0x2);
8289 vt_parser->r_buf.left = 0;
8290 transfer_data(vt_parser);
8291 } else {
8292 transfer_cancel(vt_parser, 1);
8293 /* send_file is freed in vt_transfer_start() */
8294 }
8295 send_file = NULL;
8296
8297 break;
8298 }
8299
8300 if (++count == 10) {
8301 bl_msg_printf("Retry zmodem_start.\n");
8302
8303 break;
8304 }
8305
8306 bl_usleep(100000);
8307 }
8308 }
8309 #if !defined(NO_IMAGE) && defined(ENABLE_OSC5379PICTURE)
8310 else if (strncmp(cmd, "show_picture ", 13) == 0 || strncmp(cmd, "add_frame ", 10) == 0) {
8311 int clip_beg_col = 0;
8312 int clip_beg_row = 0;
8313 int clip_cols = 0;
8314 int clip_rows = 0;
8315 int img_cols = 0;
8316 int img_rows = 0;
8317 char **argv;
8318 int argc;
8319
8320 if (!(argv = bl_argv_alloca(cmd)) || !bl_arg_str_to_array(argv, &argc, cmd) || argc == 1) {
8321 return 1;
8322 }
8323
8324 if (argc >= 3) {
8325 int has_img_size;
8326
8327 if (strchr(argv[argc - 1], '+')) {
8328 sscanf(argv[argc - 1], "%dx%d+%d+%d", &clip_cols, &clip_rows, &clip_beg_col, &clip_beg_row);
8329
8330 has_img_size = (argc >= 4);
8331 } else {
8332 has_img_size = 1;
8333 }
8334
8335 if (has_img_size) {
8336 sscanf(argv[2], "%dx%d", &img_cols, &img_rows);
8337 }
8338 }
8339
8340 if (*argv[0] == 's') {
8341 show_picture(vt_parser, argv[1], clip_beg_col, clip_beg_row, clip_cols, clip_rows,
8342 img_cols, img_rows, 0, 0);
8343 } else if (HAS_XTERM_LISTENER(vt_parser, add_frame_to_animation)) {
8344 (*vt_parser->xterm_listener->add_frame_to_animation)(vt_parser->xterm_listener->self,
8345 argv[1], &img_cols, &img_rows);
8346 }
8347 }
8348 #endif
8349 #ifdef USE_LIBSSH2
8350 else if (strncmp(cmd, "scp ", 4) == 0) {
8351 char **argv;
8352 int argc;
8353
8354 if ((argv = bl_argv_alloca(cmd)) && bl_arg_str_to_array(argv, &argc, cmd) &&
8355 (argc == 3 || argc == 4)) {
8356 vt_char_encoding_t encoding;
8357
8358 if (!argv[3] || (encoding = vt_get_char_encoding(argv[3])) == VT_UNKNOWN_ENCODING) {
8359 encoding = vt_parser->encoding;
8360 }
8361
8362 vt_pty_ssh_scp(vt_parser->pty, vt_parser->encoding, encoding, argv[2], argv[1],
8363 use_scp_full, recv_dir, vt_screen_get_cols(vt_parser->screen) / 2 + 1);
8364 }
8365 }
8366 #endif
8367 else {
8368 return 0;
8369 }
8370
8371 return 1;
8372 }
8373
8374 /*
8375 * level=1: Unuse loopback, Output ZCAN.
8376 */
vt_parser_reset(vt_parser_t * vt_parser,int level)8377 void vt_parser_reset(vt_parser_t *vt_parser, int level) {
8378 #ifdef USE_LIBSSH2
8379 if (level >= 1) {
8380 if (vt_pty_is_loopback(vt_parser->pty)) {
8381 if (vt_pty_get_mode(vt_parser->pty) == PTY_MOSH) {
8382 vt_pty_mosh_set_use_loopback(vt_parser->pty, 0);
8383 } else {
8384 vt_pty_ssh_set_use_loopback(vt_parser->pty, 0);
8385 }
8386 }
8387 }
8388 #endif
8389
8390 soft_reset(vt_parser);
8391 vt_parser->r_buf.left = 0; /* Reset DCS or OSC etc sequence */
8392 vt_parser->sixel_scrolling = 1;
8393 transfer_cancel(vt_parser, level >= 1);
8394 }
8395
8396 #define MOUSE_POS_LIMIT (0xff - 0x20)
8397 #define EXT_MOUSE_POS_LIMIT (0x7ff - 0x20)
8398
vt_parser_report_mouse_tracking(vt_parser_t * vt_parser,int col,int row,int button,int is_released,int key_state,int button_state)8399 void vt_parser_report_mouse_tracking(vt_parser_t *vt_parser, int col, int row,
8400 int button,
8401 int is_released, /* is_released is 0 if PointerMotion */
8402 int key_state, int button_state) {
8403 if (vt_parser->mouse_mode >= LOCATOR_CHARCELL_REPORT) {
8404 char seq[10 + DIGIT_STR_LEN(int)*4 + 1];
8405 int ev;
8406 int is_outside_filter_rect;
8407
8408 is_outside_filter_rect = 0;
8409 if (vt_parser->loc_filter.top > row || vt_parser->loc_filter.left > col ||
8410 vt_parser->loc_filter.bottom < row || vt_parser->loc_filter.right < col) {
8411 vt_parser->loc_filter.top = vt_parser->loc_filter.bottom = row;
8412 vt_parser->loc_filter.left = vt_parser->loc_filter.right = col;
8413
8414 if (vt_parser->locator_mode & LOCATOR_FILTER_RECT) {
8415 vt_parser->locator_mode &= ~LOCATOR_FILTER_RECT;
8416 is_outside_filter_rect = 1;
8417 }
8418 }
8419
8420 if (button == 0) {
8421 if (is_outside_filter_rect) {
8422 ev = 10;
8423 } else if (vt_parser->locator_mode & LOCATOR_REQUEST) {
8424 ev = 1;
8425 } else {
8426 return;
8427 }
8428 } else {
8429 if ((is_released && !(vt_parser->locator_mode & LOCATOR_BUTTON_UP)) ||
8430 (!is_released && !(vt_parser->locator_mode & LOCATOR_BUTTON_DOWN))) {
8431 return;
8432 }
8433
8434 if (button == 1) {
8435 ev = is_released ? 3 : 2;
8436 } else if (button == 2) {
8437 ev = is_released ? 5 : 4;
8438 } else if (button == 3) {
8439 ev = is_released ? 7 : 6;
8440 } else {
8441 ev = 1;
8442 }
8443 }
8444
8445 sprintf(seq, "\x1b[%d;%d;%d;%d;%d&w", ev, button_state, row, col,
8446 vt_screen_get_page_id(vt_parser->screen) + 1);
8447
8448 vt_write_to_pty(vt_parser->pty, seq, strlen(seq));
8449
8450 if (vt_parser->locator_mode & LOCATOR_ONESHOT) {
8451 set_mouse_report(vt_parser, 0);
8452 vt_parser->locator_mode = 0;
8453 }
8454 } else {
8455 /*
8456 * Max length is SGR style => ESC [ < %d ; %d(col) ; %d(row) ; %c('M' or
8457 * 'm') NULL
8458 * 1 1 1 3 1 3 1 3 1 1 1
8459 */
8460 u_char seq[17];
8461 size_t seq_len;
8462
8463 if (is_released && vt_parser->ext_mouse_mode != EXTENDED_MOUSE_REPORT_SGR) {
8464 key_state = 0;
8465 button = 3;
8466 } else if (button == 0) {
8467 /* PointerMotion */
8468 button = 3 + 32;
8469 } else {
8470 if (is_released) {
8471 /* for EXTENDED_MOUSE_REPORT_SGR */
8472 key_state += 0x80;
8473 }
8474
8475 button--; /* button1 == 0, button2 == 1, button3 == 2 */
8476
8477 while (button >= 3) {
8478 /* Wheel mouse */
8479 key_state += 64;
8480 button -= 3;
8481 }
8482 }
8483
8484 if (vt_parser->ext_mouse_mode == EXTENDED_MOUSE_REPORT_SGR) {
8485 sprintf(seq, "\x1b[<%d;%d;%d%c", (button + key_state) & 0x7f, col, row,
8486 ((button + key_state) & 0x80) ? 'm' : 'M');
8487 seq_len = strlen(seq);
8488 } else if (vt_parser->ext_mouse_mode == EXTENDED_MOUSE_REPORT_URXVT) {
8489 sprintf(seq, "\x1b[%d;%d;%dM", 0x20 + button + key_state, col, row);
8490 seq_len = strlen(seq);
8491 } else {
8492 memcpy(seq, "\x1b[M", 3);
8493 seq[3] = 0x20 + button + key_state;
8494
8495 if (vt_parser->ext_mouse_mode == EXTENDED_MOUSE_REPORT_UTF8) {
8496 int ch;
8497 u_char *p;
8498
8499 p = seq + 4;
8500
8501 if (col > EXT_MOUSE_POS_LIMIT) {
8502 col = EXT_MOUSE_POS_LIMIT;
8503 }
8504
8505 if ((ch = 0x20 + col) >= 0x80) {
8506 *(p++) = ((ch >> 6) & 0x1f) | 0xc0;
8507 *(p++) = (ch & 0x3f) | 0x80;
8508 } else {
8509 *(p++) = ch;
8510 }
8511
8512 if (row > EXT_MOUSE_POS_LIMIT) {
8513 row = EXT_MOUSE_POS_LIMIT;
8514 }
8515
8516 if ((ch = 0x20 + row) >= 0x80) {
8517 *(p++) = ((ch >> 6) & 0x1f) | 0xc0;
8518 *p = (ch & 0x3f) | 0x80;
8519 } else {
8520 *p = ch;
8521 }
8522
8523 seq_len = p - seq + 1;
8524 } else {
8525 seq[4] = 0x20 + (col < MOUSE_POS_LIMIT ? col : MOUSE_POS_LIMIT);
8526 seq[5] = 0x20 + (row < MOUSE_POS_LIMIT ? row : MOUSE_POS_LIMIT);
8527 seq_len = 6;
8528 }
8529 }
8530
8531 vt_write_to_pty(vt_parser->pty, seq, seq_len);
8532
8533 #ifdef __DEBUG
8534 bl_debug_printf(BL_DEBUG_TAG " [reported cursor pos] %d %d\n", col, row);
8535 #endif
8536 }
8537 }
8538
8539 #ifdef BL_DEBUG
8540
8541 #include <assert.h>
8542
TEST_vt_parser(void)8543 void TEST_vt_parser(void) {
8544 #ifndef NO_IMAGE
8545 u_char a[] = "\x1b]8k @\x1f\x1bP;1";
8546 u_char b[] = "\x1b]k @\x1f\x90;1";
8547 u_char c[] = "\x1b]16k @@@@\x1f\x1bP0;1";
8548 u_char d[] = "\x1b]A @\x90;2";
8549 u_char e[] = "\x1b]A hogefuga\x1f\x1bP;1";
8550 u_char f[] = "\x1b]A hogefug\x1f\x1bP;1";
8551
8552 assert(is_separated_sixel(a, sizeof(a) - 1) == 1);
8553 assert(is_separated_sixel(b, sizeof(b) - 1) == 1);
8554 assert(is_separated_sixel(c, sizeof(c) - 1) == 1);
8555 assert(is_separated_sixel(d, sizeof(d) - 1) == 0);
8556 assert(is_separated_sixel(e, sizeof(e) - 1) == 0);
8557 assert(is_separated_sixel(f, sizeof(f) - 1) == 1);
8558
8559 bl_msg_printf("PASS vt_parser test.\n");
8560 #endif
8561 }
8562
8563 #endif
8564