terminology: cleanup escape sequences parsing. Fix #1628

Charset length for example was not correctly handled and could even lead
to segfaults.

SVN revision: 80980
This commit is contained in:
Boris Faure 2012-12-14 18:52:19 +00:00
parent 1434247df2
commit d18cc90367
1 changed files with 71 additions and 51 deletions

View File

@ -16,12 +16,16 @@
#define ERR(...) EINA_LOG_DOM_ERR(_termpty_log_dom, __VA_ARGS__) #define ERR(...) EINA_LOG_DOM_ERR(_termpty_log_dom, __VA_ARGS__)
#define WRN(...) EINA_LOG_DOM_WARN(_termpty_log_dom, __VA_ARGS__) #define WRN(...) EINA_LOG_DOM_WARN(_termpty_log_dom, __VA_ARGS__)
#define INF(...) EINA_LOG_DOM_INFO(_termpty_log_dom, __VA_ARGS__) #define INF(...) EINA_LOG_DOM_INFO(_termpty_log_dom, __VA_ARGS__)
#define DBG(...) EINA_LOG_DOM_DBG(_termpty_log_dom, __VA_ARGS__) #define DBG(...) EINA_LOG_DOM_ERR(_termpty_log_dom, __VA_ARGS__)
#define ST 0x9c // String Terminator #define ST 0x9c // String Terminator
#define BEL 0x07 // Bell #define BEL 0x07 // Bell
#define ESC 033 // Escape #define ESC 033 // Escape
/* XXX: all handle_ functions return the number of bytes successfully read, 0
* if not enought bytes could be read
*/
static int static int
_csi_arg_get(Eina_Unicode **ptr) _csi_arg_get(Eina_Unicode **ptr)
{ {
@ -62,10 +66,7 @@ _handle_esc_csi(Termpty *ty, const Eina_Unicode *c, Eina_Unicode *ce)
b++; b++;
cc++; cc++;
} }
// if cc == ce then we got to the end of the string with no end marker if (cc == ce) return 0;
// so return -2 to indicate to go back to the escape beginning when
// there is more bufer available
if (cc == ce) return -2;
*b = 0; *b = 0;
b = buf; b = buf;
// DBG(" CSI: '%c' args '%s'", *cc, buf); // DBG(" CSI: '%c' args '%s'", *cc, buf);
@ -892,7 +893,7 @@ _handle_esc_xterm(Termpty *ty, const Eina_Unicode *c, Eina_Unicode *ce)
} }
*b = 0; *b = 0;
if ((*cc == ST) || (*cc == BEL) || (*cc == '\\')) cc++; if ((*cc == ST) || (*cc == BEL) || (*cc == '\\')) cc++;
else return -2; else return 0;
switch (buf[0]) switch (buf[0])
{ {
case '0': case '0':
@ -946,6 +947,8 @@ _handle_esc_xterm(Termpty *ty, const Eina_Unicode *c, Eina_Unicode *ce)
break; break;
case '4': case '4':
// XXX: set palette entry. not supported. // XXX: set palette entry. not supported.
DBG("set palette, not supported");
if ((cc - c) < 3) return 0;
b = &(buf[2]); b = &(buf[2]);
break; break;
default: default:
@ -974,7 +977,7 @@ _handle_esc_terminology(Termpty *ty, const Eina_Unicode *c, Eina_Unicode *ce)
} }
*b = 0; *b = 0;
if (*cc == 0x0) cc++; if (*cc == 0x0) cc++;
else return -2; else return 0;
// commands are stored in the buffer, 0 bytes not allowd (end marker) // commands are stored in the buffer, 0 bytes not allowd (end marker)
s = eina_unicode_unicode_to_utf8(buf, &slen); s = eina_unicode_unicode_to_utf8(buf, &slen);
ty->cur_cmd = s; ty->cur_cmd = s;
@ -1008,7 +1011,7 @@ _handle_esc_dcs(Termpty *ty __UNUSED__, const Eina_Unicode *c, Eina_Unicode *ce)
} }
*b = 0; *b = 0;
if ((*cc == ST) || (*cc == '\\')) cc++; if ((*cc == ST) || (*cc == '\\')) cc++;
else return -2; else return 0;
switch (buf[0]) switch (buf[0])
{ {
case '+': case '+':
@ -1025,73 +1028,89 @@ _handle_esc_dcs(Termpty *ty __UNUSED__, const Eina_Unicode *c, Eina_Unicode *ce)
static int static int
_handle_esc(Termpty *ty, const Eina_Unicode *c, Eina_Unicode *ce) _handle_esc(Termpty *ty, const Eina_Unicode *c, Eina_Unicode *ce)
{ {
if ((ce - c) < 2) return 0; int len = ce - c;
DBG("ESC: '%c'", c[1]);
switch (c[1]) if (len < 1) return 0;
DBG("ESC: '%c'", c[0]);
switch (c[0])
{ {
case '[': case '[':
return 2 + _handle_esc_csi(ty, c + 2, ce); len = _handle_esc_csi(ty, c + 1, ce);
if (len == 0) return 0;
return 1 + len;
case ']': case ']':
return 2 + _handle_esc_xterm(ty, c + 2, ce); len = _handle_esc_xterm(ty, c + 1, ce);
if (len == 0) return 0;
return 1 + len;
case '}': case '}':
return 2 + _handle_esc_terminology(ty, c + 2, ce); len = _handle_esc_terminology(ty, c + 1, ce);
if (len == 0) return 0;
return 1 + len;
case 'P': case 'P':
return 2 + _handle_esc_dcs(ty, c + 2, ce); len = _handle_esc_dcs(ty, c + 1, ce);
if (len == 0) return 0;
return 1 + len;
case '=': // set alternate keypad mode case '=': // set alternate keypad mode
ty->state.alt_kp = 1; ty->state.alt_kp = 1;
return 2; return 1;
case '>': // set numeric keypad mode case '>': // set numeric keypad mode
ty->state.alt_kp = 0; ty->state.alt_kp = 0;
return 2; return 1;
case 'M': // move to prev line case 'M': // move to prev line
ty->state.wrapnext = 0; ty->state.wrapnext = 0;
ty->state.cy--; ty->state.cy--;
_termpty_text_scroll_rev_test(ty); _termpty_text_scroll_rev_test(ty);
return 2; return 1;
case 'D': // move to next line case 'D': // move to next line
ty->state.wrapnext = 0; ty->state.wrapnext = 0;
ty->state.cy++; ty->state.cy++;
_termpty_text_scroll_test(ty); _termpty_text_scroll_test(ty);
return 2; return 1;
case 'E': // add \n\r case 'E': // add \n\r
ty->state.wrapnext = 0; ty->state.wrapnext = 0;
ty->state.cx = 0; ty->state.cx = 0;
ty->state.cy++; ty->state.cy++;
_termpty_text_scroll_test(ty); _termpty_text_scroll_test(ty);
return 2; return 1;
case 'Z': // same a 'ESC [ Pn c' case 'Z': // same a 'ESC [ Pn c'
_term_txt_write(ty, "\033[?1;2C"); _term_txt_write(ty, "\033[?1;2C");
return 2; return 1;
case 'c': // reset terminal to initial state case 'c': // reset terminal to initial state
DBG("reset to init mode and clear"); DBG("reset to init mode and clear");
_termpty_reset_state(ty); _termpty_reset_state(ty);
_termpty_clear_screen(ty, TERMPTY_CLR_ALL); _termpty_clear_screen(ty, TERMPTY_CLR_ALL);
if (ty->cb.cancel_sel.func) if (ty->cb.cancel_sel.func)
ty->cb.cancel_sel.func(ty->cb.cancel_sel.data); ty->cb.cancel_sel.func(ty->cb.cancel_sel.data);
return 2; return 1;
case '(': // charset 0 case '(': // charset 0
ty->state.chset[0] = c[2]; if (len < 2) return 0;
ty->state.chset[0] = c[1];
ty->state.multibyte = 0; ty->state.multibyte = 0;
ty->state.charsetch = c[2]; ty->state.charsetch = c[1];
return 3; return 2;
case ')': // charset 1 case ')': // charset 1
ty->state.chset[1] = c[2]; if (len < 2) return 0;
ty->state.chset[1] = c[1];
ty->state.multibyte = 0; ty->state.multibyte = 0;
return 3; return 2;
case '*': // charset 2 case '*': // charset 2
ty->state.chset[2] = c[2]; if (len < 2) return 0;
ty->state.chset[2] = c[1];
ty->state.multibyte = 0; ty->state.multibyte = 0;
return 3; return 2;
case '+': // charset 3 case '+': // charset 3
ty->state.chset[3] = c[2]; if (len < 2) return 0;
ty->state.chset[3] = c[1];
ty->state.multibyte = 0; ty->state.multibyte = 0;
return 3; return 2;
case '$': // charset -2 case '$': // charset -2
ty->state.chset[2] = c[2]; if (len < 2) return 0;
ty->state.chset[2] = c[1];
ty->state.multibyte = 1; ty->state.multibyte = 1;
return 3; return 2;
case '#': // #8 == test mode -> fill screen with "E"; case '#': // #8 == test mode -> fill screen with "E";
if (c[2] == '8') if (len < 2) return 0;
if (c[1] == '8')
{ {
int i, size; int i, size;
Termcell *cells; Termcell *cells;
@ -1110,30 +1129,31 @@ _handle_esc(Termpty *ty, const Eina_Unicode *c, Eina_Unicode *ce)
for (i = 0; i < size; i++) cells[i].codepoint = 'E'; for (i = 0; i < size; i++) cells[i].codepoint = 'E';
} }
} }
return 3; return 2;
case '@': // just consume this plus next char case '@': // just consume this plus next char
return 3; if (len < 2) return 0;
return 2;
case '7': // save cursor pos case '7': // save cursor pos
_termpty_cursor_copy(&(ty->state), &(ty->save)); _termpty_cursor_copy(&(ty->state), &(ty->save));
return 2; return 1;
case '8': // restore cursor pos case '8': // restore cursor pos
_termpty_cursor_copy(&(ty->save), &(ty->state)); _termpty_cursor_copy(&(ty->save), &(ty->state));
return 2; return 1;
/* /*
case 'G': // query gfx mode case 'G': // query gfx mode
return 3; return 2;
case 'H': // set tab at current column case 'H': // set tab at current column
return 2; return 1;
case 'n': // single shift 2 case 'n': // single shift 2
return 2; return 1;
case 'o': // single shift 3 case 'o': // single shift 3
return 2; return 1;
*/ */
default: default:
ERR("eek - esc unhandled '%c' (0x%02x)", c[1], c[1]); ERR("eek - esc unhandled '%c' (0x%02x)", c[0], c[0]);
break; return 1;
} }
return 1; return 0;
} }
int int
@ -1257,7 +1277,9 @@ _termpty_handle_seq(Termpty *ty, Eina_Unicode *c, Eina_Unicode *ce)
*/ */
case 0x1b: // ESC (escape) case 0x1b: // ESC (escape)
ty->state.had_cr = 0; ty->state.had_cr = 0;
return _handle_esc(ty, c, ce); len = _handle_esc(ty, c + 1, ce);
if (len == 0) return 0;
return 1 + len;
/* /*
case 0x1c: // FS (file separator) case 0x1c: // FS (file separator)
return 1; return 1;
@ -1282,13 +1304,11 @@ _termpty_handle_seq(Termpty *ty, Eina_Unicode *c, Eina_Unicode *ce)
} }
else if (c[0] == 0x9b) // ANSI ESC!!! else if (c[0] == 0x9b) // ANSI ESC!!!
{ {
int v;
printf("ANSI CSI!!!!!\n"); printf("ANSI CSI!!!!!\n");
ty->state.had_cr = 0; ty->state.had_cr = 0;
v = _handle_esc_csi(ty, c + 1, ce); len = _handle_esc_csi(ty, c + 1, ce);
if (v == -2) return 0; if (len == 0) return 0;
return v + 1; return 1 + len;
} }
cc = (int *)c; cc = (int *)c;