diff options
-rw-r--r-- | TODO | 1 | ||||
-rw-r--r-- | st.c | 279 |
2 files changed, 191 insertions, 89 deletions
@@ -20,6 +20,7 @@ bugs | |||
20 | * fix shift up/down (shift selection in emacs) | 20 | * fix shift up/down (shift selection in emacs) |
21 | * fix selection click | 21 | * fix selection click |
22 | * fix selection paste for xatom STRING | 22 | * fix selection paste for xatom STRING |
23 | * fix umlaut handling in settitle | ||
23 | 24 | ||
24 | misc | 25 | misc |
25 | ---- | 26 | ---- |
@@ -43,9 +43,10 @@ | |||
43 | #define XEMBED_FOCUS_OUT 5 | 43 | #define XEMBED_FOCUS_OUT 5 |
44 | 44 | ||
45 | /* Arbitrary sizes */ | 45 | /* Arbitrary sizes */ |
46 | #define ESC_TITLE_SIZ 256 | ||
47 | #define ESC_BUF_SIZ 256 | 46 | #define ESC_BUF_SIZ 256 |
48 | #define ESC_ARG_SIZ 16 | 47 | #define ESC_ARG_SIZ 16 |
48 | #define STR_BUF_SIZ 256 | ||
49 | #define STR_ARG_SIZ 16 | ||
49 | #define DRAW_BUF_SIZ 1024 | 50 | #define DRAW_BUF_SIZ 1024 |
50 | #define UTF_SIZ 4 | 51 | #define UTF_SIZ 4 |
51 | #define XK_NO_MOD UINT_MAX | 52 | #define XK_NO_MOD UINT_MAX |
@@ -110,9 +111,9 @@ enum term_mode { | |||
110 | enum escape_state { | 111 | enum escape_state { |
111 | ESC_START = 1, | 112 | ESC_START = 1, |
112 | ESC_CSI = 2, | 113 | ESC_CSI = 2, |
113 | ESC_OSC = 4, | 114 | ESC_STR = 4, /* DSC, OSC, PM, APC */ |
114 | ESC_TITLE = 8, | 115 | ESC_ALTCHARSET = 8, |
115 | ESC_ALTCHARSET = 16 | 116 | ESC_STR_END = 16, /* a final string was encountered */ |
116 | }; | 117 | }; |
117 | 118 | ||
118 | enum window_state { | 119 | enum window_state { |
@@ -158,6 +159,16 @@ typedef struct { | |||
158 | char mode; | 159 | char mode; |
159 | } CSIEscape; | 160 | } CSIEscape; |
160 | 161 | ||
162 | /* STR Escape sequence structs */ | ||
163 | /* ESC type [[ [<priv>] <arg> [;]] <mode>] ESC '\' */ | ||
164 | typedef struct { | ||
165 | char type; /* ESC type ... */ | ||
166 | char buf[STR_BUF_SIZ]; /* raw string */ | ||
167 | int len; /* raw string length */ | ||
168 | char *args[STR_ARG_SIZ]; | ||
169 | int narg; /* nb of args */ | ||
170 | } STREscape; | ||
171 | |||
161 | /* Internal representation of the screen */ | 172 | /* Internal representation of the screen */ |
162 | typedef struct { | 173 | typedef struct { |
163 | int row; /* nb row */ | 174 | int row; /* nb row */ |
@@ -170,8 +181,6 @@ typedef struct { | |||
170 | int bot; /* bottom scroll limit */ | 181 | int bot; /* bottom scroll limit */ |
171 | int mode; /* terminal mode flags */ | 182 | int mode; /* terminal mode flags */ |
172 | int esc; /* escape state flags */ | 183 | int esc; /* escape state flags */ |
173 | char title[ESC_TITLE_SIZ]; | ||
174 | int titlelen; | ||
175 | bool *tabs; | 184 | bool *tabs; |
176 | } Term; | 185 | } Term; |
177 | 186 | ||
@@ -239,6 +248,10 @@ static void csidump(void); | |||
239 | static void csihandle(void); | 248 | static void csihandle(void); |
240 | static void csiparse(void); | 249 | static void csiparse(void); |
241 | static void csireset(void); | 250 | static void csireset(void); |
251 | static void strdump(void); | ||
252 | static void strhandle(void); | ||
253 | static void strparse(void); | ||
254 | static void strreset(void); | ||
242 | 255 | ||
243 | static void tclearregion(int, int, int, int); | 256 | static void tclearregion(int, int, int, int); |
244 | static void tcursor(int); | 257 | static void tcursor(int); |
@@ -323,7 +336,8 @@ static void (*handler[LASTEvent])(XEvent *) = { | |||
323 | static DC dc; | 336 | static DC dc; |
324 | static XWindow xw; | 337 | static XWindow xw; |
325 | static Term term; | 338 | static Term term; |
326 | static CSIEscape escseq; | 339 | static CSIEscape csiescseq; |
340 | static STREscape strescseq; | ||
327 | static int cmdfd; | 341 | static int cmdfd; |
328 | static pid_t pid; | 342 | static pid_t pid; |
329 | static Selection sel; | 343 | static Selection sel; |
@@ -968,22 +982,22 @@ tnewline(int first_col) { | |||
968 | void | 982 | void |
969 | csiparse(void) { | 983 | csiparse(void) { |
970 | /* int noarg = 1; */ | 984 | /* int noarg = 1; */ |
971 | char *p = escseq.buf; | 985 | char *p = csiescseq.buf; |
972 | 986 | ||
973 | escseq.narg = 0; | 987 | csiescseq.narg = 0; |
974 | if(*p == '?') | 988 | if(*p == '?') |
975 | escseq.priv = 1, p++; | 989 | csiescseq.priv = 1, p++; |
976 | 990 | ||
977 | while(p < escseq.buf+escseq.len) { | 991 | while(p < csiescseq.buf+csiescseq.len) { |
978 | while(isdigit(*p)) { | 992 | while(isdigit(*p)) { |
979 | escseq.arg[escseq.narg] *= 10; | 993 | csiescseq.arg[csiescseq.narg] *= 10; |
980 | escseq.arg[escseq.narg] += *p++ - '0'/*, noarg = 0 */; | 994 | csiescseq.arg[csiescseq.narg] += *p++ - '0'/*, noarg = 0 */; |
981 | } | 995 | } |
982 | if(*p == ';' && escseq.narg+1 < ESC_ARG_SIZ) | 996 | if(*p == ';' && csiescseq.narg+1 < ESC_ARG_SIZ) |
983 | escseq.narg++, p++; | 997 | csiescseq.narg++, p++; |
984 | else { | 998 | else { |
985 | escseq.mode = *p; | 999 | csiescseq.mode = *p; |
986 | escseq.narg++; | 1000 | csiescseq.narg++; |
987 | return; | 1001 | return; |
988 | } | 1002 | } |
989 | } | 1003 | } |
@@ -1166,7 +1180,7 @@ tsetscroll(int t, int b) { | |||
1166 | 1180 | ||
1167 | void | 1181 | void |
1168 | csihandle(void) { | 1182 | csihandle(void) { |
1169 | switch(escseq.mode) { | 1183 | switch(csiescseq.mode) { |
1170 | default: | 1184 | default: |
1171 | unknown: | 1185 | unknown: |
1172 | fprintf(stderr, "erresc: unknown csi "); | 1186 | fprintf(stderr, "erresc: unknown csi "); |
@@ -1174,37 +1188,37 @@ csihandle(void) { | |||
1174 | /* die(""); */ | 1188 | /* die(""); */ |
1175 | break; | 1189 | break; |
1176 | case '@': /* ICH -- Insert <n> blank char */ | 1190 | case '@': /* ICH -- Insert <n> blank char */ |
1177 | DEFAULT(escseq.arg[0], 1); | 1191 | DEFAULT(csiescseq.arg[0], 1); |
1178 | tinsertblank(escseq.arg[0]); | 1192 | tinsertblank(csiescseq.arg[0]); |
1179 | break; | 1193 | break; |
1180 | case 'A': /* CUU -- Cursor <n> Up */ | 1194 | case 'A': /* CUU -- Cursor <n> Up */ |
1181 | case 'e': | 1195 | case 'e': |
1182 | DEFAULT(escseq.arg[0], 1); | 1196 | DEFAULT(csiescseq.arg[0], 1); |
1183 | tmoveto(term.c.x, term.c.y-escseq.arg[0]); | 1197 | tmoveto(term.c.x, term.c.y-csiescseq.arg[0]); |
1184 | break; | 1198 | break; |
1185 | case 'B': /* CUD -- Cursor <n> Down */ | 1199 | case 'B': /* CUD -- Cursor <n> Down */ |
1186 | DEFAULT(escseq.arg[0], 1); | 1200 | DEFAULT(csiescseq.arg[0], 1); |
1187 | tmoveto(term.c.x, term.c.y+escseq.arg[0]); | 1201 | tmoveto(term.c.x, term.c.y+csiescseq.arg[0]); |
1188 | break; | 1202 | break; |
1189 | case 'C': /* CUF -- Cursor <n> Forward */ | 1203 | case 'C': /* CUF -- Cursor <n> Forward */ |
1190 | case 'a': | 1204 | case 'a': |
1191 | DEFAULT(escseq.arg[0], 1); | 1205 | DEFAULT(csiescseq.arg[0], 1); |
1192 | tmoveto(term.c.x+escseq.arg[0], term.c.y); | 1206 | tmoveto(term.c.x+csiescseq.arg[0], term.c.y); |
1193 | break; | 1207 | break; |
1194 | case 'D': /* CUB -- Cursor <n> Backward */ | 1208 | case 'D': /* CUB -- Cursor <n> Backward */ |
1195 | DEFAULT(escseq.arg[0], 1); | 1209 | DEFAULT(csiescseq.arg[0], 1); |
1196 | tmoveto(term.c.x-escseq.arg[0], term.c.y); | 1210 | tmoveto(term.c.x-csiescseq.arg[0], term.c.y); |
1197 | break; | 1211 | break; |
1198 | case 'E': /* CNL -- Cursor <n> Down and first col */ | 1212 | case 'E': /* CNL -- Cursor <n> Down and first col */ |
1199 | DEFAULT(escseq.arg[0], 1); | 1213 | DEFAULT(csiescseq.arg[0], 1); |
1200 | tmoveto(0, term.c.y+escseq.arg[0]); | 1214 | tmoveto(0, term.c.y+csiescseq.arg[0]); |
1201 | break; | 1215 | break; |
1202 | case 'F': /* CPL -- Cursor <n> Up and first col */ | 1216 | case 'F': /* CPL -- Cursor <n> Up and first col */ |
1203 | DEFAULT(escseq.arg[0], 1); | 1217 | DEFAULT(csiescseq.arg[0], 1); |
1204 | tmoveto(0, term.c.y-escseq.arg[0]); | 1218 | tmoveto(0, term.c.y-csiescseq.arg[0]); |
1205 | break; | 1219 | break; |
1206 | case 'g': /* TBC -- Tabulation clear */ | 1220 | case 'g': /* TBC -- Tabulation clear */ |
1207 | switch (escseq.arg[0]) { | 1221 | switch (csiescseq.arg[0]) { |
1208 | case 0: /* clear current tab stop */ | 1222 | case 0: /* clear current tab stop */ |
1209 | term.tabs[term.c.x] = 0; | 1223 | term.tabs[term.c.x] = 0; |
1210 | break; | 1224 | break; |
@@ -1217,23 +1231,23 @@ csihandle(void) { | |||
1217 | break; | 1231 | break; |
1218 | case 'G': /* CHA -- Move to <col> */ | 1232 | case 'G': /* CHA -- Move to <col> */ |
1219 | case '`': /* XXX: HPA -- same? */ | 1233 | case '`': /* XXX: HPA -- same? */ |
1220 | DEFAULT(escseq.arg[0], 1); | 1234 | DEFAULT(csiescseq.arg[0], 1); |
1221 | tmoveto(escseq.arg[0]-1, term.c.y); | 1235 | tmoveto(csiescseq.arg[0]-1, term.c.y); |
1222 | break; | 1236 | break; |
1223 | case 'H': /* CUP -- Move to <row> <col> */ | 1237 | case 'H': /* CUP -- Move to <row> <col> */ |
1224 | case 'f': /* XXX: HVP -- same? */ | 1238 | case 'f': /* XXX: HVP -- same? */ |
1225 | DEFAULT(escseq.arg[0], 1); | 1239 | DEFAULT(csiescseq.arg[0], 1); |
1226 | DEFAULT(escseq.arg[1], 1); | 1240 | DEFAULT(csiescseq.arg[1], 1); |
1227 | tmoveto(escseq.arg[1]-1, escseq.arg[0]-1); | 1241 | tmoveto(csiescseq.arg[1]-1, csiescseq.arg[0]-1); |
1228 | break; | 1242 | break; |
1229 | case 'I': /* CHT -- Cursor Forward Tabulation <n> tab stops */ | 1243 | case 'I': /* CHT -- Cursor Forward Tabulation <n> tab stops */ |
1230 | DEFAULT(escseq.arg[0], 1); | 1244 | DEFAULT(csiescseq.arg[0], 1); |
1231 | while (escseq.arg[0]--) | 1245 | while (csiescseq.arg[0]--) |
1232 | tputtab(); | 1246 | tputtab(); |
1233 | break; | 1247 | break; |
1234 | case 'J': /* ED -- Clear screen */ | 1248 | case 'J': /* ED -- Clear screen */ |
1235 | sel.bx = -1; | 1249 | sel.bx = -1; |
1236 | switch(escseq.arg[0]) { | 1250 | switch(csiescseq.arg[0]) { |
1237 | case 0: /* below */ | 1251 | case 0: /* below */ |
1238 | tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); | 1252 | tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); |
1239 | if(term.c.y < term.row-1) | 1253 | if(term.c.y < term.row-1) |
@@ -1252,7 +1266,7 @@ csihandle(void) { | |||
1252 | } | 1266 | } |
1253 | break; | 1267 | break; |
1254 | case 'K': /* EL -- Clear line */ | 1268 | case 'K': /* EL -- Clear line */ |
1255 | switch(escseq.arg[0]) { | 1269 | switch(csiescseq.arg[0]) { |
1256 | case 0: /* right */ | 1270 | case 0: /* right */ |
1257 | tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); | 1271 | tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); |
1258 | break; | 1272 | break; |
@@ -1265,20 +1279,20 @@ csihandle(void) { | |||
1265 | } | 1279 | } |
1266 | break; | 1280 | break; |
1267 | case 'S': /* SU -- Scroll <n> line up */ | 1281 | case 'S': /* SU -- Scroll <n> line up */ |
1268 | DEFAULT(escseq.arg[0], 1); | 1282 | DEFAULT(csiescseq.arg[0], 1); |
1269 | tscrollup(term.top, escseq.arg[0]); | 1283 | tscrollup(term.top, csiescseq.arg[0]); |
1270 | break; | 1284 | break; |
1271 | case 'T': /* SD -- Scroll <n> line down */ | 1285 | case 'T': /* SD -- Scroll <n> line down */ |
1272 | DEFAULT(escseq.arg[0], 1); | 1286 | DEFAULT(csiescseq.arg[0], 1); |
1273 | tscrolldown(term.top, escseq.arg[0]); | 1287 | tscrolldown(term.top, csiescseq.arg[0]); |
1274 | break; | 1288 | break; |
1275 | case 'L': /* IL -- Insert <n> blank lines */ | 1289 | case 'L': /* IL -- Insert <n> blank lines */ |
1276 | DEFAULT(escseq.arg[0], 1); | 1290 | DEFAULT(csiescseq.arg[0], 1); |
1277 | tinsertblankline(escseq.arg[0]); | 1291 | tinsertblankline(csiescseq.arg[0]); |
1278 | break; | 1292 | break; |
1279 | case 'l': /* RM -- Reset Mode */ | 1293 | case 'l': /* RM -- Reset Mode */ |
1280 | if(escseq.priv) { | 1294 | if(csiescseq.priv) { |
1281 | switch(escseq.arg[0]) { | 1295 | switch(csiescseq.arg[0]) { |
1282 | case 1: | 1296 | case 1: |
1283 | term.mode &= ~MODE_APPKEYPAD; | 1297 | term.mode &= ~MODE_APPKEYPAD; |
1284 | break; | 1298 | break; |
@@ -1312,7 +1326,7 @@ csihandle(void) { | |||
1312 | tclearregion(0, 0, term.col-1, term.row-1); | 1326 | tclearregion(0, 0, term.col-1, term.row-1); |
1313 | tswapscreen(); | 1327 | tswapscreen(); |
1314 | } | 1328 | } |
1315 | if(escseq.arg[0] != 1049) | 1329 | if(csiescseq.arg[0] != 1049) |
1316 | break; | 1330 | break; |
1317 | case 1048: | 1331 | case 1048: |
1318 | tcursor(CURSOR_LOAD); | 1332 | tcursor(CURSOR_LOAD); |
@@ -1321,7 +1335,7 @@ csihandle(void) { | |||
1321 | goto unknown; | 1335 | goto unknown; |
1322 | } | 1336 | } |
1323 | } else { | 1337 | } else { |
1324 | switch(escseq.arg[0]) { | 1338 | switch(csiescseq.arg[0]) { |
1325 | case 4: | 1339 | case 4: |
1326 | term.mode &= ~MODE_INSERT; | 1340 | term.mode &= ~MODE_INSERT; |
1327 | break; | 1341 | break; |
@@ -1331,25 +1345,25 @@ csihandle(void) { | |||
1331 | } | 1345 | } |
1332 | break; | 1346 | break; |
1333 | case 'M': /* DL -- Delete <n> lines */ | 1347 | case 'M': /* DL -- Delete <n> lines */ |
1334 | DEFAULT(escseq.arg[0], 1); | 1348 | DEFAULT(csiescseq.arg[0], 1); |
1335 | tdeleteline(escseq.arg[0]); | 1349 | tdeleteline(csiescseq.arg[0]); |
1336 | break; | 1350 | break; |
1337 | case 'X': /* ECH -- Erase <n> char */ | 1351 | case 'X': /* ECH -- Erase <n> char */ |
1338 | DEFAULT(escseq.arg[0], 1); | 1352 | DEFAULT(csiescseq.arg[0], 1); |
1339 | tclearregion(term.c.x, term.c.y, term.c.x + escseq.arg[0], term.c.y); | 1353 | tclearregion(term.c.x, term.c.y, term.c.x + csiescseq.arg[0], term.c.y); |
1340 | break; | 1354 | break; |
1341 | case 'P': /* DCH -- Delete <n> char */ | 1355 | case 'P': /* DCH -- Delete <n> char */ |
1342 | DEFAULT(escseq.arg[0], 1); | 1356 | DEFAULT(csiescseq.arg[0], 1); |
1343 | tdeletechar(escseq.arg[0]); | 1357 | tdeletechar(csiescseq.arg[0]); |
1344 | break; | 1358 | break; |
1345 | /* XXX: (CSI n Z) CBT -- Cursor Backward Tabulation <n> tab stops */ | 1359 | /* XXX: (CSI n Z) CBT -- Cursor Backward Tabulation <n> tab stops */ |
1346 | case 'd': /* VPA -- Move to <row> */ | 1360 | case 'd': /* VPA -- Move to <row> */ |
1347 | DEFAULT(escseq.arg[0], 1); | 1361 | DEFAULT(csiescseq.arg[0], 1); |
1348 | tmoveto(term.c.x, escseq.arg[0]-1); | 1362 | tmoveto(term.c.x, csiescseq.arg[0]-1); |
1349 | break; | 1363 | break; |
1350 | case 'h': /* SM -- Set terminal mode */ | 1364 | case 'h': /* SM -- Set terminal mode */ |
1351 | if(escseq.priv) { | 1365 | if(csiescseq.priv) { |
1352 | switch(escseq.arg[0]) { | 1366 | switch(csiescseq.arg[0]) { |
1353 | case 1: | 1367 | case 1: |
1354 | term.mode |= MODE_APPKEYPAD; | 1368 | term.mode |= MODE_APPKEYPAD; |
1355 | break; | 1369 | break; |
@@ -1367,7 +1381,7 @@ csihandle(void) { | |||
1367 | break; | 1381 | break; |
1368 | case 12: /* att610 -- Start blinking cursor (IGNORED) */ | 1382 | case 12: /* att610 -- Start blinking cursor (IGNORED) */ |
1369 | /* fallthrough for xterm cvvis = CSI [ ? 12 ; 25 h */ | 1383 | /* fallthrough for xterm cvvis = CSI [ ? 12 ; 25 h */ |
1370 | if(escseq.narg > 1 && escseq.arg[1] != 25) | 1384 | if(csiescseq.narg > 1 && csiescseq.arg[1] != 25) |
1371 | break; | 1385 | break; |
1372 | case 25: | 1386 | case 25: |
1373 | term.c.state &= ~CURSOR_HIDE; | 1387 | term.c.state &= ~CURSOR_HIDE; |
@@ -1385,7 +1399,7 @@ csihandle(void) { | |||
1385 | tclearregion(0, 0, term.col-1, term.row-1); | 1399 | tclearregion(0, 0, term.col-1, term.row-1); |
1386 | else | 1400 | else |
1387 | tswapscreen(); | 1401 | tswapscreen(); |
1388 | if(escseq.arg[0] != 1049) | 1402 | if(csiescseq.arg[0] != 1049) |
1389 | break; | 1403 | break; |
1390 | case 1048: | 1404 | case 1048: |
1391 | tcursor(CURSOR_SAVE); | 1405 | tcursor(CURSOR_SAVE); |
@@ -1393,7 +1407,7 @@ csihandle(void) { | |||
1393 | default: goto unknown; | 1407 | default: goto unknown; |
1394 | } | 1408 | } |
1395 | } else { | 1409 | } else { |
1396 | switch(escseq.arg[0]) { | 1410 | switch(csiescseq.arg[0]) { |
1397 | case 4: | 1411 | case 4: |
1398 | term.mode |= MODE_INSERT; | 1412 | term.mode |= MODE_INSERT; |
1399 | break; | 1413 | break; |
@@ -1402,15 +1416,15 @@ csihandle(void) { | |||
1402 | }; | 1416 | }; |
1403 | break; | 1417 | break; |
1404 | case 'm': /* SGR -- Terminal attribute (color) */ | 1418 | case 'm': /* SGR -- Terminal attribute (color) */ |
1405 | tsetattr(escseq.arg, escseq.narg); | 1419 | tsetattr(csiescseq.arg, csiescseq.narg); |
1406 | break; | 1420 | break; |
1407 | case 'r': /* DECSTBM -- Set Scrolling Region */ | 1421 | case 'r': /* DECSTBM -- Set Scrolling Region */ |
1408 | if(escseq.priv) | 1422 | if(csiescseq.priv) |
1409 | goto unknown; | 1423 | goto unknown; |
1410 | else { | 1424 | else { |
1411 | DEFAULT(escseq.arg[0], 1); | 1425 | DEFAULT(csiescseq.arg[0], 1); |
1412 | DEFAULT(escseq.arg[1], term.row); | 1426 | DEFAULT(csiescseq.arg[1], term.row); |
1413 | tsetscroll(escseq.arg[0]-1, escseq.arg[1]-1); | 1427 | tsetscroll(csiescseq.arg[0]-1, csiescseq.arg[1]-1); |
1414 | tmoveto(0, 0); | 1428 | tmoveto(0, 0); |
1415 | } | 1429 | } |
1416 | break; | 1430 | break; |
@@ -1427,8 +1441,8 @@ void | |||
1427 | csidump(void) { | 1441 | csidump(void) { |
1428 | int i; | 1442 | int i; |
1429 | printf("ESC["); | 1443 | printf("ESC["); |
1430 | for(i = 0; i < escseq.len; i++) { | 1444 | for(i = 0; i < csiescseq.len; i++) { |
1431 | uint c = escseq.buf[i] & 0xff; | 1445 | uint c = csiescseq.buf[i] & 0xff; |
1432 | if(isprint(c)) putchar(c); | 1446 | if(isprint(c)) putchar(c); |
1433 | else if(c == '\n') printf("(\\n)"); | 1447 | else if(c == '\n') printf("(\\n)"); |
1434 | else if(c == '\r') printf("(\\r)"); | 1448 | else if(c == '\r') printf("(\\r)"); |
@@ -1440,7 +1454,80 @@ csidump(void) { | |||
1440 | 1454 | ||
1441 | void | 1455 | void |
1442 | csireset(void) { | 1456 | csireset(void) { |
1443 | memset(&escseq, 0, sizeof(escseq)); | 1457 | memset(&csiescseq, 0, sizeof(csiescseq)); |
1458 | } | ||
1459 | |||
1460 | void | ||
1461 | strhandle(void) { | ||
1462 | char *p; | ||
1463 | |||
1464 | p = strescseq.buf; | ||
1465 | |||
1466 | switch(strescseq.type) { | ||
1467 | case ']': /* OSC -- Operating System Command */ | ||
1468 | switch(p[0]) { | ||
1469 | case '0': | ||
1470 | case '2': | ||
1471 | /* | ||
1472 | * TODO: Handle special chars in string, like umlauts. | ||
1473 | */ | ||
1474 | if(p[1] == ';') { | ||
1475 | if(!strncmp(strescseq.buf, "settitle ", 9)) { | ||
1476 | XStoreName(xw.dpy, xw.win, strescseq.buf+11); | ||
1477 | } else { | ||
1478 | XStoreName(xw.dpy, xw.win, strescseq.buf+2); | ||
1479 | } | ||
1480 | } | ||
1481 | break; | ||
1482 | case ';': | ||
1483 | XStoreName(xw.dpy, xw.win, strescseq.buf+1); | ||
1484 | break; | ||
1485 | case '4': /* TODO: Set color (arg0) to "rgb:%hexr/$hexg/$hexb" (arg1) */ | ||
1486 | break; | ||
1487 | default: | ||
1488 | fprintf(stderr, "erresc: unknown str "); | ||
1489 | strdump(); | ||
1490 | break; | ||
1491 | } | ||
1492 | break; | ||
1493 | case 'P': /* DSC -- Device Control String */ | ||
1494 | case '_': /* APC -- Application Program Command */ | ||
1495 | case '^': /* PM -- Privacy Message */ | ||
1496 | default: | ||
1497 | fprintf(stderr, "erresc: unknown str "); | ||
1498 | strdump(); | ||
1499 | /* die(""); */ | ||
1500 | break; | ||
1501 | } | ||
1502 | } | ||
1503 | |||
1504 | void | ||
1505 | strparse(void) { | ||
1506 | /* | ||
1507 | * TODO: Implement parsing like for CSI when required. | ||
1508 | * Format: ESC type cmd ';' arg0 [';' argn] ESC \ | ||
1509 | */ | ||
1510 | return; | ||
1511 | } | ||
1512 | |||
1513 | void | ||
1514 | strdump(void) { | ||
1515 | int i; | ||
1516 | printf("ESC%c", strescseq.type); | ||
1517 | for(i = 0; i < strescseq.len; i++) { | ||
1518 | uint c = strescseq.buf[i] & 0xff; | ||
1519 | if(isprint(c)) putchar(c); | ||
1520 | else if(c == '\n') printf("(\\n)"); | ||
1521 | else if(c == '\r') printf("(\\r)"); | ||
1522 | else if(c == 0x1b) printf("(\\e)"); | ||
1523 | else printf("(%02x)", c); | ||
1524 | } | ||
1525 | printf("ESC\\\n"); | ||
1526 | } | ||
1527 | |||
1528 | void | ||
1529 | strreset(void) { | ||
1530 | memset(&strescseq, 0, sizeof(strescseq)); | ||
1444 | } | 1531 | } |
1445 | 1532 | ||
1446 | void | 1533 | void |
@@ -1457,25 +1544,31 @@ tputc(char *c) { | |||
1457 | char ascii = *c; | 1544 | char ascii = *c; |
1458 | if(term.esc & ESC_START) { | 1545 | if(term.esc & ESC_START) { |
1459 | if(term.esc & ESC_CSI) { | 1546 | if(term.esc & ESC_CSI) { |
1460 | escseq.buf[escseq.len++] = ascii; | 1547 | csiescseq.buf[csiescseq.len++] = ascii; |
1461 | if(BETWEEN(ascii, 0x40, 0x7E) || escseq.len >= ESC_BUF_SIZ) { | 1548 | if(BETWEEN(ascii, 0x40, 0x7E) || csiescseq.len >= ESC_BUF_SIZ) { |
1462 | term.esc = 0; | 1549 | term.esc = 0; |
1463 | csiparse(), csihandle(); | 1550 | csiparse(), csihandle(); |
1464 | } | 1551 | } |
1465 | /* TODO: handle other OSC */ | 1552 | } else if(term.esc & ESC_STR) { |
1466 | } else if(term.esc & ESC_OSC) { | 1553 | switch(ascii) { |
1467 | if(ascii == ';') { | 1554 | case '\033': |
1468 | term.titlelen = 0; | 1555 | term.esc = ESC_START | ESC_STR_END; |
1469 | term.esc = ESC_START | ESC_TITLE; | 1556 | break; |
1470 | } | 1557 | case '\a': /* backwards compatibility to xterm */ |
1471 | } else if(term.esc & ESC_TITLE) { | ||
1472 | if(ascii == '\a' || term.titlelen+1 >= ESC_TITLE_SIZ) { | ||
1473 | term.esc = 0; | 1558 | term.esc = 0; |
1474 | term.title[term.titlelen] = '\0'; | 1559 | strhandle(); |
1475 | XStoreName(xw.dpy, xw.win, term.title); | 1560 | break; |
1476 | } else { | 1561 | default: |
1477 | term.title[term.titlelen++] = ascii; | 1562 | strescseq.buf[strescseq.len++] = ascii; |
1563 | if (strescseq.len+1 >= STR_BUF_SIZ) { | ||
1564 | term.esc = 0; | ||
1565 | strhandle(); | ||
1566 | } | ||
1478 | } | 1567 | } |
1568 | } else if(term.esc & ESC_STR_END) { | ||
1569 | term.esc = 0; | ||
1570 | if(ascii == '\\') | ||
1571 | strhandle(); | ||
1479 | } else if(term.esc & ESC_ALTCHARSET) { | 1572 | } else if(term.esc & ESC_ALTCHARSET) { |
1480 | switch(ascii) { | 1573 | switch(ascii) { |
1481 | case '0': /* Line drawing crap */ | 1574 | case '0': /* Line drawing crap */ |
@@ -1493,8 +1586,13 @@ tputc(char *c) { | |||
1493 | case '[': | 1586 | case '[': |
1494 | term.esc |= ESC_CSI; | 1587 | term.esc |= ESC_CSI; |
1495 | break; | 1588 | break; |
1496 | case ']': | 1589 | case 'P': /* DCS -- Device Control String */ |
1497 | term.esc |= ESC_OSC; | 1590 | case '_': /* APC -- Application Program Command */ |
1591 | case '^': /* PM -- Privacy Message */ | ||
1592 | case ']': /* OSC -- Operating System Command */ | ||
1593 | strreset(); | ||
1594 | strescseq.type = ascii; | ||
1595 | term.esc |= ESC_STR; | ||
1498 | break; | 1596 | break; |
1499 | case '(': | 1597 | case '(': |
1500 | term.esc |= ESC_ALTCHARSET; | 1598 | term.esc |= ESC_ALTCHARSET; |
@@ -1541,6 +1639,9 @@ tputc(char *c) { | |||
1541 | tcursor(CURSOR_LOAD); | 1639 | tcursor(CURSOR_LOAD); |
1542 | term.esc = 0; | 1640 | term.esc = 0; |
1543 | break; | 1641 | break; |
1642 | case '\\': /* ST -- Stop */ | ||
1643 | term.esc = 0; | ||
1644 | break; | ||
1544 | default: | 1645 | default: |
1545 | fprintf(stderr, "erresc: unknown sequence ESC 0x%02X '%c'\n", | 1646 | fprintf(stderr, "erresc: unknown sequence ESC 0x%02X '%c'\n", |
1546 | (uchar) ascii, isprint(ascii)?ascii:'.'); | 1647 | (uchar) ascii, isprint(ascii)?ascii:'.'); |