#include #include #include #include "terminal_vt100.h" static unsigned int get_mode_mask(unsigned int mode) { switch (mode) { case LNM : return MASK_LNM; case DECCKM : return MASK_DECCKM; case DECANM : return MASK_DECANM; case DECCOLM : return MASK_DECCOLM; case DECSCLM : return MASK_DECSCLM; case DECSCNM : return MASK_DECSCNM; case DECOM : return MASK_DECOM; case DECAWM : return MASK_DECAWM; case DECARM : return MASK_DECARM; case DECINLM : return MASK_DECINLM; default: return 0; } } /* Modes ===== The following is a list of VT100 modes which may be changed with set mode (SM) and reset mode (RM) controls. ANSI Specified Modes -------------------- Parameter Mode Mnemonic Mode Function 0 Error (ignored) 20 LNM Line feed new line mode DEC Private Modes ================= If the first character in the parameter string is ? (077), the parameters are interpreted as DEC private parameters according to the following: Parameter Mode Mnemonic Mode Function 0 Error (ignored) 1 DECCKM Cursor key 2 DECANM ANSI/VT52 3 DECCOLM Column 4 DECSCLM Scrolling 5 DECSCNM Screen 6 DECOM Origin 7 DECAWM Auto wrap 8 DECARM Auto repeating 9 DECINLM Interlace LNM – Line Feed/New Line Mode ----------------------------- This is a parameter applicable to set mode (SM) and reset mode (RM) control sequences. The reset state causes the interpretation of the line feed (LF), defined in ANSI Standard X3.4-1977, to imply only vertical movement of the active position and causes the RETURN key (CR) to send the single code CR. The set state causes the LF to imply movement to the first position of the following line and causes the RETURN key to send the two codes (CR, LF). This is the New Line (NL) option. This mode does not affect the index (IND), or next line (NEL) format effectors. DECCKM – Cursor Keys Mode (DEC Private) --------------------------------------- This is a private parameter applicable to set mode (SM) and reset mode (RM) control sequences. This mode is only effective when the terminal is in keypad application mode (see DECKPAM) and the ANSI/VT52 mode (DECANM) is set (see DECANM). Under these conditions, if the cursor key mode is reset, the four cursor function keys will send ANSI cursor control commands. If cursor key mode is set, the four cursor function keys will send application functions. DECANM – ANSI/VT52 Mode (DEC Private) ------------------------------------- This is a private parameter applicable to set mode (SM) and reset mode (RM) control sequences. The reset state causes only VT52 compatible escape sequences to be interpreted and executed. The set state causes only ANSI "compatible" escape and control sequences to be interpreted and executed. DECCOLM – Column Mode (DEC Private) ----------------------------------- This is a private parameter applicable to set mode (SM) and reset mode (RM) control sequences. The reset state causes a maximum of 80 columns on the screen. The set state causes a maximum of 132 columns on the screen. DECSCLM – Scrolling Mode (DEC Private) -------------------------------------- This is a private parameter applicable to set mode (SM) and reset mode (RM) control sequences. The reset state causes scrolls to "jump" instantaneously. The set state causes scrolls to be "smooth" at a maximum rate of six lines per second. DECSCNM – Screen Mode (DEC Private) ----------------------------------- This is a private parameter applicable to set mode (SM) and reset mode (RM) control sequences. The reset state causes the screen to be black with white characters. The set state causes the screen to be white with black characters. DECOM – Origin Mode (DEC Private) --------------------------------- This is a private parameter applicable to set mode (SM) and reset mode (RM) control sequences. The reset state causes the origin to be at the upper-left character position on the screen. Line and column numbers are, therefore, independent of current margin settings. The cursor may be positioned outside the margins with a cursor position (CUP) or horizontal and vertical position (HVP) control. The set state causes the origin to be at the upper-left character position within the margins. Line and column numbers are therefore relative to the current margin settings. The cursor is not allowed to be positioned outside the margins. The cursor is moved to the new home position when this mode is set or reset. Lines and columns are numbered consecutively, with the origin being line 1, column 1. DECAWM – Autowrap Mode (DEC Private) ------------------------------------ This is a private parameter applicable to set mode (SM) and reset mode (RM) control sequences. The reset state causes any displayable characters received when the cursor is at the right margin to replace any previous characters there. The set state causes these characters to advance to the start of the next line, doing a scroll up if required and permitted. DECARM – Auto Repeat Mode (DEC Private) --------------------------------------- This is a private parameter applicable to set mode (SM) and reset mode (RM) control sequences. The reset state causes no keyboard keys to auto-repeat. The set state causes certain keyboard keys to auto-repeat. DECINLM – Interlace Mode (DEC Private) -------------------------------------- This is a private parameter applicable to set mode (SM) and reset mode (RM) control sequences. The reset state (non-interlace) causes the video processor to display 240 scan lines per frame. The set state (interlace) causes the video processor to display 480 scan lines per frame. There is no increase in character resolution. */ #define SCREEN_PTR(vt100, x, y) \ ((vt100->top_line * vt100->width + x + vt100->width * y) \ % (vt100->width * SCROLLBACK * vt100->height)) #define FROZEN_SCREEN_PTR(vt100, x, y) \ ((x + vt100->width * y) \ % (vt100->width * SCROLLBACK * vt100->height)) static void set(struct terminal_vt100 *headless_term, unsigned int x, unsigned int y, char c) { if (y < headless_term->margin_top || y > headless_term->margin_bottom) headless_term->frozen_screen[FROZEN_SCREEN_PTR(headless_term, x, y)] = c; else headless_term->screen[SCREEN_PTR(headless_term, x, y)] = c; } char vt100_get(struct terminal_vt100 *vt100, unsigned int x, unsigned int y) { if (y < vt100->margin_top || y > vt100->margin_bottom) return vt100->frozen_screen[FROZEN_SCREEN_PTR(vt100, x, y)]; else return vt100->screen[SCREEN_PTR(vt100, x, y)]; } static void froze_line(struct terminal_vt100 *vt100, unsigned int y) { memcpy(vt100->frozen_screen + vt100->width * y, vt100->screen + SCREEN_PTR(vt100, 0, y), vt100->width); } static void unfroze_line(struct terminal_vt100 *vt100, unsigned int y) { memcpy(vt100->screen + SCREEN_PTR(vt100, 0, y), vt100->frozen_screen + vt100->width * y, vt100->width); } static void blank_screen(struct terminal_vt100 *terminal_vt100) { unsigned int x; unsigned int y; for (x = 0; x < terminal_vt100->width; ++x) for (y = 0; y < terminal_vt100->height; ++y) set(terminal_vt100, x, y, ' '); } /* DECSC – Save Cursor (DEC Private) ESC 7 This sequence causes the cursor position, graphic rendition, and character set to be saved. (See DECRC). */ static void DECSC(struct terminal *term_emul) { /*TODO: Save graphic rendition and charset.*/ struct terminal_vt100 *vt100; vt100 = (struct terminal_vt100 *)term_emul->user_data; vt100->saved_x = vt100->x; vt100->saved_y = vt100->y; } /* RM – Reset Mode ESC [ Ps ; Ps ; . . . ; Ps l Resets one or more VT100 modes as specified by each selective parameter in the parameter string. Each mode to be reset is specified by a separate parameter. [See Set Mode (SM) control sequence]. (See Modes following this section). */ static void RM(struct terminal *term_emul) { struct terminal_vt100 *vt100; unsigned int mode; vt100 = (struct terminal_vt100 *)term_emul->user_data; if (term_emul->argc > 0) { mode = term_emul->argv[0]; if (mode == DECCOLM) { vt100->width = 80; vt100->x = vt100->y = 0; blank_screen(vt100); } UNSET_MODE(vt100, mode); } } /* CUP – Cursor Position ESC [ Pn ; Pn H default value: 1 The CUP sequence moves the active position to the position specified by the parameters. This sequence has two parameter values, the first specifying the line position and the second specifying the column position. A parameter value of zero or one for the first or second parameter moves the active position to the first line or column in the display, respectively. The default condition with no parameters present is equivalent to a cursor to home action. In the VT100, this control behaves identically with its format effector counterpart, HVP. Editor Function The numbering of lines depends on the state of the Origin Mode (DECOM). */ static void CUP(struct terminal *term_emul) { struct terminal_vt100 *vt100; int arg0; int arg1; vt100 = (struct terminal_vt100 *)term_emul->user_data; arg0 = 0; arg1 = 0; if (term_emul->argc > 0) arg0 = term_emul->argv[0] - 1; if (term_emul->argc > 1) arg1 = term_emul->argv[1] - 1; if (arg0 < 0) arg0 = 0; if (arg1 < 0) arg1 = 0; if (MODE_IS_SET(vt100, DECOM)) { arg0 += vt100->margin_top; if ((unsigned int)arg0 > vt100->margin_bottom) arg0 = vt100->margin_bottom; } vt100->y = arg0; vt100->x = arg1; } /* SM – Set Mode ESC [ Ps ; . . . ; Ps h Causes one or more modes to be set within the VT100 as specified by each selective parameter in the parameter string. Each mode to be set is specified by a separate parameter. A mode is considered set until it is reset by a reset mode (RM) control sequence. */ static void SM(struct terminal *term_emul) { struct terminal_vt100 *vt100; unsigned int mode; unsigned int saved_argc; vt100 = (struct terminal_vt100 *)term_emul->user_data; if (term_emul->argc > 0) { mode = term_emul->argv[0]; SET_MODE(vt100, mode); if (mode == DECANM) { /* TODO: Support vt52 mode */ return ; } if (mode == DECCOLM) { vt100->width = 132; vt100->x = vt100->y = 0; blank_screen(vt100); } if (mode == DECOM) { saved_argc = term_emul->argc; term_emul->argc = 0; CUP(term_emul); term_emul->argc = saved_argc; } } } /* DECSTBM – Set Top and Bottom Margins (DEC Private) ESC [ Pn; Pn r This sequence sets the top and bottom margins to define the scrolling region. The first parameter is the line number of the first line in the scrolling region; the second parameter is the line number of the bottom line in the scrolling region. Default is the entire screen (no margins). The minimum size of the scrolling region allowed is two lines, i.e., the top margin must be less than the bottom margin. The cursor is placed in the home position (see Origin Mode DECOM). */ static void DECSTBM(struct terminal *term_emul) { unsigned int margin_top; unsigned int margin_bottom; struct terminal_vt100 *vt100; unsigned int line; vt100 = (struct terminal_vt100 *)term_emul->user_data; if (term_emul->argc == 2) { margin_top = term_emul->argv[0] - 1; margin_bottom = term_emul->argv[1] - 1; if (margin_bottom >= vt100->height) return ; if (margin_bottom - margin_top <= 0) return ; } else { margin_top = 0; margin_bottom = vt100->height - 1; } for (line = vt100->margin_top; line < margin_top; ++line) froze_line(vt100, line); for (line = vt100->margin_bottom; line < margin_bottom; ++line) unfroze_line(vt100, line); for (line = margin_top; line < vt100->margin_top; ++line) unfroze_line(vt100, line); for (line = margin_bottom; line < vt100->margin_bottom; ++line) froze_line(vt100, line); vt100->margin_bottom = margin_bottom; vt100->margin_top = margin_top; term_emul->argc = 0; CUP(term_emul); } /* SGR – Select Graphic Rendition ESC [ Ps ; . . . ; Ps m Invoke the graphic rendition specified by the parameter(s). All following characters transmitted to the VT100 are rendered according to the parameter(s) until the next occurrence of SGR. Format Effector Parameter Parameter Meaning 0 Attributes off 1 Bold or increased intensity 4 Underscore 5 Blink 7 Negative (reverse) image All other parameter values are ignored. With the Advanced Video Option, only one type of character attribute is possible as determined by the cursor selection; in that case specifying either the underscore or the reverse attribute will activate the currently selected attribute. (See cursor selection in Chapter 1). */ static void SGR(struct terminal *term_emul) { term_emul = term_emul; /* Just ignore them for now, we are rendering pure text only */ } /* DA – Device Attributes ESC [ Pn c The host requests the VT100 to send a device attributes (DA) control sequence to identify itself by sending the DA control sequence with either no parameter or a parameter of 0. Response to the request described above (VT100 to host) is generated by the VT100 as a DA control sequence with the numeric parameters as follows: Option Present Sequence Sent No options ESC [?1;0c Processor option (STP) ESC [?1;1c Advanced video option (AVO) ESC [?1;2c AVO and STP ESC [?1;3c Graphics option (GPO) ESC [?1;4c GPO and STP ESC [?1;5c GPO and AVO ESC [?1;6c GPO, STP and AVO ESC [?1;7c */ static void DA(struct terminal *term_emul) { struct terminal_vt100 *vt100; vt100 = (struct terminal_vt100 *)term_emul->user_data; write(term_emul->fd, "\033[?1;0c", 7); /* Do not write directly ? */ } /* DECRC – Restore Cursor (DEC Private) ESC 8 This sequence causes the previously saved cursor position, graphic rendition, and character set to be restored. */ static void DECRC(struct terminal *term_emul) { /*TODO Save graphic rendition and charset */ struct terminal_vt100 *vt100; vt100 = (struct terminal_vt100 *)term_emul->user_data; vt100->x = vt100->saved_x; vt100->y = vt100->saved_y; } /* DECALN – Screen Alignment Display (DEC Private) ESC # 8 This command fills the entire screen area with uppercase Es for screen focus and alignment. This command is used by DEC manufacturing and Field Service personnel. */ static void DECALN(struct terminal *term_emul) { struct terminal_vt100 *vt100; unsigned int x; unsigned int y; vt100 = (struct terminal_vt100 *)term_emul->user_data; for (x = 0; x < vt100->width; ++x) for (y = 0; y < vt100->height; ++y) set(vt100, x, y, 'E'); } /* IND – Index ESC D This sequence causes the active position to move downward one line without changing the column position. If the active position is at the bottom margin, a scroll up is performed. Format Effector */ static void IND(struct terminal *term_emul) { struct terminal_vt100 *vt100; unsigned int x; vt100 = (struct terminal_vt100 *)term_emul->user_data; if (vt100->y >= vt100->margin_bottom) { /* SCROLL */ vt100->top_line = (vt100->top_line + 1) % (vt100->height * SCROLLBACK); for (x = 0; x < vt100->width; ++x) set(vt100, x, vt100->margin_bottom, ' '); } else { /* Do not scroll, just move downward on the current display space */ vt100->y += 1; } } /* RI – Reverse Index ESC M Move the active position to the same horizontal position on the preceding line. If the active position is at the top margin, a scroll down is performed. Format Effector */ static void RI(struct terminal *term_emul) { struct terminal_vt100 *vt100; vt100 = (struct terminal_vt100 *)term_emul->user_data; if (vt100->y == 0) { /* SCROLL */ vt100->top_line = (vt100->top_line - 1) % (vt100->height * SCROLLBACK); } else { /* Do not scroll, just move upward on the current display space */ vt100->y -= 1; } } /* NEL – Next Line ESC E This sequence causes the active position to move to the first position on the next line downward. If the active position is at the bottom margin, a scroll up is performed. Format Effector */ static void NEL(struct terminal *term_emul) { struct terminal_vt100 *vt100; unsigned int x; vt100 = (struct terminal_vt100 *)term_emul->user_data; if (vt100->y >= vt100->margin_bottom) { /* SCROLL */ vt100->top_line = (vt100->top_line + 1) % (vt100->height * SCROLLBACK); for (x = 0; x < vt100->width; ++x) set(vt100, x, vt100->margin_bottom, ' '); } else { /* Do not scroll, just move downward on the current display space */ vt100->y += 1; } vt100->x = 0; } /* CUU – Cursor Up – Host to VT100 and VT100 to Host ESC [ Pn A default value: 1 Moves the active position upward without altering the column position. The number of lines moved is determined by the parameter. A parameter value of zero or one moves the active position one line upward. A parameter value of n moves the active position n lines upward. If an attempt is made to move the cursor above the top margin, the cursor stops at the top margin. Editor Function */ static void CUU(struct terminal *term_emul) { struct terminal_vt100 *vt100; unsigned int arg0; vt100 = (struct terminal_vt100 *)term_emul->user_data; arg0 = 1; if (term_emul->argc > 0) arg0 = term_emul->argv[0]; if (arg0 == 0) arg0 = 1; if (arg0 <= vt100->y) vt100->y -= arg0; else vt100->y = 0; } /* CUD – Cursor Down – Host to VT100 and VT100 to Host ESC [ Pn B default value: 1 The CUD sequence moves the active position downward without altering the column position. The number of lines moved is determined by the parameter. If the parameter value is zero or one, the active position is moved one line downward. If the parameter value is n, the active position is moved n lines downward. In an attempt is made to move the cursor below the bottom margin, the cursor stops at the bottom margin. Editor Function */ static void CUD(struct terminal *term_emul) { struct terminal_vt100 *vt100; unsigned int arg0; vt100 = (struct terminal_vt100 *)term_emul->user_data; arg0 = 1; if (term_emul->argc > 0) arg0 = term_emul->argv[0]; if (arg0 == 0) arg0 = 1; vt100->y += arg0; if (vt100->y >= vt100->height) vt100->y = vt100->height - 1; } /* CUF – Cursor Forward – Host to VT100 and VT100 to Host ESC [ Pn C default value: 1 The CUF sequence moves the active position to the right. The distance moved is determined by the parameter. A parameter value of zero or one moves the active position one position to the right. A parameter value of n moves the active position n positions to the right. If an attempt is made to move the cursor to the right of the right margin, the cursor stops at the right margin. Editor Function */ static void CUF(struct terminal *term_emul) { struct terminal_vt100 *vt100; unsigned int arg0; vt100 = (struct terminal_vt100 *)term_emul->user_data; arg0 = 1; if (term_emul->argc > 0) arg0 = term_emul->argv[0]; if (arg0 == 0) arg0 = 1; vt100->x += arg0; if (vt100->x >= vt100->width) vt100->x = vt100->width - 1; } /* CUB – Cursor Backward – Host to VT100 and VT100 to Host ESC [ Pn D default value: 1 The CUB sequence moves the active position to the left. The distance moved is determined by the parameter. If the parameter value is zero or one, the active position is moved one position to the left. If the parameter value is n, the active position is moved n positions to the left. If an attempt is made to move the cursor to the left of the left margin, the cursor stops at the left margin. Editor Function */ static void CUB(struct terminal *term_emul) { struct terminal_vt100 *vt100; unsigned int arg0; vt100 = (struct terminal_vt100 *)term_emul->user_data; arg0 = 1; if (term_emul->argc > 0) arg0 = term_emul->argv[0]; if (arg0 == 0) arg0 = 1; if (arg0 < vt100->x) vt100->x -= arg0; else vt100->x = 0; } /* ED – Erase In Display ESC [ Ps J default value: 0 This sequence erases some or all of the characters in the display according to the parameter. Any complete line erased by this sequence will return that line to single width mode. Editor Function Parameter Parameter Meaning 0 Erase from the active position to the end of the screen, inclusive (default) 1 Erase from start of the screen to the active position, inclusive 2 Erase all of the display – all lines are erased, changed to single-width, and the cursor does not move. */ static void ED(struct terminal *term_emul) { struct terminal_vt100 *vt100; unsigned int arg0; unsigned int x; unsigned int y; vt100 = (struct terminal_vt100 *)term_emul->user_data; arg0 = 0; if (term_emul->argc > 0) arg0 = term_emul->argv[0]; if (arg0 == 0) { for (x = vt100->x; x < vt100->width; ++x) set(vt100, x, vt100->y, ' '); for (x = 0 ; x < vt100->width; ++x) for (y = vt100->y + 1; y < vt100->height; ++y) set(vt100, x, y, ' '); } else if (arg0 == 1) { for (x = 0 ; x < vt100->width; ++x) for (y = 0; y < vt100->y; ++y) set(vt100, x, y, ' '); for (x = 0; x <= vt100->x; ++x) set(vt100, x, vt100->y, ' '); } else if (arg0 == 2) { for (x = 0 ; x < vt100->width; ++x) for (y = 0; y < vt100->height; ++y) set(vt100, x, y, ' '); } } /* EL – Erase In Line ESC [ Ps K default value: 0 Erases some or all characters in the active line according to the parameter. Editor Function Parameter Parameter Meaning 0 Erase from the active position to the end of the line, inclusive (default) 1 Erase from the start of the screen to the active position, inclusive 2 Erase all of the line, inclusive */ static void EL(struct terminal *term_emul) { struct terminal_vt100 *vt100; unsigned int arg0; unsigned int x; vt100 = (struct terminal_vt100 *)term_emul->user_data; arg0 = 0; if (term_emul->argc > 0) arg0 = term_emul->argv[0]; if (arg0 == 0) { for (x = vt100->x; x < vt100->width; ++x) set(vt100, x, vt100->y, ' '); } else if (arg0 == 1) { for (x = 0; x <= vt100->x; ++x) set(vt100, x, vt100->y, ' '); } else if (arg0 == 2) { for (x = 0; x < vt100->width; ++x) set(vt100, x, vt100->y, ' '); } } /* HVP – Horizontal and Vertical Position ESC [ Pn ; Pn f default value: 1 Moves the active position to the position specified by the parameters. This sequence has two parameter values, the first specifying the line position and the second specifying the column. A parameter value of either zero or one causes the active position to move to the first line or column in the display, respectively. The default condition with no parameters present moves the active position to the home position. In the VT100, this control behaves identically with its editor function counterpart, CUP. The numbering of lines and columns depends on the reset or set state of the origin mode (DECOM). Format Effector */ static void HVP(struct terminal *term_emul) { CUP(term_emul); } static void TBC(struct terminal *term_emul) { struct terminal_vt100 *vt100; unsigned int i; vt100 = (struct terminal_vt100 *)term_emul->user_data; if (term_emul->argc == 0 || term_emul->argv[0] == 0) { vt100->tabulations[vt100->x] = '-'; } else if (term_emul->argc == 1 && term_emul->argv[0] == 3) { for (i = 0; i < 132; ++i) vt100->tabulations[i] = '-'; } } static void HTS(struct terminal *term_emul) { struct terminal_vt100 *vt100; vt100 = (struct terminal_vt100 *)term_emul->user_data; vt100->tabulations[vt100->x] = '|'; } static void vt100_write(struct terminal *term_emul, char c) { struct terminal_vt100 *vt100; vt100 = (struct terminal_vt100 *)term_emul->user_data; if (c == '\r') { vt100->x = 0; return ; } if (c == '\n' || c == '\013' || c == '\014') { if (MODE_IS_SET(vt100, LNM)) NEL(term_emul); else IND(term_emul); return ; } if (c == '\010' && vt100->x > 0) { if (vt100->x == vt100->width) vt100->x -= 1; vt100->x -= 1; return ; } if (c == '\t') { do { set(vt100, vt100->x, vt100->y, ' '); vt100->x += 1; } while (vt100->x < vt100->width && vt100->tabulations[vt100->x] == '-'); return ; } if (c == '\016') { vt100->selected_charset = 0; return ; } if (c == '\017') { vt100->selected_charset = 1; return ; } if (vt100->x == vt100->width) { if (MODE_IS_SET(vt100, DECAWM)) NEL(term_emul); else vt100->x -= 1; } set(vt100, vt100->x, vt100->y, c); vt100->x += 1; } const char **vt100_getlines(struct terminal_vt100 *vt100) { unsigned int y; for (y = 0; y < vt100->height; ++y) if (y < vt100->margin_top || y > vt100->margin_bottom) vt100->lines[y] = vt100->frozen_screen + FROZEN_SCREEN_PTR(vt100, 0, y); else vt100->lines[y] = vt100->screen + SCREEN_PTR(vt100, 0, y); return (const char **)vt100->lines; } struct terminal_vt100 *vt100_init(void (*unimplemented)(struct terminal* term_emul, char *seq, char chr)) { struct terminal_vt100 *this; this = calloc(1, sizeof(*this)); if (this == NULL) return NULL; this->height = 24; this->width = 80; this->screen = malloc(132 * SCROLLBACK * this->height); if (this->screen == NULL) goto free_this; memset(this->screen, ' ', 132 * SCROLLBACK * this->height); this->frozen_screen = malloc(132 * this->height); if (this->frozen_screen == NULL) goto free_screen; memset(this->frozen_screen, ' ', 132 * this->height); this->tabulations = malloc(132); if (this->tabulations == NULL) goto free_frozen_screen; if (this->tabulations == NULL) return NULL; this->margin_top = 0; this->margin_bottom = this->height - 1; this->selected_charset = 0; this->x = 0; this->y = 0; this->modes = MASK_DECANM; this->top_line = 0; this->terminal = terminal_init(); if (this->terminal == NULL) goto free_tabulations; this->terminal->user_data = this; this->terminal->write = vt100_write; this->terminal->callbacks.csi.f = HVP; this->terminal->callbacks.csi.K = EL; this->terminal->callbacks.csi.c = DA; this->terminal->callbacks.csi.h = SM; this->terminal->callbacks.csi.l = RM; this->terminal->callbacks.csi.J = ED; this->terminal->callbacks.csi.H = CUP; this->terminal->callbacks.csi.C = CUF; this->terminal->callbacks.csi.B = CUD; this->terminal->callbacks.csi.r = DECSTBM; this->terminal->callbacks.csi.m = SGR; this->terminal->callbacks.csi.A = CUU; this->terminal->callbacks.csi.g = TBC; this->terminal->callbacks.esc.H = HTS; this->terminal->callbacks.csi.D = CUB; this->terminal->callbacks.esc.E = NEL; this->terminal->callbacks.esc.D = IND; this->terminal->callbacks.esc.M = RI; this->terminal->callbacks.esc.n8 = DECRC; this->terminal->callbacks.esc.n7 = DECSC; this->terminal->callbacks.hash.n8 = DECALN; this->terminal->unimplemented = unimplemented; return this; free_tabulations: free(this->tabulations); free_frozen_screen: free(this->frozen_screen); free_screen: free(this->screen); free_this: free(this); return NULL; } void terminal_this_destroy(struct terminal_vt100 *this) { terminal_destroy(this->terminal); free(this->screen); free(this->frozen_screen); free(this); }