1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
//Types of ANSI Escape Sequences
//C0 [0x07-0x0A|0x0C-0x0D|0x1B]
//C1/Fe [ESC][0x40-0x5F]
// technically can be represented in 1 byte w/ bytes above 0x80 but
// unimplemented b/c of unicode
// STring Terminator ESC \
//CSI (ESC\[|0x9B)[0-9:;<=>?]*[!"#$%&'()*+,-./]*[&A-Z[\]^_`a-z{|}~]
//OSC (ESC\]|0x9D).*(0x9C|0x1B 0x5C)
//OCS (ESCP|0x90).*(0x9C|0x1B 0x5C)
//Fs ESC[0x60-0x7E]
//nF ESC[0x20-02F]*[0x30-0x7E]
//Fp ESC[0x30-0x3F] save and clear
//last read key
enum esc_state {
//C0 except BEL or ESC, \n ,\r and \f
C0,
ESC,
CSI_START,
CSI_MID,
CSI_END,
//OSC, DCS, PM APC etc ST terminted C1,
C1_START,
ST,
nF_START,
nF_END,
//other fixed elngth C1, Fs,
C1,
//save and clear
DECSC,
DECRC,
NORMAL,
//escape followed by an escape, has to be user generated
DOUBLE_ESC,
};
//global stdin -> pty ESC state
enum esc_state in_state = NORMAL;
//global pty -> stdout ESC state
enum esc_state out_state = NORMAL;
//c0 c1 c2 osc, sf nF sequences
//also ESC 7 and ESC 8 up down bit
//have a semaphore and above lock, IM will draw if available when input updates
//or if some time has passed since output has been written
enum esc_state update_esc_state(char * buff,unsigned int buff_len, enum esc_state state) {
for (int i = 0; i < buff_len; i++) {
char c = buff[i];
switch (state) {
case CSI_END:
case ST:
case nF_END:
case C0:
case C1:
case DECSC:
case DECRC:
case DOUBLE_ESC:
//all the sequences that have ended don't have an end
//and default to normal
case NORMAL:
if (c >= 0x08 && c <= 0x0A) {
state = C0;
}
if (c == 0x1B) {
state = ESC;
} else {
//return to normal
state = NORMAL;
}
break;
case ESC:
//fix length C1
if (c == 'N' || c == 'O') {
state = C1;
}
else if (c == '[') {
state = CSI_START;
}
//ST terminated C1 OSC, DCS, SOS, PM, APC
else if (c == ']' || c =='P' || c == '^' || c == 'X' || c == '_') {
state = C1_START;
}
//nF
else if (c >= 0x20 && c <= 0x2F) {
state = nF_START;
}
else if (c == '\\') {
state - ST;
}
else if (c == '7') {
state = DECSC;
}
else if (c == '8') {
state = DECSC;
}
else if (c == 0x1B) {
state = DOUBLE_ESC;
//deformed escape sequence
}
else {
state = NORMAL;
}
break;
case C1_START:
if (c == 0x1B) {
state = ESC;
}
if (c == 0x9C) {
state = ST;
}
break;
case CSI_START:
case CSI_MID:
if (c >= 0x30 && c <= 0x3F) {
state = CSI_MID;
} else if (c >= 0x20 && c <= 0x2F) {
state = CSI_MID;
} else if (c >= 0x40 && c <= 0x7E) {
state = CSI_END;
} else {
//malformed CSI sequence
state = NORMAL;
}
break;
case nF_START:
if (c >= 0x20 && c <= 0x2F) {
state = nF_START;
} else if (c >= 0x30 && c <= 0x7E) {
state = nF_END;
//malformed nF sequence
} else {
state = NORMAL;
}
break;
}
}
return state;
}
|