in src/terminal/terminal-handlers.c [236:408]
int guac_terminal_echo(guac_terminal* term, unsigned char c) {
int width;
static int bytes_remaining = 0;
static int codepoint = 0;
const int* char_mapping = term->char_mapping[term->active_char_set];
/* Echo to pipe stream if open and not starting an ESC sequence */
if (term->pipe_stream != NULL && c != 0x1B) {
guac_terminal_pipe_stream_write(term, c);
/* Do not render output while pipe is open unless explicitly requested
* via flags */
if (!(term->pipe_stream_flags & GUAC_TERMINAL_PIPE_INTERPRET_OUTPUT))
return 0;
}
/* If using non-Unicode mapping, just map straight bytes */
if (char_mapping != NULL) {
codepoint = c;
bytes_remaining = 0;
}
/* 1-byte UTF-8 codepoint */
else if ((c & 0x80) == 0x00) { /* 0xxxxxxx */
codepoint = c & 0x7F;
bytes_remaining = 0;
}
/* 2-byte UTF-8 codepoint */
else if ((c & 0xE0) == 0xC0) { /* 110xxxxx */
codepoint = c & 0x1F;
bytes_remaining = 1;
}
/* 3-byte UTF-8 codepoint */
else if ((c & 0xF0) == 0xE0) { /* 1110xxxx */
codepoint = c & 0x0F;
bytes_remaining = 2;
}
/* 4-byte UTF-8 codepoint */
else if ((c & 0xF8) == 0xF0) { /* 11110xxx */
codepoint = c & 0x07;
bytes_remaining = 3;
}
/* Continuation of UTF-8 codepoint */
else if ((c & 0xC0) == 0x80) { /* 10xxxxxx */
codepoint = (codepoint << 6) | (c & 0x3F);
bytes_remaining--;
}
/* Unrecognized prefix */
else {
codepoint = '?';
bytes_remaining = 0;
}
/* If we need more bytes, wait for more bytes */
if (bytes_remaining != 0)
return 0;
switch (codepoint) {
/* Enquiry */
case 0x05:
guac_terminal_send_string(term, GUAC_TERMINAL_ANSWERBACK);
break;
/* Bell */
case 0x07:
break;
/* Backspace */
case 0x08:
guac_terminal_move_cursor(term, term->cursor_row,
term->cursor_col - 1);
break;
/* Tab */
case 0x09:
guac_terminal_move_cursor(term, term->cursor_row,
guac_terminal_next_tab(term, term->cursor_col));
break;
/* Line feed / VT / FF */
case '\n':
case 0x0B: /* VT */
case 0x0C: /* FF */
/* Advance to next row */
guac_terminal_linefeed(term, false);
/* If automatic carriage return, fall through to CR handler */
if (!term->automatic_carriage_return)
break;
/* Carriage return */
case '\r':
guac_terminal_move_cursor(term, term->cursor_row, 0);
break;
/* SO (activates character set G1) */
case 0x0E:
term->active_char_set = 1;
break;
/* SI (activates character set G0) */
case 0x0F:
term->active_char_set = 0;
break;
/* ESC */
case 0x1B:
term->char_handler = guac_terminal_escape;
break;
/* CSI */
case 0x9B:
term->char_handler = guac_terminal_csi;
break;
/* DEL (ignored) */
case 0x7F:
break;
/* Displayable chars */
default:
/* Don't bother handling control chars if unknown */
if (codepoint < 0x20)
break;
/* Translate mappable codepoints to whatever codepoint is mapped */
if (codepoint >= 0x20 && codepoint <= 0xFF && char_mapping != NULL)
codepoint = char_mapping[codepoint - 0x20];
/* Wrap if necessary */
if (term->cursor_col >= term->term_width) {
/* New line */
term->cursor_col = 0;
guac_terminal_linefeed(term, true);
}
/* If insert mode, shift other characters right by 1 */
if (term->insert_mode)
guac_terminal_copy_columns(term, term->cursor_row,
term->cursor_col, term->term_width-2, 1);
/* Write character */
guac_terminal_set(term,
term->cursor_row,
term->cursor_col,
codepoint);
width = wcwidth(codepoint);
if (width < 0)
width = 1;
/* Advance cursor */
term->cursor_col += width;
}
return 0;
}