You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

1305 lines
67 KiB

  1. #include "vt.h"
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #include <assert.h>
  6. #define LOG_MODULE "vt"
  7. #define LOG_ENABLE_DBG 0
  8. #include "log.h"
  9. #include "csi.h"
  10. #include "dcs.h"
  11. #include "grid.h"
  12. #include "osc.h"
  13. #include "util.h"
  14. #include "xmalloc.h"
  15. #define UNHANDLED() LOG_DBG("unhandled: %s", esc_as_string(term, final))
  16. /* https://vt100.net/emu/dec_ansi_parser */
  17. enum state {
  18. STATE_GROUND,
  19. STATE_ESCAPE,
  20. STATE_ESCAPE_INTERMEDIATE,
  21. STATE_CSI_ENTRY,
  22. STATE_CSI_PARAM,
  23. STATE_CSI_INTERMEDIATE,
  24. STATE_CSI_IGNORE,
  25. STATE_OSC_STRING,
  26. STATE_DCS_ENTRY,
  27. STATE_DCS_PARAM,
  28. STATE_DCS_INTERMEDIATE,
  29. STATE_DCS_IGNORE,
  30. STATE_DCS_PASSTHROUGH,
  31. STATE_SOS_PM_APC_STRING,
  32. STATE_UTF8_21,
  33. STATE_UTF8_31,
  34. STATE_UTF8_32,
  35. STATE_UTF8_41,
  36. STATE_UTF8_42,
  37. STATE_UTF8_43,
  38. };
  39. #if defined(_DEBUG) && defined(LOG_ENABLE_DBG) && LOG_ENABLE_DBG && 0
  40. static const char *const state_names[] = {
  41. [STATE_GROUND] = "ground",
  42. [STATE_ESCAPE] = "escape",
  43. [STATE_ESCAPE_INTERMEDIATE] = "escape intermediate",
  44. [STATE_CSI_ENTRY] = "CSI entry",
  45. [STATE_CSI_PARAM] = "CSI param",
  46. [STATE_CSI_INTERMEDIATE] = "CSI intermediate",
  47. [STATE_CSI_IGNORE] = "CSI ignore",
  48. [STATE_OSC_STRING] = "OSC string",
  49. [STATE_DCS_ENTRY] = "DCS entry",
  50. [STATE_DCS_PARAM] = "DCS param",
  51. [STATE_DCS_INTERMEDIATE] = "DCS intermediate",
  52. [STATE_DCS_IGNORE] = "DCS ignore",
  53. [STATE_DCS_PASSTHROUGH] = "DCS passthrough",
  54. [STATE_SOS_PM_APC_STRING] = "sos/pm/apc string",
  55. [STATE_UTF8_21] = "UTF8 2-byte 1/2",
  56. [STATE_UTF8_31] = "UTF8 3-byte 1/3",
  57. [STATE_UTF8_32] = "UTF8 3-byte 2/3",
  58. };
  59. #endif
  60. #if defined(LOG_ENABLE_DBG) && LOG_ENABLE_DBG
  61. static const char *
  62. esc_as_string(struct terminal *term, uint8_t final)
  63. {
  64. static char msg[1024];
  65. int c = snprintf(msg, sizeof(msg), "\\E");
  66. for (size_t i = 0; i < sizeof(term->vt.private) / sizeof(term->vt.private[0]); i++) {
  67. if (term->vt.private[i] == 0)
  68. break;
  69. c += snprintf(&msg[c], sizeof(msg) - c, "%c", term->vt.private[i]);
  70. }
  71. assert(term->vt.params.idx == 0);
  72. snprintf(&msg[c], sizeof(msg) - c, "%c", final);
  73. return msg;
  74. }
  75. #endif
  76. static void
  77. action_ignore(struct terminal *term)
  78. {
  79. }
  80. static void
  81. action_clear(struct terminal *term)
  82. {
  83. term->vt.params.idx = 0;
  84. term->vt.private[0] = 0;
  85. term->vt.private[1] = 0;
  86. }
  87. static void
  88. action_execute(struct terminal *term, uint8_t c)
  89. {
  90. LOG_DBG("execute: 0x%02x", c);
  91. switch (c) {
  92. /*
  93. * 7-bit C0 control characters
  94. */
  95. case '\0':
  96. break;
  97. case '\a':
  98. /* BEL - bell */
  99. term_bell(term);
  100. break;
  101. case '\b':
  102. /* backspace */
  103. if (term->grid->cursor.lcf)
  104. term->grid->cursor.lcf = false;
  105. else
  106. term_cursor_left(term, 1);
  107. break;
  108. case '\t': {
  109. /* HT - horizontal tab */
  110. int new_col = term->cols - 1;
  111. tll_foreach(term->tab_stops, it) {
  112. if (it->item > term->grid->cursor.point.col) {
  113. new_col = it->item;
  114. break;
  115. }
  116. }
  117. assert(new_col >= term->grid->cursor.point.col);
  118. /* According to the specification, HT _should_ cancel LCF. But
  119. * XTerm, and nearly all other emulators, don't. So we follow
  120. * suit */
  121. bool lcf = term->grid->cursor.lcf;
  122. term_cursor_right(term, new_col - term->grid->cursor.point.col);
  123. term->grid->cursor.lcf = lcf;
  124. break;
  125. }
  126. case '\n':
  127. case '\v':
  128. case '\f':
  129. /* LF - \n - line feed */
  130. /* VT - \v - vertical tab */
  131. /* FF - \f - form feed */
  132. term_linefeed(term);
  133. break;
  134. case '\r':
  135. /* CR - carriage ret */
  136. term_carriage_return(term);
  137. break;
  138. case '\x0e':
  139. /* SO - shift out */
  140. term->charsets.selected = 1; /* G1 */
  141. break;
  142. case '\x0f':
  143. /* SI - shift in */
  144. term->charsets.selected = 0; /* G0 */
  145. break;
  146. /*
  147. * 8-bit C1 control characters
  148. *
  149. * We ignore these, but keep them here for reference, along
  150. * with their corresponding 7-bit variants.
  151. *
  152. * As far as I can tell, XTerm also ignores these _when in
  153. * UTF-8 mode_. Which would be the normal mode of operation
  154. * these days. And since we _only_ support UTF-8...
  155. */
  156. #if 0
  157. case '\x84': /* IND -> ESC D */
  158. case '\x85': /* NEL -> ESC E */
  159. case '\x88': /* Tab Set -> ESC H */
  160. case '\x8d': /* RI -> ESC M */
  161. case '\x8e': /* SS2 -> ESC N */
  162. case '\x8f': /* SS3 -> ESC O */
  163. case '\x90': /* DCS -> ESC P */
  164. case '\x96': /* SPA -> ESC V */
  165. case '\x97': /* EPA -> ESC W */
  166. case '\x98': /* SOS -> ESC X */
  167. case '\x9a': /* DECID -> ESC Z (obsolete form of CSI c) */
  168. case '\x9b': /* CSI -> ESC [ */
  169. case '\x9c': /* ST -> ESC \ */
  170. case '\x9d': /* OSC -> ESC ] */
  171. case '\x9e': /* PM -> ESC ^ */
  172. case '\x9f': /* APC -> ESC _ */
  173. break;
  174. #endif
  175. default:
  176. break;
  177. }
  178. }
  179. static void
  180. action_print(struct terminal *term, uint8_t c)
  181. {
  182. /* 0x60 - 0x7e */
  183. static const wchar_t vt100_0[] = {
  184. L'◆', L'▒', L'␉', L'␌', L'␍', L'␊', L'°', L'±', /* ` - g */
  185. L'␤', L'␋', L'┘', L'┐', L'┌', L'└', L'┼', L'⎺', /* h - o */
  186. L'⎻', L'─', L'⎼', L'⎽', L'├', L'┤', L'┴', L'┬', /* p - w */
  187. L'│', L'≤', L'≥', L'π', L'≠', L'£', L'·', /* x - ~ */
  188. };
  189. assert(wcwidth(c) == 1);
  190. if (unlikely(term->charsets.set[term->charsets.selected] == CHARSET_GRAPHIC) &&
  191. c >= 0x60 && c <= 0x7e)
  192. {
  193. term_print(term, vt100_0[c - 0x60], 1);
  194. } else {
  195. term_print(term, c, 1);
  196. }
  197. }
  198. static void
  199. action_param(struct terminal *term, uint8_t c)
  200. {
  201. if (term->vt.params.idx == 0) {
  202. struct vt_param *param = &term->vt.params.v[0];
  203. param->value = 0;
  204. param->sub.idx = 0;
  205. term->vt.params.idx = 1;
  206. }
  207. assert(term->vt.params.idx > 0);
  208. const size_t max_params
  209. = sizeof(term->vt.params.v) / sizeof(term->vt.params.v[0]);
  210. const size_t max_sub_params
  211. = sizeof(term->vt.params.v[0].sub.value) / sizeof(term->vt.params.v[0].sub.value[0]);
  212. /* New parameter */
  213. if (c == ';') {
  214. if (unlikely(term->vt.params.idx >= max_params))
  215. goto excess_params;
  216. struct vt_param *param = &term->vt.params.v[term->vt.params.idx++];
  217. param->value = 0;
  218. param->sub.idx = 0;
  219. }
  220. /* New sub-parameter */
  221. else if (c == ':') {
  222. if (unlikely(term->vt.params.idx - 1 >= max_params))
  223. goto excess_params;
  224. struct vt_param *param = &term->vt.params.v[term->vt.params.idx - 1];
  225. if (unlikely(param->sub.idx >= max_sub_params))
  226. goto excess_sub_params;
  227. param->sub.value[param->sub.idx++] = 0;
  228. }
  229. /* New digit for current parameter/sub-parameter */
  230. else {
  231. if (unlikely(term->vt.params.idx - 1 >= max_params))
  232. goto excess_params;
  233. struct vt_param *param = &term->vt.params.v[term->vt.params.idx - 1];
  234. unsigned *value;
  235. if (param->sub.idx > 0) {
  236. if (unlikely(param->sub.idx - 1 >= max_sub_params))
  237. goto excess_sub_params;
  238. value = &param->sub.value[param->sub.idx - 1];
  239. } else
  240. value = &param->value;
  241. *value *= 10;
  242. *value += c - '0';
  243. }
  244. #if defined(_DEBUG)
  245. /* The rest of the code assumes 'idx' *never* points outside the array */
  246. assert(term->vt.params.idx <= max_params);
  247. for (size_t i = 0; i < term->vt.params.idx; i++)
  248. assert(term->vt.params.v[i].sub.idx <= max_sub_params);
  249. #endif
  250. return;
  251. excess_params:
  252. {
  253. static bool have_warned = false;
  254. if (!have_warned) {
  255. have_warned = true;
  256. LOG_WARN(
  257. "unsupported: escape with more than %zu parameters "
  258. "(will not warn again)",
  259. sizeof(term->vt.params.v) / sizeof(term->vt.params.v[0]));
  260. }
  261. }
  262. return;
  263. excess_sub_params:
  264. {
  265. static bool have_warned = false;
  266. if (!have_warned) {
  267. have_warned = true;
  268. LOG_WARN(
  269. "unsupported: escape with more than %zu sub-parameters "
  270. "(will not warn again)",
  271. sizeof(term->vt.params.v[0].sub.value) / sizeof(term->vt.params.v[0].sub.value[0]));
  272. }
  273. }
  274. return;
  275. }
  276. static void
  277. action_collect(struct terminal *term, uint8_t c)
  278. {
  279. LOG_DBG("collect: %c", c);
  280. if (term->vt.private[0] == 0)
  281. term->vt.private[0] = c;
  282. else if (term->vt.private[1] == 0)
  283. term->vt.private[1] = c;
  284. else
  285. LOG_WARN("only two private/intermediate characters supported");
  286. }
  287. static void
  288. action_esc_dispatch(struct terminal *term, uint8_t final)
  289. {
  290. LOG_DBG("ESC: %s", esc_as_string(term, final));
  291. switch (term->vt.private[0]) {
  292. case 0:
  293. switch (final) {
  294. case '7':
  295. term->grid->saved_cursor = term->grid->cursor;
  296. term->vt.saved_attrs = term->vt.attrs;
  297. term->saved_charsets = term->charsets;
  298. break;
  299. case '8':
  300. term_restore_cursor(term, &term->grid->saved_cursor);
  301. term->vt.attrs = term->vt.saved_attrs;
  302. term->charsets = term->saved_charsets;
  303. break;
  304. case 'c':
  305. term_reset(term, true);
  306. break;
  307. case 'D':
  308. term_linefeed(term);
  309. break;
  310. case 'E':
  311. term_carriage_return(term);
  312. term_linefeed(term);
  313. break;
  314. case 'H':
  315. tll_foreach(term->tab_stops, it) {
  316. if (it->item >= term->grid->cursor.point.col) {
  317. tll_insert_before(term->tab_stops, it, term->grid->cursor.point.col);
  318. break;
  319. }
  320. }
  321. tll_push_back(term->tab_stops, term->grid->cursor.point.col);
  322. break;
  323. case 'M':
  324. term_reverse_index(term);
  325. break;
  326. case 'N':
  327. /* SS2 - Single Shift 2 */
  328. term->charsets.selected = 2; /* G2 */
  329. break;
  330. case 'O':
  331. /* SS3 - Single Shift 3 */
  332. term->charsets.selected = 3; /* G3 */
  333. break;
  334. case '\\':
  335. /* ST - String Terminator */
  336. break;
  337. case '=':
  338. term->keypad_keys_mode = KEYPAD_APPLICATION;
  339. break;
  340. case '>':
  341. term->keypad_keys_mode = KEYPAD_NUMERICAL;
  342. break;
  343. default:
  344. UNHANDLED();
  345. break;
  346. }
  347. break; /* private[0] == 0 */
  348. case '(':
  349. case ')':
  350. case '*':
  351. case '+':
  352. switch (final) {
  353. case '0': {
  354. char priv = term->vt.private[0];
  355. ssize_t idx = priv ==
  356. '(' ? 0 :
  357. ')' ? 1 :
  358. '*' ? 2 :
  359. '+' ? 3 : -1;
  360. assert(idx != -1);
  361. term->charsets.set[idx] = CHARSET_GRAPHIC;
  362. break;
  363. }
  364. case 'B': {
  365. char priv = term->vt.private[0];
  366. ssize_t idx = priv ==
  367. '(' ? 0 :
  368. ')' ? 1 :
  369. '*' ? 2 :
  370. '+' ? 3 : -1;
  371. assert(idx != -1);
  372. term->charsets.set[idx] = CHARSET_ASCII;
  373. break;
  374. }
  375. }
  376. break;
  377. case '#':
  378. switch (final) {
  379. case '8':
  380. for (int r = 0; r < term->rows; r++) {
  381. struct row *row = grid_row(term->grid, r);
  382. for (int c = 0; c < term->cols; c++) {
  383. row->cells[c].wc = L'E';
  384. row->cells[c].attrs.clean = 0;
  385. }
  386. row->dirty = true;
  387. }
  388. break;
  389. }
  390. break; /* private[0] == '#' */
  391. }
  392. }
  393. static void
  394. action_csi_dispatch(struct terminal *term, uint8_t c)
  395. {
  396. csi_dispatch(term, c);
  397. }
  398. static void
  399. action_osc_start(struct terminal *term, uint8_t c)
  400. {
  401. term->vt.osc.idx = 0;
  402. }
  403. static void
  404. action_osc_end(struct terminal *term, uint8_t c)
  405. {
  406. if (!osc_ensure_size(term, term->vt.osc.idx + 1))
  407. return;
  408. term->vt.osc.data[term->vt.osc.idx] = '\0';
  409. osc_dispatch(term);
  410. }
  411. static void
  412. action_osc_put(struct terminal *term, uint8_t c)
  413. {
  414. if (!osc_ensure_size(term, term->vt.osc.idx + 1))
  415. return;
  416. term->vt.osc.data[term->vt.osc.idx++] = c;
  417. }
  418. static void
  419. action_hook(struct terminal *term, uint8_t c)
  420. {
  421. dcs_hook(term, c);
  422. }
  423. static void
  424. action_unhook(struct terminal *term, uint8_t c)
  425. {
  426. dcs_unhook(term);
  427. }
  428. static void
  429. action_put(struct terminal *term, uint8_t c)
  430. {
  431. dcs_put(term, c);
  432. }
  433. static void
  434. action_utf8_print(struct terminal *term, wchar_t wc)
  435. {
  436. int width = wcwidth(wc);
  437. /*
  438. * Is this is combining character? The basic assumption is that if
  439. * wcwdith() returns 0, then it *is* a combining character.
  440. *
  441. * We hen optimize this by ignoring all characters before 0x0300,
  442. * since there aren't any zero-width characters there. This means
  443. * all "normal" western characters will quickly be categorized as
  444. * *not* being combining characters.
  445. *
  446. * TODO: xterm does more or less the same, but also filters a
  447. * small subset of BIDI control characters. Should we too? I think
  448. * what we have here is good enough - a control character
  449. * shouldn't have a glyph associated with it, so rendering
  450. * shouldn't be affected.
  451. *
  452. * TODO: handle line-wrap when locating the base character.
  453. */
  454. if (width == 0 && wc >= 0x0300 && term->grid->cursor.point.col > 0) {
  455. const struct row *row = term->grid->cur_row;
  456. int base_col = term->grid->cursor.point.col;
  457. if (!term->grid->cursor.lcf)
  458. base_col--;
  459. while (row->cells[base_col].wc == CELL_MULT_COL_SPACER && base_col > 0)
  460. base_col--;
  461. assert(base_col >= 0 && base_col < term->cols);
  462. wchar_t base = row->cells[base_col].wc;
  463. const struct composed *composed =
  464. (base >= CELL_COMB_CHARS_LO &&
  465. base < (CELL_COMB_CHARS_LO + term->composed_count))
  466. ? &term->composed[base - CELL_COMB_CHARS_LO]
  467. : NULL;
  468. if (composed != NULL)
  469. base = composed->base;
  470. int base_width = wcwidth(base);
  471. if (base != 0 && base_width > 0) {
  472. /*
  473. * If this is the *first* combining characger, see if
  474. * there's a pre-composed character of this combo, with
  475. * the same column width as the base character.
  476. *
  477. * If there is, replace the base character with the
  478. * pre-composed character, as that is likely to produce a
  479. * better looking result.
  480. */
  481. term->grid->cursor.point.col = base_col;
  482. term->grid->cursor.lcf = false;
  483. if (composed == NULL) {
  484. bool base_from_primary;
  485. bool comb_from_primary;
  486. bool pre_from_primary;
  487. wchar_t precomposed = fcft_precompose(
  488. term->fonts[0], base, wc, &base_from_primary,
  489. &comb_from_primary, &pre_from_primary);
  490. int precomposed_width = wcwidth(precomposed);
  491. /*
  492. * Only use the pre-composed character if:
  493. *
  494. * 1. we *have* a pre-composed character
  495. * 2. the width matches the base characters width
  496. * 3. it's in the primary font, OR one of the base or
  497. * combining characters are *not* from the primary
  498. * font
  499. */
  500. if (precomposed != (wchar_t)-1 &&
  501. precomposed_width == base_width &&
  502. (pre_from_primary ||
  503. !base_from_primary ||
  504. !comb_from_primary))
  505. {
  506. term_print(term, precomposed, precomposed_width);
  507. return;
  508. }
  509. }
  510. size_t wanted_count = composed != NULL ? composed->count + 1 : 1;
  511. if (wanted_count > ALEN(composed->combining)) {
  512. assert(composed != NULL);
  513. #if defined(LOG_ENABLE_DBG) && LOG_ENABLE_DBG
  514. LOG_WARN("combining character overflow:");
  515. LOG_WARN(" base: 0x%04x", composed->base);
  516. for (size_t i = 0; i < composed->count; i++)
  517. LOG_WARN(" cc: 0x%04x", composed->combining[i]);
  518. LOG_ERR(" new: 0x%04x", wc);
  519. #endif
  520. /* This are going to break anyway... */
  521. wanted_count--;
  522. }
  523. assert(wanted_count <= ALEN(composed->combining));
  524. /* Look for existing combining chain */
  525. for (size_t i = 0; i < term->composed_count; i++) {
  526. const struct composed *cc = &term->composed[i];
  527. if (cc->base != base)
  528. continue;
  529. if (cc->count != wanted_count)
  530. continue;
  531. if (cc->combining[wanted_count - 1] != wc)
  532. continue;
  533. term_print(term, CELL_COMB_CHARS_LO + i, base_width);
  534. return;
  535. }
  536. /* Allocate new chain */
  537. struct composed new_cc;
  538. new_cc.base = base;
  539. new_cc.count = wanted_count;
  540. for (size_t i = 0; i < wanted_count - 1; i++)
  541. new_cc.combining[i] = composed->combining[i];
  542. new_cc.combining[wanted_count - 1] = wc;
  543. if (term->composed_count < CELL_COMB_CHARS_HI) {
  544. term->composed_count++;
  545. term->composed = xrealloc(term->composed, term->composed_count * sizeof(term->composed[0]));
  546. term->composed[term->composed_count - 1] = new_cc;
  547. term_print(term, CELL_COMB_CHARS_LO + term->composed_count - 1, base_width);
  548. return;
  549. } else {
  550. /* We reached our maximum number of allowed composed
  551. * character chains. Fall through here and print the
  552. * current zero-width character to the current cell */
  553. LOG_WARN("maximum number of composed characters reached");
  554. }
  555. }
  556. }
  557. if (width > 0)
  558. term_print(term, wc, width);
  559. }
  560. static void
  561. action_utf8_21(struct terminal *term, uint8_t c)
  562. {
  563. // wc = ((utf8[0] & 0x1f) << 6) | (utf8[1] & 0x3f)
  564. term->vt.utf8 = (c & 0x1f) << 6;
  565. }
  566. static void
  567. action_utf8_22(struct terminal *term, uint8_t c)
  568. {
  569. // wc = ((utf8[0] & 0x1f) << 6) | (utf8[1] & 0x3f)
  570. term->vt.utf8 |= c & 0x3f;
  571. action_utf8_print(term, term->vt.utf8);
  572. }
  573. static void
  574. action_utf8_31(struct terminal *term, uint8_t c)
  575. {
  576. // wc = ((utf8[0] & 0xf) << 12) | ((utf8[1] & 0x3f) << 6) | (utf8[2] & 0x3f)
  577. term->vt.utf8 = (c & 0x0f) << 12;
  578. }
  579. static void
  580. action_utf8_32(struct terminal *term, uint8_t c)
  581. {
  582. // wc = ((utf8[0] & 0xf) << 12) | ((utf8[1] & 0x3f) << 6) | (utf8[2] & 0x3f)
  583. term->vt.utf8 |= (c & 0x3f) << 6;
  584. }
  585. static void
  586. action_utf8_33(struct terminal *term, uint8_t c)
  587. {
  588. // wc = ((utf8[0] & 0xf) << 12) | ((utf8[1] & 0x3f) << 6) | (utf8[2] & 0x3f)
  589. term->vt.utf8 |= c & 0x3f;
  590. action_utf8_print(term, term->vt.utf8);
  591. }
  592. static void
  593. action_utf8_41(struct terminal *term, uint8_t c)
  594. {
  595. // wc = ((utf8[0] & 7) << 18) | ((utf8[1] & 0x3f) << 12) | ((utf8[2] & 0x3f) << 6) | (utf8[3] & 0x3f);
  596. term->vt.utf8 = (c & 0x07) << 18;
  597. }
  598. static void
  599. action_utf8_42(struct terminal *term, uint8_t c)
  600. {
  601. // wc = ((utf8[0] & 7) << 18) | ((utf8[1] & 0x3f) << 12) | ((utf8[2] & 0x3f) << 6) | (utf8[3] & 0x3f);
  602. term->vt.utf8 |= (c & 0x3f) << 12;
  603. }
  604. static void
  605. action_utf8_43(struct terminal *term, uint8_t c)
  606. {
  607. // wc = ((utf8[0] & 7) << 18) | ((utf8[1] & 0x3f) << 12) | ((utf8[2] & 0x3f) << 6) | (utf8[3] & 0x3f);
  608. term->vt.utf8 |= (c & 0x3f) << 6;
  609. }
  610. static void
  611. action_utf8_44(struct terminal *term, uint8_t c)
  612. {
  613. // wc = ((utf8[0] & 7) << 18) | ((utf8[1] & 0x3f) << 12) | ((utf8[2] & 0x3f) << 6) | (utf8[3] & 0x3f);
  614. term->vt.utf8 |= c & 0x3f;
  615. action_utf8_print(term, term->vt.utf8);
  616. }
  617. #if defined(__GNUC__)
  618. #pragma GCC diagnostic push
  619. #pragma GCC diagnostic ignored "-Wpedantic"
  620. #endif
  621. static enum state
  622. state_ground_switch(struct terminal *term, uint8_t data)
  623. {
  624. switch (data) {
  625. /* exit current enter new state */
  626. case 0x00 ... 0x17:
  627. case 0x19:
  628. case 0x1c ... 0x1f: action_execute(term, data); return STATE_GROUND;
  629. /* modified from 0x20..0x7f to 0x20..0x7e, since 0x7f is DEL, which is a zero-width character */
  630. case 0x20 ... 0x7e: action_print(term, data); return STATE_GROUND;
  631. case 0xc2 ... 0xdf: action_utf8_21(term, data); return STATE_UTF8_21;
  632. case 0xe0 ... 0xef: action_utf8_31(term, data); return STATE_UTF8_31;
  633. case 0xf0 ... 0xf4: action_utf8_41(term, data); return STATE_UTF8_41;
  634. /* Anywhere */
  635. case 0x18: action_execute(term, data); return STATE_GROUND;
  636. case 0x1a: action_execute(term, data); return STATE_GROUND;
  637. case 0x1b: action_clear(term); return STATE_ESCAPE;
  638. case 0x80 ... 0x8f: action_execute(term, data); return STATE_GROUND;
  639. case 0x90: action_clear(term); return STATE_DCS_ENTRY;
  640. case 0x91 ... 0x97: action_execute(term, data); return STATE_GROUND;
  641. case 0x98: return STATE_SOS_PM_APC_STRING;
  642. case 0x99: action_execute(term, data); return STATE_GROUND;
  643. case 0x9a: action_execute(term, data); return STATE_GROUND;
  644. case 0x9b: action_clear(term); return STATE_CSI_ENTRY;
  645. case 0x9c: return STATE_GROUND;
  646. case 0x9d: action_osc_start(term, data); return STATE_OSC_STRING;
  647. case 0x9e ... 0x9f: return STATE_SOS_PM_APC_STRING;
  648. default: return STATE_GROUND;
  649. }
  650. }
  651. static enum state
  652. state_escape_switch(struct terminal *term, uint8_t data)
  653. {
  654. switch (data) {
  655. /* exit current enter new state */
  656. case 0x00 ... 0x17:
  657. case 0x19:
  658. case 0x1c ... 0x1f: action_execute(term, data); return STATE_ESCAPE;
  659. case 0x20 ... 0x2f: action_collect(term, data); return STATE_ESCAPE_INTERMEDIATE;
  660. case 0x30 ... 0x4f: action_esc_dispatch(term, data); return STATE_GROUND;
  661. case 0x50: action_clear(term); return STATE_DCS_ENTRY;
  662. case 0x51 ... 0x57: action_esc_dispatch(term, data); return STATE_GROUND;
  663. case 0x58: return STATE_SOS_PM_APC_STRING;
  664. case 0x59: action_esc_dispatch(term, data); return STATE_GROUND;
  665. case 0x5a: action_esc_dispatch(term, data); return STATE_GROUND;
  666. case 0x5b: action_clear(term); return STATE_CSI_ENTRY;
  667. case 0x5c: action_esc_dispatch(term, data); return STATE_GROUND;
  668. case 0x5d: action_osc_start(term, data); return STATE_OSC_STRING;
  669. case 0x5e ... 0x5f: return STATE_SOS_PM_APC_STRING;
  670. case 0x60 ... 0x7e: action_esc_dispatch(term, data); return STATE_GROUND;
  671. case 0x7f: action_ignore(term); return STATE_ESCAPE;
  672. /* Anywhere */
  673. case 0x18: action_execute(term, data); return STATE_GROUND;
  674. case 0x1a: action_execute(term, data); return STATE_GROUND;
  675. case 0x1b: action_clear(term); return STATE_ESCAPE;
  676. case 0x80 ... 0x8f: action_execute(term, data); return STATE_GROUND;
  677. case 0x90: action_clear(term); return STATE_DCS_ENTRY;
  678. case 0x91 ... 0x97: action_execute(term, data); return STATE_GROUND;
  679. case 0x98: return STATE_SOS_PM_APC_STRING;
  680. case 0x99: action_execute(term, data); return STATE_GROUND;
  681. case 0x9a: action_execute(term, data); return STATE_GROUND;
  682. case 0x9b: action_clear(term); return STATE_CSI_ENTRY;
  683. case 0x9c: return STATE_GROUND;
  684. case 0x9d: action_osc_start(term, data); return STATE_OSC_STRING;
  685. case 0x9e ... 0x9f: return STATE_SOS_PM_APC_STRING;
  686. default: return STATE_ESCAPE;
  687. }
  688. }
  689. static enum state
  690. state_escape_intermediate_switch(struct terminal *term, uint8_t data)
  691. {
  692. switch (data) {
  693. /* exit current enter new state */
  694. case 0x00 ... 0x17:
  695. case 0x19:
  696. case 0x1c ... 0x1f: action_execute(term, data); return STATE_ESCAPE_INTERMEDIATE;
  697. case 0x20 ... 0x2f: action_collect(term, data); return STATE_ESCAPE_INTERMEDIATE;
  698. case 0x30 ... 0x7e: action_esc_dispatch(term, data); return STATE_GROUND;
  699. case 0x7f: action_ignore(term); return STATE_ESCAPE_INTERMEDIATE;
  700. /* Anywhere */
  701. case 0x18: action_execute(term, data); return STATE_GROUND;
  702. case 0x1a: action_execute(term, data); return STATE_GROUND;
  703. case 0x1b: action_clear(term); return STATE_ESCAPE;
  704. case 0x80 ... 0x8f: action_execute(term, data); return STATE_GROUND;
  705. case 0x90: action_clear(term); return STATE_DCS_ENTRY;
  706. case 0x91 ... 0x97: action_execute(term, data); return STATE_GROUND;
  707. case 0x98: return STATE_SOS_PM_APC_STRING;
  708. case 0x99: action_execute(term, data); return STATE_GROUND;
  709. case 0x9a: action_execute(term, data); return STATE_GROUND;
  710. case 0x9b: action_clear(term); return STATE_CSI_ENTRY;
  711. case 0x9c: return STATE_GROUND;
  712. case 0x9d: action_osc_start(term, data); return STATE_OSC_STRING;
  713. case 0x9e ... 0x9f: return STATE_SOS_PM_APC_STRING;
  714. default: return STATE_ESCAPE_INTERMEDIATE;
  715. }
  716. }
  717. static enum state
  718. state_csi_entry_switch(struct terminal *term, uint8_t data)
  719. {
  720. switch (data) {
  721. /* exit current enter new state */
  722. case 0x00 ... 0x17:
  723. case 0x19:
  724. case 0x1c ... 0x1f: action_execute(term, data); return STATE_CSI_ENTRY;
  725. case 0x20 ... 0x2f: action_collect(term, data); return STATE_CSI_INTERMEDIATE;
  726. case 0x30 ... 0x39: action_param(term, data); return STATE_CSI_PARAM;
  727. case 0x3a ... 0x3b: action_param(term, data); return STATE_CSI_PARAM;
  728. case 0x3c ... 0x3f: action_collect(term, data); return STATE_CSI_PARAM;
  729. case 0x40 ... 0x7e: action_csi_dispatch(term, data); return STATE_GROUND;
  730. case 0x7f: action_ignore(term); return STATE_CSI_ENTRY;
  731. /* Anywhere */
  732. case 0x18: action_execute(term, data); return STATE_GROUND;
  733. case 0x1a: action_execute(term, data); return STATE_GROUND;
  734. case 0x1b: action_clear(term); return STATE_ESCAPE;
  735. case 0x80 ... 0x8f: action_execute(term, data); return STATE_GROUND;
  736. case 0x90: action_clear(term); return STATE_DCS_ENTRY;
  737. case 0x91 ... 0x97: action_execute(term, data); return STATE_GROUND;
  738. case 0x98: return STATE_SOS_PM_APC_STRING;
  739. case 0x99: action_execute(term, data); return STATE_GROUND;
  740. case 0x9a: action_execute(term, data); return STATE_GROUND;
  741. case 0x9b: action_clear(term); return STATE_CSI_ENTRY;
  742. case 0x9c: return STATE_GROUND;
  743. case 0x9d: action_osc_start(term, data); return STATE_OSC_STRING;
  744. case 0x9e ... 0x9f: return STATE_SOS_PM_APC_STRING;
  745. default: return STATE_CSI_ENTRY;
  746. }
  747. }
  748. static enum state
  749. state_csi_param_switch(struct terminal *term, uint8_t data)
  750. {
  751. switch (data) {
  752. /* exit current enter new state */
  753. case 0x00 ... 0x17:
  754. case 0x19:
  755. case 0x1c ... 0x1f: action_execute(term, data); return STATE_CSI_PARAM;
  756. case 0x20 ... 0x2f: action_collect(term, data); return STATE_CSI_INTERMEDIATE;
  757. case 0x30 ... 0x39:
  758. case 0x3a ... 0x3b: action_param(term, data); return STATE_CSI_PARAM;
  759. case 0x3c ... 0x3f: return STATE_CSI_IGNORE;
  760. case 0x40 ... 0x7e: action_csi_dispatch(term, data); return STATE_GROUND;
  761. case 0x7f: action_ignore(term); return STATE_CSI_PARAM;
  762. /* Anywhere */
  763. case 0x18: action_execute(term, data); return STATE_GROUND;
  764. case 0x1a: action_execute(term, data); return STATE_GROUND;
  765. case 0x1b: action_clear(term); return STATE_ESCAPE;
  766. case 0x80 ... 0x8f: action_execute(term, data); return STATE_GROUND;
  767. case 0x90: action_clear(term); return STATE_DCS_ENTRY;
  768. case 0x91 ... 0x97: action_execute(term, data); return STATE_GROUND;
  769. case 0x98: return STATE_SOS_PM_APC_STRING;
  770. case 0x99: action_execute(term, data); return STATE_GROUND;
  771. case 0x9a: action_execute(term, data); return STATE_GROUND;
  772. case 0x9b: action_clear(term); return STATE_CSI_ENTRY;
  773. case 0x9c: return STATE_GROUND;
  774. case 0x9d: action_osc_start(term, data); return STATE_OSC_STRING;
  775. case 0x9e ... 0x9f: return STATE_SOS_PM_APC_STRING;
  776. default: return STATE_CSI_PARAM;
  777. }
  778. }
  779. static enum state
  780. state_csi_intermediate_switch(struct terminal *term, uint8_t data)
  781. {
  782. switch (data) {
  783. /* exit current enter new state */
  784. case 0x00 ... 0x17:
  785. case 0x19:
  786. case 0x1c ... 0x1f: action_execute(term, data); return STATE_CSI_INTERMEDIATE;
  787. case 0x20 ... 0x2f: action_collect(term, data); return STATE_CSI_INTERMEDIATE;
  788. case 0x30 ... 0x3f: return STATE_CSI_IGNORE;
  789. case 0x40 ... 0x7e: action_csi_dispatch(term, data); return STATE_GROUND;
  790. case 0x7f: action_ignore(term); return STATE_CSI_INTERMEDIATE;
  791. /* Anywhere */
  792. case 0x18: action_execute(term, data); return STATE_GROUND;
  793. case 0x1a: action_execute(term, data); return STATE_GROUND;
  794. case 0x1b: action_clear(term); return STATE_ESCAPE;
  795. case 0x80 ... 0x8f: action_execute(term, data); return STATE_GROUND;
  796. case 0x90: action_clear(term); return STATE_DCS_ENTRY;
  797. case 0x91 ... 0x97: action_execute(term, data); return STATE_GROUND;
  798. case 0x98: return STATE_SOS_PM_APC_STRING;
  799. case 0x99: action_execute(term, data); return STATE_GROUND;
  800. case 0x9a: action_execute(term, data); return STATE_GROUND;
  801. case 0x9b: action_clear(term); return STATE_CSI_ENTRY;
  802. case 0x9c: return STATE_GROUND;
  803. case 0x9d: action_osc_start(term, data); return STATE_OSC_STRING;
  804. case 0x9e ... 0x9f: return STATE_SOS_PM_APC_STRING;
  805. default: return STATE_CSI_INTERMEDIATE;
  806. }
  807. }
  808. static enum state
  809. state_csi_ignore_switch(struct terminal *term, uint8_t data)
  810. {
  811. switch (data) {
  812. /* exit current enter new state */
  813. case 0x00 ... 0x17:
  814. case 0x19:
  815. case 0x1c ... 0x1f: action_execute(term, data); return STATE_CSI_IGNORE;
  816. case 0x20 ... 0x3f: action_ignore(term); return STATE_CSI_IGNORE;
  817. case 0x40 ... 0x7e: return STATE_GROUND;
  818. case 0x7f: action_ignore(term); return STATE_CSI_IGNORE;
  819. /* Anywhere */
  820. case 0x18: action_execute(term, data); return STATE_GROUND;
  821. case 0x1a: action_execute(term, data); return STATE_GROUND;
  822. case 0x1b: action_clear(term); return STATE_ESCAPE;
  823. case 0x80 ... 0x8f: action_execute(term, data); return STATE_GROUND;
  824. case 0x90: action_clear(term); return STATE_DCS_ENTRY;
  825. case 0x91 ... 0x97: action_execute(term, data); return STATE_GROUND;
  826. case 0x98: return STATE_SOS_PM_APC_STRING;
  827. case 0x99: action_execute(term, data); return STATE_GROUND;
  828. case 0x9a: action_execute(term, data); return STATE_GROUND;
  829. case 0x9b: action_clear(term); return STATE_CSI_ENTRY;
  830. case 0x9c: return STATE_GROUND;
  831. case 0x9d: action_osc_start(term, data); return STATE_OSC_STRING;
  832. case 0x9e ... 0x9f: return STATE_SOS_PM_APC_STRING;
  833. default: return STATE_CSI_IGNORE;
  834. }
  835. }
  836. static enum state
  837. state_osc_string_switch(struct terminal *term, uint8_t data)
  838. {
  839. switch (data) {
  840. /* exit current enter new state */
  841. /* Note: original was 20-7f, but I changed to 20-ff to include utf-8. Don't forget to add EXECUTE to 8-bit C1 if we implement that. */
  842. default: action_osc_put(term, data); return STATE_OSC_STRING;
  843. case 0x07: action_osc_end(term, data); return STATE_GROUND;
  844. case 0x00 ... 0x06:
  845. case 0x08 ... 0x17:
  846. case 0x19:
  847. case 0x1c ... 0x1f: action_ignore(term); return STATE_OSC_STRING;
  848. case 0x18:
  849. case 0x1a: action_osc_end(term, data); action_execute(term, data); return STATE_GROUND;
  850. case 0x1b: action_osc_end(term, data); action_clear(term); return STATE_ESCAPE;
  851. }
  852. }
  853. static enum state
  854. state_dcs_entry_switch(struct terminal *term, uint8_t data)
  855. {
  856. switch (data) {
  857. /* exit current enter new state */
  858. case 0x00 ... 0x17:
  859. case 0x19:
  860. case 0x1c ... 0x1f: action_ignore(term); return STATE_DCS_ENTRY;
  861. case 0x20 ... 0x2f: action_collect(term, data); return STATE_DCS_INTERMEDIATE;
  862. case 0x30 ... 0x39: action_param(term, data); return STATE_DCS_PARAM;
  863. case 0x3a: return STATE_DCS_IGNORE;
  864. case 0x3b: action_param(term, data); return STATE_DCS_PARAM;
  865. case 0x3c ... 0x3f: action_collect(term, data); return STATE_DCS_PARAM;
  866. case 0x40 ... 0x7e: action_hook(term, data); return STATE_DCS_PASSTHROUGH;
  867. case 0x7f: action_ignore(term); return STATE_DCS_ENTRY;
  868. /* Anywhere */
  869. case 0x18: action_execute(term, data); return STATE_GROUND;
  870. case 0x1a: action_execute(term, data); return STATE_GROUND;
  871. case 0x1b: action_clear(term); return STATE_ESCAPE;
  872. case 0x80 ... 0x8f: action_execute(term, data); return STATE_GROUND;
  873. case 0x90: action_clear(term); return STATE_DCS_ENTRY;
  874. case 0x91 ... 0x97: action_execute(term, data); return STATE_GROUND;
  875. case 0x98: return STATE_SOS_PM_APC_STRING;
  876. case 0x99: action_execute(term, data); return STATE_GROUND;
  877. case 0x9a: action_execute(term, data); return STATE_GROUND;
  878. case 0x9b: action_clear(term); return STATE_CSI_ENTRY;
  879. case 0x9c: return STATE_GROUND;
  880. case 0x9d: action_osc_start(term, data); return STATE_OSC_STRING;
  881. case 0x9e ... 0x9f: return STATE_SOS_PM_APC_STRING;
  882. default: return STATE_DCS_ENTRY;
  883. }
  884. }
  885. static enum state
  886. state_dcs_param_switch(struct terminal *term, uint8_t data)
  887. {
  888. switch (data) {
  889. /* exit current enter new state */
  890. case 0x00 ... 0x17:
  891. case 0x19:
  892. case 0x1c ... 0x1f: action_ignore(term); return STATE_DCS_PARAM;
  893. case 0x20 ... 0x2f: action_collect(term, data); return STATE_DCS_INTERMEDIATE;
  894. case 0x30 ... 0x39: action_param(term, data); return STATE_DCS_PARAM;
  895. case 0x3a: return STATE_DCS_IGNORE;
  896. case 0x3b: action_param(term, data); return STATE_DCS_PARAM;
  897. case 0x3c ... 0x3f: return STATE_DCS_IGNORE;
  898. case 0x40 ... 0x7e: action_hook(term, data); return STATE_DCS_PASSTHROUGH;
  899. case 0x7f: action_ignore(term); return STATE_DCS_PARAM;
  900. /* Anywhere */
  901. case 0x18: action_execute(term, data); return STATE_GROUND;
  902. case 0x1a: action_execute(term, data); return STATE_GROUND;
  903. case 0x1b: action_clear(term); return STATE_ESCAPE;
  904. case 0x80 ... 0x8f: action_execute(term, data); return STATE_GROUND;
  905. case 0x90: action_clear(term); return STATE_DCS_ENTRY;
  906. case 0x91 ... 0x97: action_execute(term, data); return STATE_GROUND;
  907. case 0x98: return STATE_SOS_PM_APC_STRING;
  908. case 0x99: action_execute(term, data); return STATE_GROUND;
  909. case 0x9a: action_execute(term, data); return STATE_GROUND;
  910. case 0x9b: action_clear(term); return STATE_CSI_ENTRY;
  911. case 0x9c: return STATE_GROUND;
  912. case 0x9d: action_osc_start(term, data); return STATE_OSC_STRING;
  913. case 0x9e ... 0x9f: return STATE_SOS_PM_APC_STRING;
  914. default: return STATE_DCS_PARAM;
  915. }
  916. }
  917. static enum state
  918. state_dcs_intermediate_switch(struct terminal *term, uint8_t data)
  919. {
  920. switch (data) {
  921. /* exit current enter new state */
  922. case 0x00 ... 0x17:
  923. case 0x19:
  924. case 0x1c ... 0x1f: action_ignore(term); return STATE_DCS_INTERMEDIATE;
  925. case 0x20 ... 0x2f: action_collect(term, data); return STATE_DCS_INTERMEDIATE;
  926. case 0x30 ... 0x3f: return STATE_DCS_IGNORE;
  927. case 0x40 ... 0x7e: action_hook(term, data); return STATE_DCS_PASSTHROUGH;
  928. case 0x7f: action_ignore(term); return STATE_DCS_INTERMEDIATE;
  929. /* Anywhere */
  930. case 0x18: action_execute(term, data); return STATE_GROUND;
  931. case 0x1a: action_execute(term, data); return STATE_GROUND;
  932. case 0x1b: action_clear(term); return STATE_ESCAPE;
  933. case 0x80 ... 0x8f: action_execute(term, data); return STATE_GROUND;
  934. case 0x90: action_clear(term); return STATE_DCS_ENTRY;
  935. case 0x91 ... 0x97: action_execute(term, data); return STATE_GROUND;
  936. case 0x98: return STATE_SOS_PM_APC_STRING;
  937. case 0x99: action_execute(term, data); return STATE_GROUND;
  938. case 0x9a: action_execute(term, data); return STATE_GROUND;
  939. case 0x9b: action_clear(term); return STATE_CSI_ENTRY;
  940. case 0x9c: return STATE_GROUND;
  941. case 0x9d: action_osc_start(term, data); return STATE_OSC_STRING;
  942. case 0x9e ... 0x9f: return STATE_SOS_PM_APC_STRING;
  943. default: return STATE_DCS_INTERMEDIATE;
  944. }
  945. }
  946. static enum state
  947. state_dcs_ignore_switch(struct terminal *term, uint8_t data)
  948. {
  949. switch (data) {
  950. /* exit current enter new state */
  951. case 0x00 ... 0x17:
  952. case 0x19:
  953. case 0x1c ... 0x1f:
  954. case 0x20 ... 0x7f: action_ignore(term); return STATE_DCS_IGNORE;
  955. /* Anywhere */
  956. case 0x18: action_execute(term, data); return STATE_GROUND;
  957. case 0x1a: action_execute(term, data); return STATE_GROUND;
  958. case 0x1b: action_clear(term); return STATE_ESCAPE;
  959. case 0x80 ... 0x8f: action_execute(term, data); return STATE_GROUND;
  960. case 0x90: action_clear(term); return STATE_DCS_ENTRY;
  961. case 0x91 ... 0x97: action_execute(term, data); return STATE_GROUND;
  962. case 0x98: return STATE_SOS_PM_APC_STRING;
  963. case 0x99: action_execute(term, data); return STATE_GROUND;
  964. case 0x9a: action_execute(term, data); return STATE_GROUND;
  965. case 0x9b: action_clear(term); return STATE_CSI_ENTRY;
  966. case 0x9c: return STATE_GROUND;
  967. case 0x9d: action_osc_start(term, data); return STATE_OSC_STRING;
  968. case 0x9e ... 0x9f: return STATE_SOS_PM_APC_STRING;
  969. default: return STATE_DCS_IGNORE;
  970. }
  971. }
  972. static enum state
  973. state_dcs_passthrough_switch(struct terminal *term, uint8_t data)
  974. {
  975. switch (data) {
  976. /* exit current enter new state */
  977. case 0x00 ... 0x17:
  978. case 0x19:
  979. case 0x1c ... 0x7e: action_put(term, data); return STATE_DCS_PASSTHROUGH;
  980. case 0x7f: action_ignore(term); return STATE_DCS_PASSTHROUGH;
  981. /* Anywhere */
  982. case 0x18: action_unhook(term, data); action_execute(term, data); return STATE_GROUND;
  983. case 0x1a: action_unhook(term, data); action_execute(term, data); return STATE_GROUND;
  984. case 0x1b: action_unhook(term, data); action_clear(term); return STATE_ESCAPE;
  985. case 0x80 ... 0x8f: action_unhook(term, data); action_execute(term, data); return STATE_GROUND;
  986. case 0x90: action_unhook(term, data); action_clear(term); return STATE_DCS_ENTRY;
  987. case 0x91 ... 0x97: action_unhook(term, data); action_execute(term, data); return STATE_GROUND;
  988. case 0x98: action_unhook(term, data); return STATE_SOS_PM_APC_STRING;
  989. case 0x99: action_unhook(term, data); action_execute(term, data); return STATE_GROUND;
  990. case 0x9a: action_unhook(term, data); action_execute(term, data); return STATE_GROUND;
  991. case 0x9b: action_unhook(term, data); action_clear(term); return STATE_CSI_ENTRY;
  992. case 0x9c: action_unhook(term, data); return STATE_GROUND;
  993. case 0x9d: action_unhook(term, data); action_osc_start(term, data); return STATE_OSC_STRING;
  994. case 0x9e ... 0x9f: action_unhook(term, data); return STATE_SOS_PM_APC_STRING;
  995. default: return STATE_DCS_PASSTHROUGH;
  996. }
  997. }
  998. static enum state
  999. state_sos_pm_apc_string_switch(struct terminal *term, uint8_t data)
  1000. {
  1001. switch (data) {
  1002. /* exit current enter new state */
  1003. case 0x00 ... 0x17:
  1004. case 0x19:
  1005. case 0x1c ... 0x7f: action_ignore(term); return STATE_SOS_PM_APC_STRING;
  1006. /* Anywhere */
  1007. case 0x18: action_execute(term, data); return STATE_GROUND;
  1008. case 0x1a: action_execute(term, data); return STATE_GROUND;
  1009. case 0x1b: action_clear(term); return STATE_ESCAPE;
  1010. case 0x80 ... 0x8f: action_execute(term, data); return STATE_GROUND;
  1011. case 0x90: action_clear(term); return STATE_DCS_ENTRY;
  1012. case 0x91 ... 0x97: action_execute(term, data); return STATE_GROUND;
  1013. case 0x98: return STATE_SOS_PM_APC_STRING;
  1014. case 0x99: action_execute(term, data); return STATE_GROUND;
  1015. case 0x9a: action_execute(term, data); return STATE_GROUND;
  1016. case 0x9b: action_clear(term); return STATE_CSI_ENTRY;
  1017. case 0x9c: return STATE_GROUND;
  1018. case 0x9d: action_osc_start(term, data); return STATE_OSC_STRING;
  1019. case 0x9e ... 0x9f: return STATE_SOS_PM_APC_STRING;
  1020. default: return STATE_SOS_PM_APC_STRING;
  1021. }
  1022. }
  1023. static enum state
  1024. state_utf8_21_switch(struct terminal *term, uint8_t data)
  1025. {
  1026. switch (data) {
  1027. /* exit current enter new state */
  1028. case 0x80 ... 0xbf: action_utf8_22(term, data); return STATE_GROUND;
  1029. default: action_utf8_print(term, 0); return STATE_GROUND;
  1030. }
  1031. }
  1032. static enum state
  1033. state_utf8_31_switch(struct terminal *term, uint8_t data)
  1034. {
  1035. switch (data) {
  1036. /* exit current enter new state */
  1037. case 0x80 ... 0xbf: action_utf8_32(term, data); return STATE_UTF8_32;
  1038. default: action_utf8_print(term, 0); return STATE_GROUND;
  1039. }
  1040. }
  1041. static enum state
  1042. state_utf8_32_switch(struct terminal *term, uint8_t data)
  1043. {
  1044. switch (data) {
  1045. /* exit current enter new state */
  1046. case 0x80 ... 0xbf: action_utf8_33(term, data); return STATE_GROUND;
  1047. default: action_utf8_print(term, 0); return STATE_GROUND;
  1048. }
  1049. }
  1050. static enum state
  1051. state_utf8_41_switch(struct terminal *term, uint8_t data)
  1052. {
  1053. switch (data) {
  1054. /* exit current enter new state */
  1055. case 0x80 ... 0xbf: action_utf8_42(term, data); return STATE_UTF8_42;
  1056. default: action_utf8_print(term, 0); return STATE_GROUND;
  1057. }
  1058. }
  1059. static enum state
  1060. state_utf8_42_switch(struct terminal *term, uint8_t data)
  1061. {
  1062. switch (data) {
  1063. /* exit current enter new state */
  1064. case 0x80 ... 0xbf: action_utf8_43(term, data); return STATE_UTF8_43;
  1065. default: action_utf8_print(term, 0); return STATE_GROUND;
  1066. }
  1067. }
  1068. static enum state
  1069. state_utf8_43_switch(struct terminal *term, uint8_t data)
  1070. {
  1071. switch (data) {
  1072. /* exit current enter new state */
  1073. case 0x80 ... 0xbf: action_utf8_44(term, data); return STATE_GROUND;
  1074. default: action_utf8_print(term, 0); return STATE_GROUND;
  1075. }
  1076. }
  1077. #if defined(__GNUC__)
  1078. #pragma GCC diagnostic pop
  1079. #endif
  1080. void
  1081. vt_from_slave(struct terminal *term, const uint8_t *data, size_t len)
  1082. {
  1083. enum state current_state = term->vt.state;
  1084. const uint8_t *p = data;
  1085. for (size_t i = 0; i < len; i++, p++) {
  1086. switch (current_state) {
  1087. case STATE_GROUND: current_state = state_ground_switch(term, *p); break;
  1088. case STATE_ESCAPE: current_state = state_escape_switch(term, *p); break;
  1089. case STATE_ESCAPE_INTERMEDIATE: current_state = state_escape_intermediate_switch(term, *p); break;
  1090. case STATE_CSI_ENTRY: current_state = state_csi_entry_switch(term, *p); break;
  1091. case STATE_CSI_PARAM: current_state = state_csi_param_switch(term, *p); break;
  1092. case STATE_CSI_INTERMEDIATE: current_state = state_csi_intermediate_switch(term, *p); break;
  1093. case STATE_CSI_IGNORE: current_state = state_csi_ignore_switch(term, *p); break;
  1094. case STATE_OSC_STRING: current_state = state_osc_string_switch(term, *p); break;
  1095. case STATE_DCS_ENTRY: current_state = state_dcs_entry_switch(term, *p); break;
  1096. case STATE_DCS_PARAM: current_state = state_dcs_param_switch(term, *p); break;
  1097. case STATE_DCS_INTERMEDIATE: current_state = state_dcs_intermediate_switch(term, *p); break;
  1098. case STATE_DCS_IGNORE: current_state = state_dcs_ignore_switch(term, *p); break;
  1099. case STATE_DCS_PASSTHROUGH: current_state = state_dcs_passthrough_switch(term, *p); break;
  1100. case STATE_SOS_PM_APC_STRING: current_state = state_sos_pm_apc_string_switch(term, *p); break;
  1101. case STATE_UTF8_21: current_state = state_utf8_21_switch(term, *p); break;
  1102. case STATE_UTF8_31: current_state = state_utf8_31_switch(term, *p); break;
  1103. case STATE_UTF8_32: current_state = state_utf8_32_switch(term, *p); break;
  1104. case STATE_UTF8_41: current_state = state_utf8_41_switch(term, *p); break;
  1105. case STATE_UTF8_42: current_state = state_utf8_42_switch(term, *p); break;
  1106. case STATE_UTF8_43: current_state = state_utf8_43_switch(term, *p); break;
  1107. }
  1108. }
  1109. term->vt.state = current_state;
  1110. }