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:'.'); |
