Cancel DCS with SUB, CAN, ESC or any CC1 code
From http://www.vt100.net/docs/vt510-rm/chapter4: *The VT510 ignores all following characters until it receives a SUB, ST, or any other C1 control character. So OSC, PM and APC sequence ends with a SUB (it cancels the sequence and show a question mark as error), ST or any another C1 (8 bits) code, or their C0 (7 bits) equivalent sequences (at this moment we do not handle C1 codes, but we should). But it is also said that: Cancel CAN 1/8 Immediately cancels an escape sequence, control sequence, or device control string in progress. In this case, the VT510 does not display any error character. Escape ESC 1/11 Introduces an escape sequence. ESC also cancels any escape sequence, control sequence, or device control string in progress.
This commit is contained in:
parent
704d12442e
commit
aa35bbd7a1
1 changed files with 127 additions and 79 deletions
174
st.c
174
st.c
|
@ -70,6 +70,8 @@ char *argv0;
|
||||||
#define LEN(a) (sizeof(a) / sizeof(a)[0])
|
#define LEN(a) (sizeof(a) / sizeof(a)[0])
|
||||||
#define DEFAULT(a, b) (a) = (a) ? (a) : (b)
|
#define DEFAULT(a, b) (a) = (a) ? (a) : (b)
|
||||||
#define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b))
|
#define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b))
|
||||||
|
#define ISCONTROLC0(c) (BETWEEN((uchar) (c), 0, 0x1f))
|
||||||
|
#define ISCONTROLC1(c) (BETWEEN((uchar) (c), 0x80, 0x9f))
|
||||||
#define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x)
|
#define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x)
|
||||||
#define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || (a).bg != (b).bg)
|
#define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || (a).bg != (b).bg)
|
||||||
#define IS_SET(flag) ((term.mode & (flag)) != 0)
|
#define IS_SET(flag) ((term.mode & (flag)) != 0)
|
||||||
|
@ -390,6 +392,7 @@ static void tsetdirtattr(int);
|
||||||
static void tsetmode(bool, bool, int *, int);
|
static void tsetmode(bool, bool, int *, int);
|
||||||
static void tfulldirt(void);
|
static void tfulldirt(void);
|
||||||
static void techo(char *, int);
|
static void techo(char *, int);
|
||||||
|
static bool tcontrolcode(uchar );
|
||||||
static int32_t tdefcolor(int *, int *, int);
|
static int32_t tdefcolor(int *, int *, int);
|
||||||
static void tselcs(void);
|
static void tselcs(void);
|
||||||
static void tdeftran(char);
|
static void tdeftran(char);
|
||||||
|
@ -399,6 +402,7 @@ static void ttyread(void);
|
||||||
static void ttyresize(void);
|
static void ttyresize(void);
|
||||||
static void ttysend(char *, size_t);
|
static void ttysend(char *, size_t);
|
||||||
static void ttywrite(const char *, size_t);
|
static void ttywrite(const char *, size_t);
|
||||||
|
static inline bool iscontrol(char);
|
||||||
|
|
||||||
static void xdraws(char *, Glyph, int, int, int, int);
|
static void xdraws(char *, Glyph, int, int, int, int);
|
||||||
static void xhints(void);
|
static void xhints(void);
|
||||||
|
@ -2136,6 +2140,7 @@ strhandle(void) {
|
||||||
char *p = NULL;
|
char *p = NULL;
|
||||||
int j, narg, par;
|
int j, narg, par;
|
||||||
|
|
||||||
|
term.esc &= ~(ESC_STR_END|ESC_STR);
|
||||||
strparse();
|
strparse();
|
||||||
narg = strescseq.narg;
|
narg = strescseq.narg;
|
||||||
par = atoi(strescseq.args[0]);
|
par = atoi(strescseq.args[0]);
|
||||||
|
@ -2295,13 +2300,22 @@ tputtab(int n) {
|
||||||
tmoveto(x, term.c.y);
|
tmoveto(x, term.c.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
iscontrol(char c) {
|
||||||
|
return ISCONTROLC0(c) || ISCONTROLC1(c);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
techo(char *buf, int len) {
|
techo(char *buf, int len) {
|
||||||
for(; len > 0; buf++, len--) {
|
for(; len > 0; buf++, len--) {
|
||||||
char c = *buf;
|
char c = *buf;
|
||||||
|
|
||||||
if(BETWEEN(c, 0x00, 0x1f) || c == 0x7f) { /* control code */
|
if(iscontrol(c)) { /* control code */
|
||||||
if(c != '\n' && c != '\r' && c != '\t') {
|
if(c & 0x80) {
|
||||||
|
c &= 0x7f;
|
||||||
|
tputc("^", 1);
|
||||||
|
tputc("[", 1);
|
||||||
|
} else if(c != '\n' && c != '\r' && c != '\t') {
|
||||||
c ^= '\x40';
|
c ^= '\x40';
|
||||||
tputc("^", 1);
|
tputc("^", 1);
|
||||||
}
|
}
|
||||||
|
@ -2340,40 +2354,119 @@ tselcs(void) {
|
||||||
ATTR_GFX);
|
ATTR_GFX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
tcontrolcode(uchar ascii) {
|
||||||
|
static char question[UTF_SIZ] = "?";
|
||||||
|
|
||||||
|
switch(ascii) {
|
||||||
|
case '\t': /* HT */
|
||||||
|
tputtab(1);
|
||||||
|
break;
|
||||||
|
case '\b': /* BS */
|
||||||
|
tmoveto(term.c.x-1, term.c.y);
|
||||||
|
break;
|
||||||
|
case '\r': /* CR */
|
||||||
|
tmoveto(0, term.c.y);
|
||||||
|
break;
|
||||||
|
case '\f': /* LF */
|
||||||
|
case '\v': /* VT */
|
||||||
|
case '\n': /* LF */
|
||||||
|
/* go to first col if the mode is set */
|
||||||
|
tnewline(IS_SET(MODE_CRLF));
|
||||||
|
break;
|
||||||
|
case '\a': /* BEL */
|
||||||
|
if(term.esc & ESC_STR_END) {
|
||||||
|
/* backwards compatibility to xterm */
|
||||||
|
strhandle();
|
||||||
|
} else {
|
||||||
|
if(!(xw.state & WIN_FOCUSED))
|
||||||
|
xseturgency(1);
|
||||||
|
if (bellvolume)
|
||||||
|
XBell(xw.dpy, bellvolume);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '\033': /* ESC */
|
||||||
|
csireset();
|
||||||
|
term.esc &= ~(ESC_CSI|ESC_ALTCHARSET|ESC_TEST);
|
||||||
|
term.esc |= ESC_START;
|
||||||
|
return 1;
|
||||||
|
case '\016': /* SO */
|
||||||
|
term.charset = 0;
|
||||||
|
tselcs();
|
||||||
|
break;
|
||||||
|
case '\017': /* SI */
|
||||||
|
term.charset = 1;
|
||||||
|
tselcs();
|
||||||
|
break;
|
||||||
|
case '\032': /* SUB */
|
||||||
|
tsetchar(question, &term.c.attr, term.c.x, term.c.y);
|
||||||
|
case '\030': /* CAN */
|
||||||
|
csireset();
|
||||||
|
break;
|
||||||
|
case '\005': /* ENQ (IGNORED) */
|
||||||
|
case '\000': /* NUL (IGNORED) */
|
||||||
|
case '\021': /* XON (IGNORED) */
|
||||||
|
case '\023': /* XOFF (IGNORED) */
|
||||||
|
case 0177: /* DEL (IGNORED) */
|
||||||
|
case 0x84: /* TODO: IND */
|
||||||
|
case 0x85: /* TODO: NEL */
|
||||||
|
case 0x88: /* TODO: HTS */
|
||||||
|
case 0x8d: /* TODO: RI */
|
||||||
|
case 0x8e: /* TODO: SS2 */
|
||||||
|
case 0x8f: /* TODO: SS3 */
|
||||||
|
case 0x90: /* TODO: DCS */
|
||||||
|
case 0x98: /* TODO: SOS */
|
||||||
|
case 0x9a: /* TODO: DECID */
|
||||||
|
case 0x9b: /* TODO: CSI */
|
||||||
|
case 0x9c: /* TODO: ST */
|
||||||
|
case 0x9d: /* TODO: OSC */
|
||||||
|
case 0x9e: /* TODO: PM */
|
||||||
|
case 0x9f: /* TODO: APC */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
term.esc &= ~(ESC_STR_END|ESC_STR);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
tputc(char *c, int len) {
|
tputc(char *c, int len) {
|
||||||
uchar ascii = *c;
|
uchar ascii;
|
||||||
bool control = ascii < '\x20' || ascii == 0177;
|
bool control;
|
||||||
long unicodep;
|
long unicodep;
|
||||||
int width;
|
int width;
|
||||||
|
|
||||||
if(len == 1) {
|
if(len == 1) {
|
||||||
width = 1;
|
width = 1;
|
||||||
|
ascii = *c;
|
||||||
} else {
|
} else {
|
||||||
utf8decode(c, &unicodep, UTF_SIZ);
|
utf8decode(c, &unicodep, UTF_SIZ);
|
||||||
width = wcwidth(unicodep);
|
width = wcwidth(unicodep);
|
||||||
|
ascii = unicodep;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
control = iscontrol(ascii) && width == 1;
|
||||||
if(IS_SET(MODE_PRINT))
|
if(IS_SET(MODE_PRINT))
|
||||||
tprinter(c, len);
|
tprinter(c, len);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* STR sequences must be checked before anything else
|
* STR sequence must be checked before anything else
|
||||||
* because it can use some control codes as part of the sequence.
|
* because it uses all following characters until it
|
||||||
|
* receives a ESC, a SUB, a ST or any other C1 control
|
||||||
|
* character.
|
||||||
*/
|
*/
|
||||||
if(term.esc & ESC_STR) {
|
if(term.esc & ESC_STR) {
|
||||||
switch(ascii) {
|
if(width == 1 &&
|
||||||
case '\033':
|
(ascii == '\a' || ascii == 030 ||
|
||||||
term.esc = ESC_START | ESC_STR_END;
|
ascii == 032 || ascii == 033 ||
|
||||||
break;
|
ISCONTROLC1(ascii))) {
|
||||||
case '\a': /* backwards compatibility to xterm */
|
term.esc &= ~ESC_STR;
|
||||||
term.esc = 0;
|
term.esc |= ESC_STR_END;
|
||||||
strhandle();
|
} else if(strescseq.len + len < sizeof(strescseq.buf) - 1) {
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if(strescseq.len + len < sizeof(strescseq.buf) - 1) {
|
|
||||||
memmove(&strescseq.buf[strescseq.len], c, len);
|
memmove(&strescseq.buf[strescseq.len], c, len);
|
||||||
strescseq.len += len;
|
strescseq.len += len;
|
||||||
|
return;
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* Here is a bug in terminals. If the user never sends
|
* Here is a bug in terminals. If the user never sends
|
||||||
|
@ -2388,11 +2481,9 @@ tputc(char *c, int len) {
|
||||||
* term.esc = 0;
|
* term.esc = 0;
|
||||||
* strhandle();
|
* strhandle();
|
||||||
*/
|
*/
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Actions of control codes must be performed as soon they arrive
|
* Actions of control codes must be performed as soon they arrive
|
||||||
|
@ -2400,51 +2491,8 @@ tputc(char *c, int len) {
|
||||||
* they must not cause conflicts with sequences.
|
* they must not cause conflicts with sequences.
|
||||||
*/
|
*/
|
||||||
if(control) {
|
if(control) {
|
||||||
switch(ascii) {
|
if (tcontrolcode(ascii))
|
||||||
case '\t': /* HT */
|
|
||||||
tputtab(1);
|
|
||||||
return;
|
return;
|
||||||
case '\b': /* BS */
|
|
||||||
tmoveto(term.c.x-1, term.c.y);
|
|
||||||
return;
|
|
||||||
case '\r': /* CR */
|
|
||||||
tmoveto(0, term.c.y);
|
|
||||||
return;
|
|
||||||
case '\f': /* LF */
|
|
||||||
case '\v': /* VT */
|
|
||||||
case '\n': /* LF */
|
|
||||||
/* go to first col if the mode is set */
|
|
||||||
tnewline(IS_SET(MODE_CRLF));
|
|
||||||
return;
|
|
||||||
case '\a': /* BEL */
|
|
||||||
if(!(xw.state & WIN_FOCUSED))
|
|
||||||
xseturgency(1);
|
|
||||||
if (bellvolume)
|
|
||||||
XBell(xw.dpy, bellvolume);
|
|
||||||
return;
|
|
||||||
case '\033': /* ESC */
|
|
||||||
csireset();
|
|
||||||
term.esc = ESC_START;
|
|
||||||
return;
|
|
||||||
case '\016': /* SO */
|
|
||||||
term.charset = 0;
|
|
||||||
tselcs();
|
|
||||||
return;
|
|
||||||
case '\017': /* SI */
|
|
||||||
term.charset = 1;
|
|
||||||
tselcs();
|
|
||||||
return;
|
|
||||||
case '\032': /* SUB */
|
|
||||||
case '\030': /* CAN */
|
|
||||||
csireset();
|
|
||||||
return;
|
|
||||||
case '\005': /* ENQ (IGNORED) */
|
|
||||||
case '\000': /* NUL (IGNORED) */
|
|
||||||
case '\021': /* XON (IGNORED) */
|
|
||||||
case '\023': /* XOFF (IGNORED) */
|
|
||||||
case 0177: /* DEL (IGNORED) */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else if(term.esc & ESC_START) {
|
} else if(term.esc & ESC_START) {
|
||||||
if(term.esc & ESC_CSI) {
|
if(term.esc & ESC_CSI) {
|
||||||
csiescseq.buf[csiescseq.len++] = ascii;
|
csiescseq.buf[csiescseq.len++] = ascii;
|
||||||
|
|
Loading…
Reference in a new issue