From 68845f0403fce8f45a88915e5a12c752adcc0258 Mon Sep 17 00:00:00 2001 From: Curtis McEnroe Date: Wed, 14 Aug 2019 14:31:34 -0400 Subject: Handle state transitions just much better --- Makefile | 2 +- term.c | 287 +++++++++++++++++++++++++++++++++++++-------------------------- term.h | 1 - 3 files changed, 169 insertions(+), 121 deletions(-) diff --git a/Makefile b/Makefile index 0cae642..d280a66 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ CHROOT_USER = stream CHROOT_GROUP = ${CHROOT_USER} -CFLAGS += -Wall -Wextra -Wpedantic +CFLAGS += -Wall -Wextra -Wpedantic -Wno-gnu-case-range LDFLAGS = -static LDLIBS = -lcurses -lutil diff --git a/term.c b/term.c index 2a8960a..9910889 100644 --- a/term.c +++ b/term.c @@ -83,59 +83,23 @@ static void scrollDown(struct Term *term, uint top, uint n) { ); } -typedef void Action(struct Term *, wchar_t); - #define ACTION(name) \ - static void name(struct Term *t, wchar_t _ch __attribute__((unused))) + static void name(struct Term *t, wchar_t ch __attribute__((unused))) -enum { - Def, - Esc, - G0, - CSI, - OSC, - OSCEsc, -}; +ACTION(nop) { (void)t; } -ACTION(nop) { (void)t; } -ACTION(esc) { t->state = Esc; } -ACTION(g0) { t->state = G0; } -ACTION(osc) { t->state = OSC; } -ACTION(oscEsc) { t->state = OSCEsc; } ACTION(csi) { - t->state = CSI; memset(&t->param, 0, sizeof(t->param)); } - -static void csiParam(struct Term *t, wchar_t ch) { - switch (ch) { - case L'0': case L'1': case L'2': case L'3': case L'4': - case L'5': case L'6': case L'7': case L'8': case L'9': { - t->param.s[t->param.i] *= 10; - t->param.s[t->param.i] += ch - L'0'; - if (!t->param.n) t->param.n++; - } - break; case L':': // ignore - break; case L';': { - if (t->param.n == ParamCap) break; - t->param.n++; - t->param.i++; - } - break; case L'<': t->param.lt = true; - break; case L'=': t->param.eq = true; - break; case L'>': t->param.gt = true; - break; case L'?': t->param.qm = true; - break; default: { - unhandled("CSI %lc", ch); - return; - } - } - t->state = CSI; +ACTION(csiSep) { + if (t->param.n == ParamCap) return; + t->param.n++; + t->param.i++; } - -static void escUnhandled(struct Term *t, wchar_t ch) { - (void)t; - unhandled("ESC %lc", ch); +ACTION(csiDigit) { + t->param.s[t->param.i] *= 10; + t->param.s[t->param.i] += ch - L'0'; + if (!t->param.n) t->param.n++; } #define Y t->y @@ -152,8 +116,8 @@ ACTION(cuu) { Y -= MIN(P(0, 1), Y); } ACTION(cud) { Y = MIN(Y + P(0, 1), B); } ACTION(cuf) { X = MIN(X + P(0, 1), R); } ACTION(cub) { X -= MIN(P(0, 1), X); } -ACTION(cnl) { X = 0; cud(t, 0); } -ACTION(cpl) { X = 0; cuu(t, 0); } +ACTION(cnl) { X = 0; cud(t, ch); } +ACTION(cpl) { X = 0; cuu(t, ch); } ACTION(cha) { X = MIN(P(0, 1) - 1, R); } ACTION(vpa) { Y = MIN(P(0, 1) - 1, B); } ACTION(cup) { @@ -232,29 +196,46 @@ enum { DECTCEM = 25, }; -static void mode(struct Term *t, wchar_t ch) { +static enum Mode paramMode(struct Term *t) { + enum Mode mode = 0; + for (uint i = 0; i < t->param.n; ++i) { + switch (t->param.s[i]) { + break; case IRM: mode |= Insert; + break; default: unhandled("SM/RM %u", t->param.s[i]); + } + } + return mode; +} + +static enum Mode paramDECMode(struct Term *t) { enum Mode mode = 0; for (uint i = 0; i < t->param.n; ++i) { - if (t->param.qm) { - switch (t->param.s[i]) { - break; case 1: // DECCKM - break; case DECAWM: mode |= Wrap; - break; case 12: // "Start Blinking Cursor" - break; case DECTCEM: mode |= Cursor; - break; default: { - if (t->param.s[i] < 1000) { - unhandled("DECSET/DECRST %u", t->param.s[i]); - } + switch (t->param.s[i]) { + break; case 1: // DECCKM + break; case DECAWM: mode |= Wrap; + break; case 12: // "Start Blinking Cursor" + break; case DECTCEM: mode |= Cursor; + break; default: { + if (t->param.s[i] < 1000) { + unhandled("DECSET/DECRST %u", t->param.s[i]); } } - } else { - switch (t->param.s[i]) { - break; case IRM: mode |= Insert; - break; default: unhandled("SM/RM %u", t->param.s[i]); - } } } - t->mode = (ch == L'h' ? t->mode | mode : t->mode & ~mode); + return mode; +} + +ACTION(sm) { + t->mode |= paramMode(t); +} +ACTION(decset) { + t->mode |= paramDECMode(t); +} +ACTION(rm) { + t->mode &= ~paramMode(t); +} +ACTION(decrst) { + t->mode &= ~paramDECMode(t); } enum { @@ -339,7 +320,7 @@ ACTION(sgr) { } } -static void add(struct Term *t, wchar_t ch) { +ACTION(add) { int width = wcwidth(ch); if (width < 0) { unhandled("\\u%02X", ch); @@ -369,75 +350,143 @@ static void add(struct Term *t, wchar_t ch) { } } -#define S(s) break; case (s): switch (ch) -#define A(c, a) break; case (c): (a)(term, ch) -#define D(a) break; default: (a)(term, ch) +enum { + Data, + Esc, + G0, + CSI, + CSILt, + CSIEq, + CSIGt, + CSIQm, + CSIInter, + OSC, + OSCEsc, +}; + +ACTION(escDefault) { + (void)t; + unhandled("ESC %lc", ch); +} + +ACTION(csiInter) { + switch (t->state) { + break; case CSI: unhandled("CSI %lc ...", ch); + break; case CSILt: unhandled("CSI < %lc ...", ch); + break; case CSIEq: unhandled("CSI = %lc ...", ch); + break; case CSIGt: unhandled("CSI > %lc ...", ch); + break; case CSIQm: unhandled("CSI ? %lc ...", ch); + } +} + +ACTION(csiFinal) { + switch (t->state) { + break; case CSI: unhandled("CSI %lc", ch); + break; case CSILt: unhandled("CSI < %lc", ch); + break; case CSIEq: unhandled("CSI = %lc", ch); + break; case CSIGt: unhandled("CSI > %lc", ch); + break; case CSIQm: unhandled("CSI ? %lc", ch); + break; case CSIInter: unhandled("CSI ... %lc", ch); + } +} + +#define S(s) break; case s: switch (ch) +#define A(c, a, s) break; case c: a(term, ch); term->state = s +#define D(a, s) break; default: a(term, ch); term->state = s void termUpdate(struct Term *term, wchar_t ch) { - uint state = term->state; - term->state = Def; - switch (state) { + switch (term->state) { default: abort(); - S(Def) { - A(BEL, nop); - A(BS, bs); - A(HT, ht); - A(NL, nl); - A(CR, cr); - A(ESC, esc); - D(add); + S(Data) { + A(BEL, nop, Data); + A(BS, bs, Data); + A(HT, ht, Data); + A(NL, nl, Data); + A(CR, cr, Data); + A(ESC, nop, Esc); + D(add, Data); } S(Esc) { - A('(', g0); - A('7', decsc); - A('8', decrc); - A('=', nop); - A('>', nop); - A('M', ri); - A('[', csi); - A(']', osc); - D(escUnhandled); + A('(', nop, G0); + A('7', decsc, Data); + A('8', decrc, Data); + A('=', nop, Data); + A('>', nop, Data); + A('M', ri, Data); + A('[', csi, CSI); + A(']', nop, OSC); + D(escDefault, Data); } S(G0) { - D(nop); + D(nop, Data); } S(CSI) { - A('@', ich); - A('A', cuu); - A('B', cud); - A('C', cuf); - A('D', cub); - A('E', cnl); - A('F', cpl); - A('G', cha); - A('H', cup); - A('J', ed); - A('K', el); - A('L', il); - A('M', dl); - A('P', dch); - A('S', su); - A('T', sd); - A('X', ech); - A('d', vpa); - A('h', mode); - A('l', mode); - A('m', sgr); - A('r', decstbm); - A('t', nop); - D(csiParam); + A(' ' ... '/', csiInter, CSIInter); + A('0' ... '9', csiDigit, CSI); + A(':', nop, CSI); + A(';', csiSep, CSI); + A('<', nop, CSILt); + A('=', nop, CSIEq); + A('>', nop, CSIGt); + A('?', nop, CSIQm); + A('@', ich, Data); + A('A', cuu, Data); + A('B', cud, Data); + A('C', cuf, Data); + A('D', cub, Data); + A('E', cnl, Data); + A('F', cpl, Data); + A('G', cha, Data); + A('H', cup, Data); + A('J', ed, Data); + A('K', el, Data); + A('L', il, Data); + A('M', dl, Data); + A('P', dch, Data); + A('S', su, Data); + A('T', sd, Data); + A('X', ech, Data); + A('d', vpa, Data); + A('h', sm, Data); + A('l', rm, Data); + A('m', sgr, Data); + A('r', decstbm, Data); + A('t', nop, Data); + D(csiFinal, Data); + } + + S(CSILt ... CSIGt) { + A(' ' ... '/', csiInter, CSIInter); + A('0' ... '9', csiDigit, term->state); + A(':', nop, term->state); + A(';', csiSep, term->state); + D(csiFinal, Data); + } + + S(CSIQm) { + A(' ' ... '/', csiInter, CSIInter); + A('0' ... '9', csiDigit, CSIQm); + A(':', nop, CSIQm); + A(';', csiSep, CSIQm); + A('h', decset, Data); + A('l', decrst, Data); + D(csiFinal, Data); + } + + S(CSIInter) { + D(csiFinal, Data); } S(OSC) { - A(BEL, nop); - A(ESC, oscEsc); - D(osc); + A(BEL, nop, Data); + A(ESC, nop, OSCEsc); + D(nop, OSC); } S(OSCEsc) { - A('\\', nop); - D(osc); + A('\\', nop, Data); + D(nop, OSC); } } } diff --git a/term.h b/term.h index 19ebb95..f2df1fa 100644 --- a/term.h +++ b/term.h @@ -58,7 +58,6 @@ struct Term { uint rows, cols; uint state; struct { - bool lt, eq, gt, qm; uint s[ParamCap]; uint n, i; } param; -- cgit 1.4.1