Changeset 3989
- Timestamp:
- 11/21/09 15:58:11 (3 years ago)
- File:
-
- 1 edited
-
neercs/trunk/src/term.c (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
neercs/trunk/src/term.c
r3988 r3989 125 125 unsigned int, unsigned int const *); 126 126 127 static int handle_single_char(unsigned char c, int *x, int *y, 128 struct screen_list *screen_list, 129 struct screen *sc); 130 131 static int handle_single_char(unsigned char c, int *x, int *y, 132 struct screen_list *screen_list, 133 struct screen *sc) 134 { 135 if (c == '\r') 136 { 137 *x = 0; 138 } 139 140 else if (c == '\n') 141 { 142 *x = 0; 143 *y = *y + 1; 144 } 145 else if (c == '\a') 146 { 147 if (!sc->bell) 148 screen_list->in_bell++; 149 sc->bell = 1; 150 } 151 152 else if (c == '\t') 153 { 154 *x = (*x + 7) & ~7; 155 } 156 157 else if (c == '\x08') 158 { 159 if (*x > 0) 160 *x = *x - 1; 161 } 162 163 else if (c == '\x0e') 164 { 165 /* Shift Out (Ctrl-N) -> Switch to Alternate Character Set: invokes 166 the G1 character set. */ 167 sc->conv_state.glr[0] = 1; 168 } 169 170 else if (c == '\x0f') 171 { 172 /* Shift In (Ctrl-O) -> Switch to Standard Character Set: invokes the 173 G0 character set. */ 174 sc->conv_state.glr[0] = 0; 175 } 176 else 177 { 178 return 1; 179 } 180 return 0; 181 182 } 183 127 184 long int import_term(struct screen_list *screen_list, struct screen *sc, 128 185 void const *data, unsigned int size) … … 166 223 skip = 1; 167 224 168 if (buffer[i] == '\r') 169 { 170 x = 0; 171 } 172 173 else if (buffer[i] == '\n') 174 { 175 x = 0; 176 y++; 177 } 178 else if (buffer[i] == '\a') 179 { 180 if (!sc->bell) 181 screen_list->in_bell++; 182 sc->bell = 1; 183 } 184 185 else if (buffer[i] == '\t') 186 { 187 x = (x + 7) & ~7; 188 } 189 190 else if (buffer[i] == '\x08') 191 { 192 if (x > 0) 193 x--; 194 } 195 196 else if (buffer[i] == '\x0e') 197 { 198 /* Shift Out (Ctrl-N) -> Switch to Alternate Character Set: 199 invokes the G1 character set. */ 200 sc->conv_state.glr[0] = 1; 201 } 202 203 else if (buffer[i] == '\x0f') 204 { 205 /* Shift In (Ctrl-O) -> Switch to Standard Character Set: invokes 206 the G0 character set. */ 207 sc->conv_state.glr[0] = 0; 208 } 225 #define ASCCHAR(c) (c>31&&c<127)?c:'?' 226 if (buffer[i] == '\033') 227 { 228 debug("ansi ESC : '%c%c%c%c%c'\n", 229 ASCCHAR(buffer[i + 1]), 230 ASCCHAR(buffer[i + 2]), 231 ASCCHAR(buffer[i + 3]), 232 ASCCHAR(buffer[i + 4]), ASCCHAR(buffer[i + 5])); 233 } 234 235 if(!handle_single_char(buffer[i], &x, &y, screen_list, sc)) 236 {} 237 209 238 210 239 /* If there are not enough characters to parse the escape sequence, 211 240 wait until the next try. We require 3. */ 212 else if (buffer[i] == '\033' && i + 2 >= size) 213 break; 241 242 else if (buffer[i] == '\033' && i + 2 >= size) 243 break; 214 244 215 245 /* Single Shift Select of G2 Character Set (SS2: 0x8e): affects next 216 246 character only */ 217 else if (buffer[i] == '\033' && buffer[i + 1] == 'N')218 {219 sc->conv_state.ss = 2;220 skip += 1;221 }247 else if (buffer[i] == '\033' && buffer[i + 1] == 'N') 248 { 249 sc->conv_state.ss = 2; 250 skip += 1; 251 } 222 252 /* Reverse Index (RI) go up one line, reverse scroll if necessary */ 223 else if (buffer[i] == '\033' && buffer[i + 1] == 'M') 224 { 225 /* FIXME : not sure about the meaning of 'go up one line' and 'if 226 necessary' words. Implemented as a scroller only. */ 227 for (j = bottom - 1; j > top; j--) 253 else if (buffer[i] == '\033' && buffer[i + 1] == 'M') 254 { 255 /* FIXME : not sure about the meaning of 'go up one line' and 'if 256 necessary' words. Implemented as a scroller only. */ 257 for (j = bottom - 1; j > top; j--) 258 { 259 for (k = 0; k < width; k++) 260 { 261 caca_put_char(sc->cv, k, j, caca_get_char(sc->cv, k, j - 1)); 262 caca_put_attr(sc->cv, k, j, caca_get_attr(sc->cv, k, j - 1)); 263 } 264 } 265 caca_draw_line(sc->cv, 0, top - 1, width - 1, top - 1, ' '); 266 skip += 1; 267 } 268 269 /* Single Shift Select of G3 Character Set (SS2: 0x8f): affects next 270 character only */ 271 else if (buffer[i] == '\033' && buffer[i + 1] == 'O') 272 { 273 sc->conv_state.ss = 3; 274 skip += 1; 275 } 276 277 /* LOCKING-SHIFT TWO (LS2), ISO 2022, ECMA-48 (1986), ISO 6429 : 1988 */ 278 else if (buffer[i] == '\033' && buffer[i + 1] == 'n') 279 { 280 sc->conv_state.glr[0] = 2; 281 skip += 1; 282 } 283 284 /* LOCKING-SHIFT THREE (LS3) ISO 2022, ECMA-48 (1986), ISO 6429 : 1988 285 */ 286 else if (buffer[i] == '\033' && buffer[i + 1] == 'o') 287 { 288 sc->conv_state.glr[0] = 3; 289 skip += 1; 290 } 291 292 /* RESET TO INITIAL STATE (RIS), ECMA-48 (1986), ISO 6429 : 1988 */ 293 else if (buffer[i] == '\033' && buffer[i + 1] == 'c') 294 { 295 sc->dfg = CACA_DEFAULT; 296 sc->dbg = CACA_DEFAULT; 297 298 caca_set_color_ansi(sc->cv, sc->dfg, sc->dbg); 299 sc->clearattr = caca_get_attr(sc->cv, -1, -1); 300 ansi_parse_grcm(sc, 1, &dummy); 301 302 reset_conv_state(sc); 303 skip += 1; 304 } 305 306 /* Coding Method Delimiter (CMD), ECMA-48 (1991), ISO/IEC 6429:1992 307 (ISO IR 189) */ 308 else if (buffer[i] == '\033' && buffer[i + 1] == 'd') 309 { 310 reset_conv_state(sc); 311 skip += 1; 312 } 313 314 /* GZDM4, G0-Designators, multi, 94^n chars [grandfathered short form 315 from ISO 2022:1986] */ 316 else if (buffer[i] == '\033' && buffer[i + 1] == '$' 317 && (buffer[i + 2] >= '@') && (buffer[i + 2] <= 'C')) 318 { 319 sc->conv_state.gn[0] = LITERAL2CHAR('$', buffer[i + 2]); 320 skip += 2; 321 } 322 323 /* GnDMx Gn-Designators, 9x^n chars; need one more char to distinguish 324 these */ 325 else if (buffer[i] == '\033' && buffer[i + 1] == '$' && (i + 3 >= size)) 326 break; 327 328 /* GZD4 G0-Designator, 94 chars */ 329 else if (buffer[i] == '\033' && buffer[i + 1] == '(') 330 { 331 sc->conv_state.gn[0] = buffer[i + 2]; 332 skip += 2; 333 } 334 335 /* G1D4 G1-Designator, 94 chars */ 336 else if (buffer[i] == '\033' && buffer[i + 1] == ')') 337 { 338 sc->conv_state.gn[1] = buffer[i + 2]; 339 skip += 2; 340 } 341 342 /* G2D4 G2-Designator, 94 chars */ 343 else if (buffer[i] == '\033' && buffer[i + 1] == '*') 344 { 345 sc->conv_state.gn[2] = buffer[i + 2]; 346 skip += 2; 347 } 348 349 /* G3D4 G3-Designator, 94 chars */ 350 else if (buffer[i] == '\033' && buffer[i + 1] == '+') 351 { 352 sc->conv_state.gn[3] = buffer[i + 2]; 353 skip += 2; 354 } 355 356 /* G2D6 G2-Designator, 96 chars */ 357 else if (buffer[i] == '\033' && buffer[i + 1] == '.') 358 { 359 sc->conv_state.gn[2] = LITERAL2CHAR('.', buffer[i + 2]); 360 skip += 2; 361 } 362 363 /* G3D6 G3-Designator, 96 chars */ 364 else if (buffer[i] == '\033' && buffer[i + 1] == '/') 365 { 366 sc->conv_state.gn[3] = LITERAL2CHAR('.', buffer[i + 2]); 367 skip += 2; 368 } 369 370 /* GZDM4 G0-Designator, 94^n chars */ 371 else if (buffer[i] == '\033' && buffer[i + 1] == '$' 372 && buffer[i + 2] == '(') 373 { 374 sc->conv_state.gn[0] = LITERAL2CHAR('$', buffer[i + 3]); 375 skip += 3; 376 } 377 378 /* G1DM4 G1-Designator, 94^n chars */ 379 else if (buffer[i] == '\033' && buffer[i + 1] == '$' 380 && buffer[i + 2] == ')') 381 { 382 sc->conv_state.gn[1] = LITERAL2CHAR('$', buffer[i + 3]); 383 skip += 3; 384 } 385 386 /* G2DM4 G2-Designator, 94^n chars */ 387 else if (buffer[i] == '\033' && buffer[i + 1] == '$' 388 && buffer[i + 2] == '*') 389 { 390 sc->conv_state.gn[2] = LITERAL2CHAR('$', buffer[i + 3]); 391 skip += 3; 392 } 393 394 /* G3DM4 G3-Designator, 94^n chars */ 395 else if (buffer[i] == '\033' && buffer[i + 1] == '$' 396 && buffer[i + 2] == '+') 397 { 398 sc->conv_state.gn[3] = LITERAL2CHAR('$', buffer[i + 3]); 399 skip += 3; 400 } 401 402 /* G2DM6 G2-Designator, 96^n chars */ 403 else if (buffer[i] == '\033' && buffer[i + 1] == '$' 404 && buffer[i + 2] == '.') 405 { 406 sc->conv_state.gn[2] = LITERAL3CHAR('$', '.', buffer[i + 3]); 407 skip += 3; 408 } 409 410 /* G3DM6 G3-Designator, 96^n chars */ 411 else if (buffer[i] == '\033' && buffer[i + 1] == '$' 412 && buffer[i + 2] == '/') 413 { 414 sc->conv_state.gn[3] = LITERAL3CHAR('$', '.', buffer[i + 3]); 415 skip += 3; 416 } 417 else if (buffer[i] == '\033' && buffer[i + 1] == '#') 418 { 419 debug("ansi private '#' sequence\n"); 420 421 switch (buffer[i + 2]) 422 { 423 case '8': /* DECALN Fills the entire screen area with 424 uppercase Es for screen focus and 425 alignment. */ 426 for (j = 0; j < height; j++) 228 427 { 229 428 for (k = 0; k < width; k++) 230 429 { 231 caca_put_char(sc->cv, k, j, 232 caca_get_char(sc->cv, k, j - 1)); 233 caca_put_attr(sc->cv, k, j, 234 caca_get_attr(sc->cv, k, j - 1)); 430 caca_put_char(sc->cv, k, j, 'E'); 235 431 } 236 432 } 237 caca_draw_line(sc->cv, 0, top - 1, width - 1, top - 1, ' '); 238 skip += 1; 239 } 240 241 /* Single Shift Select of G3 Character Set (SS2: 0x8f): affects next 242 character only */ 243 else if (buffer[i] == '\033' && buffer[i + 1] == 'O') 244 { 245 sc->conv_state.ss = 3; 246 skip += 1; 247 } 248 249 /* LOCKING-SHIFT TWO (LS2), ISO 2022, ECMA-48 (1986), ISO 6429 : 1988 */ 250 else if (buffer[i] == '\033' && buffer[i + 1] == 'n') 251 { 252 sc->conv_state.glr[0] = 2; 253 skip += 1; 254 } 255 256 /* LOCKING-SHIFT THREE (LS3) ISO 2022, ECMA-48 (1986), ISO 6429 : 1988 433 skip += 2; 434 break; 435 436 default: 437 debug("Unknow private sequence 'ESC#%c'\n", buffer[i + 2]); 438 continue; 439 } 440 441 } 442 /* Interpret escape commands, as per Standard ECMA-48 "Control 443 Functions for Coded Character Sets", 5.4. Control sequences. */ 444 else if (buffer[i] == '\033' && buffer[i + 1] == '[') 445 { 446 unsigned int argc = 0, argv[101]; 447 unsigned int param, inter, junk, final; 448 449 450 /* Compute offsets to parameter bytes, intermediate bytes and to the 451 final byte. Only the final byte is mandatory, there can be zero of 452 the others. 0 param=2 inter final final+1 453 +-----+------------------+---------------------+-----------------+ 454 | CSI | parameter bytes | intermediate bytes | final byte | | | 455 0x30 - 0x3f | 0x20 - 0x2f | 0x40 - 0x7e | | ^[[ | 0123456789:;<=>? 456 | SPC !"#$%&'()*+,-./ | azAZ@[\]^_`{|}~ | 457 +-----+------------------+---------------------+-----------------+ */ 458 param = 2; 459 460 /* vttest use to interleave normal characters (\014 CR or \010 BS) 461 into CSI sequences, either directly after ESC[ or after param. 462 Can't find anything related to this in any documentation nor XTerm 463 sources, thought. */ 464 465 for (junk = param; i + junk < size; junk++) 466 if (buffer[i + junk] < 0x20) 467 { 468 handle_single_char(buffer[i + junk], &x, &y, screen_list, sc); 469 } 470 else 471 { 472 break; 473 } 474 475 /* Intermediate offset */ 476 for (inter = junk; i + inter < size; inter++) 477 if (buffer[i + inter] < 0x30 || buffer[i + inter] > 0x3f) 478 { 479 break; 480 } 481 /* Interleaved character */ 482 for (junk = inter; i + junk < size; junk++) 483 if (buffer[i + junk] < 0x20) 484 { 485 handle_single_char(buffer[i + junk], &x, &y, screen_list, sc); 486 } 487 else 488 { 489 break; 490 } 491 492 /* Final Byte offset */ 493 for (final = junk; i + final < size; final++) 494 if (buffer[i + final] < 0x20 || buffer[i + final] > 0x2f) 495 { 496 break; 497 } 498 if (i + final >= size 499 || buffer[i + final] < 0x40 || buffer[i + final] > 0x7e) 500 { 501 debug("ansi Invalid Final Byte (%d %c)\n", buffer[i + final], 502 buffer[i + final]); 503 break; /* Invalid Final Byte */ 504 } 505 506 skip += final; 507 508 /* Sanity checks */ 509 if (param < inter && buffer[i + param] >= 0x3c) 510 { 511 /* Private sequence, only parse what we know */ 512 debug("ansi import: private sequence \"^[[%.*s\"", 513 final - param + 1, buffer + i + param); 514 continue; /* Private sequence, skip it entirely */ 515 } 516 517 if (final - param > 100) 518 continue; /* Suspiciously long sequence, skip it */ 519 520 /* Parse parameter bytes as per ECMA-48 5.4.2: Parameter string format 257 521 */ 258 else if (buffer[i] == '\033' && buffer[i + 1] == 'o') 259 { 260 sc->conv_state.glr[0] = 3; 261 skip += 1; 262 } 263 264 /* RESET TO INITIAL STATE (RIS), ECMA-48 (1986), ISO 6429 : 1988 */ 265 else if (buffer[i] == '\033' && buffer[i + 1] == 'c') 266 { 267 sc->dfg = CACA_DEFAULT; 268 sc->dbg = CACA_DEFAULT; 269 270 caca_set_color_ansi(sc->cv, sc->dfg, sc->dbg); 271 sc->clearattr = caca_get_attr(sc->cv, -1, -1); 272 ansi_parse_grcm(sc, 1, &dummy); 273 274 reset_conv_state(sc); 275 skip += 1; 276 } 277 278 /* Coding Method Delimiter (CMD), ECMA-48 (1991), ISO/IEC 6429:1992 279 (ISO IR 189) */ 280 else if (buffer[i] == '\033' && buffer[i + 1] == 'd') 281 { 282 reset_conv_state(sc); 283 skip += 1; 284 } 285 286 /* GZDM4, G0-Designators, multi, 94^n chars [grandfathered short form 287 from ISO 2022:1986] */ 288 else if (buffer[i] == '\033' && buffer[i + 1] == '$' 289 && (buffer[i + 2] >= '@') && (buffer[i + 2] <= 'C')) 290 { 291 sc->conv_state.gn[0] = LITERAL2CHAR('$', buffer[i + 2]); 292 skip += 2; 293 } 294 295 /* GnDMx Gn-Designators, 9x^n chars; need one more char to distinguish 296 these */ 297 else if (buffer[i] == '\033' && buffer[i + 1] == '$' 298 && (i + 3 >= size)) 299 break; 300 301 /* GZD4 G0-Designator, 94 chars */ 302 else if (buffer[i] == '\033' && buffer[i + 1] == '(') 303 { 304 sc->conv_state.gn[0] = buffer[i + 2]; 305 skip += 2; 306 } 307 308 /* G1D4 G1-Designator, 94 chars */ 309 else if (buffer[i] == '\033' && buffer[i + 1] == ')') 310 { 311 sc->conv_state.gn[1] = buffer[i + 2]; 312 skip += 2; 313 } 314 315 /* G2D4 G2-Designator, 94 chars */ 316 else if (buffer[i] == '\033' && buffer[i + 1] == '*') 317 { 318 sc->conv_state.gn[2] = buffer[i + 2]; 319 skip += 2; 320 } 321 322 /* G3D4 G3-Designator, 94 chars */ 323 else if (buffer[i] == '\033' && buffer[i + 1] == '+') 324 { 325 sc->conv_state.gn[3] = buffer[i + 2]; 326 skip += 2; 327 } 328 329 /* G2D6 G2-Designator, 96 chars */ 330 else if (buffer[i] == '\033' && buffer[i + 1] == '.') 331 { 332 sc->conv_state.gn[2] = LITERAL2CHAR('.', buffer[i + 2]); 333 skip += 2; 334 } 335 336 /* G3D6 G3-Designator, 96 chars */ 337 else if (buffer[i] == '\033' && buffer[i + 1] == '/') 338 { 339 sc->conv_state.gn[3] = LITERAL2CHAR('.', buffer[i + 2]); 340 skip += 2; 341 } 342 343 /* GZDM4 G0-Designator, 94^n chars */ 344 else if (buffer[i] == '\033' && buffer[i + 1] == '$' 345 && buffer[i + 2] == '(') 346 { 347 sc->conv_state.gn[0] = LITERAL2CHAR('$', buffer[i + 3]); 348 skip += 3; 349 } 350 351 /* G1DM4 G1-Designator, 94^n chars */ 352 else if (buffer[i] == '\033' && buffer[i + 1] == '$' 353 && buffer[i + 2] == ')') 354 { 355 sc->conv_state.gn[1] = LITERAL2CHAR('$', buffer[i + 3]); 356 skip += 3; 357 } 358 359 /* G2DM4 G2-Designator, 94^n chars */ 360 else if (buffer[i] == '\033' && buffer[i + 1] == '$' 361 && buffer[i + 2] == '*') 362 { 363 sc->conv_state.gn[2] = LITERAL2CHAR('$', buffer[i + 3]); 364 skip += 3; 365 } 366 367 /* G3DM4 G3-Designator, 94^n chars */ 368 else if (buffer[i] == '\033' && buffer[i + 1] == '$' 369 && buffer[i + 2] == '+') 370 { 371 sc->conv_state.gn[3] = LITERAL2CHAR('$', buffer[i + 3]); 372 skip += 3; 373 } 374 375 /* G2DM6 G2-Designator, 96^n chars */ 376 else if (buffer[i] == '\033' && buffer[i + 1] == '$' 377 && buffer[i + 2] == '.') 378 { 379 sc->conv_state.gn[2] = LITERAL3CHAR('$', '.', buffer[i + 3]); 380 skip += 3; 381 } 382 383 /* G3DM6 G3-Designator, 96^n chars */ 384 else if (buffer[i] == '\033' && buffer[i + 1] == '$' 385 && buffer[i + 2] == '/') 386 { 387 sc->conv_state.gn[3] = LITERAL3CHAR('$', '.', buffer[i + 3]); 388 skip += 3; 389 } 390 else if (buffer[i] == '\033' && buffer[i + 1] == '#') 391 { 392 debug("ansi private '#' sequence\n"); 393 394 switch (buffer[i + 2]) 395 { 396 case '8': /* DECALN Fills the entire screen area with 397 uppercase Es for screen focus and 398 alignment. */ 399 for (j = 0; j < height; j++) 522 if (param < inter) 523 { 524 argv[0] = 0; 525 for (j = param; j < inter; j++) 526 { 527 if (buffer[i + j] == ';') 528 argv[++argc] = 0; 529 else if (buffer[i + j] >= '0' && buffer[i + j] <= '9') 530 argv[argc] = 10 * argv[argc] + (buffer[i + j] - '0'); 531 } 532 argc++; 533 } 534 535 /* Interpret final byte. The code representations are given in ECMA-48 536 5.4: Control sequences, and the code definitions are given in 537 ECMA-48 8.3: Definition of control functions. */ 538 debug("ansi import: command '%c'", buffer[i + final]); 539 switch (buffer[i + final]) 540 { 541 case 'A': /* CUU (0x41) - Cursor Up */ 542 y -= argc ? argv[0] : 1; 543 if (y < 0) 544 y = 0; 545 break; 546 case 'B': /* CUD (0x42) - Cursor Down */ 547 y += argc ? argv[0] : 1; 548 break; 549 case 'C': /* CUF (0x43) - Cursor Right */ 550 debug("ansi : CUF %d \n", argc ? argv[0] : 1); 551 x += argc ? argv[0] : 1; 552 break; 553 case 'D': /* CUB (0x44) - Cursor Left */ 554 x -= argc ? argv[0] : 1; 555 if (x < 0) 556 x = 0; 557 break; 558 case 'G': /* CHA (0x47) - Cursor Character Absolute */ 559 x = (argc && argv[0] > 0) ? argv[0] - 1 : 0; 560 break; 561 case 'H': /* CUP (0x48) - Cursor Position */ 562 x = (argc > 1 && argv[1] > 0) ? argv[1] - 1 : 0; 563 y = (argc > 0 && argv[0] > 0) ? argv[0] - 1 : 0; 564 debug("ansi CUP : Cursor at %dx%d\n", x, y); 565 break; 566 case 'J': /* ED (0x4a) - Erase In Page */ 567 savedattr = caca_get_attr(sc->cv, -1, -1); 568 caca_set_attr(sc->cv, sc->clearattr); 569 if (!argc || argv[0] == 0) 570 { 571 caca_draw_line(sc->cv, x, y, width, y, ' '); 572 caca_fill_box(sc->cv, 0, y + 1, width, height - 1, ' '); 573 } 574 else if (argv[0] == 1) 575 { 576 caca_fill_box(sc->cv, 0, 0, width, y, ' '); 577 caca_draw_line(sc->cv, 0, y, x, y, ' '); 578 } 579 else if (argv[0] == 2) 580 { 581 // x = y = 0; 582 caca_fill_box(sc->cv, 0, 0, width, height, ' '); 583 } 584 caca_set_attr(sc->cv, savedattr); 585 break; 586 case 'K': /* EL (0x4b) - Erase In Line */ 587 debug("ansi EL : cursor at %dx%d\n", x, y); 588 if (!argc || argv[0] == 0) 589 { 590 caca_draw_line(sc->cv, x, y, width, y, ' '); 591 } 592 else if (argv[0] == 1) 593 { 594 caca_draw_line(sc->cv, 0, y, x, y, ' '); 595 } 596 else if (argv[0] == 2) 597 { 598 caca_draw_line(sc->cv, 0, y, width, y, ' '); 599 } 600 break; 601 case 'L': /* IL - Insert line */ 602 { 603 unsigned int nb_lines = argc ? argv[0] : 1; 604 for (j = bottom - 1; j >= (unsigned int)y + nb_lines; j--) 400 605 { 401 606 for (k = 0; k < width; k++) 402 607 { 403 caca_put_char(sc->cv, k, j, 'E'); 608 caca_put_char(sc->cv, k, j, 609 caca_get_char(sc->cv, k, j - nb_lines)); 610 caca_put_attr(sc->cv, k, j, 611 caca_get_attr(sc->cv, k, j - nb_lines)); 404 612 } 613 caca_draw_line(sc->cv, 0, j - nb_lines, width, 614 j - nb_lines, ' '); 405 615 } 406 skip += 2; 407 break; 408 409 default: 410 debug("Unknow private sequence 'ESC#%c'\n", buffer[i + 2]); 411 continue; 412 } 413 414 } 415 /* Interpret escape commands, as per Standard ECMA-48 "Control 416 Functions for Coded Character Sets", 5.4. Control sequences. */ 417 else if (buffer[i] == '\033' && buffer[i + 1] == '[') 418 { 419 unsigned int argc = 0, argv[101]; 420 unsigned int param, inter, final; 421 422 423 /* Compute offsets to parameter bytes, intermediate bytes and to 424 the final byte. Only the final byte is mandatory, there can be 425 zero of the others. 0 param=2 inter final final+1 426 +-----+------------------+---------------------+-----------------+ 427 | CSI | parameter bytes | intermediate bytes | final byte | | | 428 0x30 - 0x3f | 0x20 - 0x2f | 0x40 - 0x7e | | ^[[ | 0123456789:;<=>? 429 | SPC !"#$%&'()*+,-./ | azAZ@[\]^_`{|}~ | 430 +-----+------------------+---------------------+-----------------+ */ 431 param = 2; 432 433 for (inter = param; i + inter < size; inter++) 434 if (buffer[i + inter] < 0x30 || buffer[i + inter] > 0x3f) 435 break; 436 437 for (final = inter; i + final < size; final++) 438 if (buffer[i + final] < 0x20 || buffer[i + final] > 0x2f) 439 break; 440 441 if (i + final >= size 442 || buffer[i + final] < 0x40 || buffer[i + final] > 0x7e) 443 break; /* Invalid Final Byte */ 444 445 skip += final; 446 447 /* Sanity checks */ 448 if (param < inter && buffer[i + param] >= 0x3c) 449 { 450 /* Private sequence, only parse what we know */ 451 debug("ansi import: private sequence \"^[[%.*s\"", 452 final - param + 1, buffer + i + param); 453 continue; /* Private sequence, skip it entirely */ 454 } 455 456 if (final - param > 100) 457 continue; /* Suspiciously long sequence, skip it */ 458 459 /* Parse parameter bytes as per ECMA-48 5.4.2: Parameter string 460 format */ 461 if (param < inter) 462 { 463 argv[0] = 0; 464 for (j = param; j < inter; j++) 465 { 466 if (buffer[i + j] == ';') 467 argv[++argc] = 0; 468 else if (buffer[i + j] >= '0' && buffer[i + j] <= '9') 469 argv[argc] = 10 * argv[argc] + (buffer[i + j] - '0'); 470 } 471 argc++; 472 } 473 474 /* Interpret final byte. The code representations are given in 475 ECMA-48 5.4: Control sequences, and the code definitions are 476 given in ECMA-48 8.3: Definition of control functions. */ 477 debug("ansi import: command '%c'", buffer[i + final]); 478 switch (buffer[i + final]) 479 { 480 case 'A': /* CUU (0x41) - Cursor Up */ 481 y -= argc ? argv[0] : 1; 482 if (y < 0) 483 y = 0; 484 break; 485 case 'B': /* CUD (0x42) - Cursor Down */ 486 y += argc ? argv[0] : 1; 487 break; 488 case 'C': /* CUF (0x43) - Cursor Right */ 489 x += argc ? argv[0] : 1; 490 break; 491 case 'D': /* CUB (0x44) - Cursor Left */ 492 x -= argc ? argv[0] : 1; 493 if (x < 0) 494 x = 0; 495 break; 496 case 'G': /* CHA (0x47) - Cursor Character Absolute */ 497 x = (argc && argv[0] > 0) ? argv[0] - 1 : 0; 498 break; 499 case 'H': /* CUP (0x48) - Cursor Position */ 500 x = (argc > 1 && argv[1] > 0) ? argv[1] - 1 : 0; 501 y = (argc > 0 && argv[0] > 0) ? argv[0] - 1 : 0; 502 debug("ansi CUP : Cursor at %dx%d\n", x, y); 503 break; 504 case 'J': /* ED (0x4a) - Erase In Page */ 616 } 617 break; 618 case 'P': /* DCH (0x50) - Delete Character */ 619 if (!argc || argv[0] == 0) 620 argv[0] = 1; /* echo -ne 'foobar\r\e[0P\n' */ 621 /* Jylam : Start from x, not 0 */ 622 for (j = x; (unsigned int)(j + argv[0]) < width; j++) 623 { 624 caca_put_char(sc->cv, j, y, 625 caca_get_char(sc->cv, j + argv[0], y)); 626 caca_put_attr(sc->cv, j, y, 627 caca_get_attr(sc->cv, j + argv[0], y)); 628 } 629 break; /* Jylam: this one was missing I guess */ 630 #if 0 631 savedattr = caca_get_attr(sc->cv, -1, -1); 632 caca_set_attr(sc->cv, sc->clearattr); 633 for (; (unsigned int)j < width; j++) 634 caca_put_char(sc->cv, j, y, ' '); 635 caca_set_attr(sc->cv, savedattr); 636 #endif 637 case 'X': /* ECH (0x58) - Erase Character */ 638 if (argc && argv[0]) 639 { 505 640 savedattr = caca_get_attr(sc->cv, -1, -1); 506 641 caca_set_attr(sc->cv, sc->clearattr); 507 if (!argc || argv[0] == 0) 508 { 509 caca_draw_line(sc->cv, x, y, width, y, ' '); 510 caca_fill_box(sc->cv, 0, y + 1, width, height - 1, ' '); 511 } 512 else if (argv[0] == 1) 513 { 514 caca_fill_box(sc->cv, 0, 0, width, y, ' '); 515 caca_draw_line(sc->cv, 0, y, x, y, ' '); 516 } 517 else if (argv[0] == 2) 518 { 519 // x = y = 0; 520 caca_fill_box(sc->cv, 0, 0, width, height, ' '); 521 } 642 caca_draw_line(sc->cv, x, y, x + argv[0] - 1, y, ' '); 522 643 caca_set_attr(sc->cv, savedattr); 523 break; 524 case 'K': /* EL (0x4b) - Erase In Line */ 525 debug("ansi EL : cursor at %dx%d\n", x, y); 526 if (!argc || argv[0] == 0) 527 { 528 caca_draw_line(sc->cv, x, y, width, y, ' '); 529 } 530 else if (argv[0] == 1) 531 { 532 caca_draw_line(sc->cv, 0, y, x, y, ' '); 533 } 534 else if (argv[0] == 2) 535 { 536 caca_draw_line(sc->cv, 0, y, width, y, ' '); 537 } 538 break; 539 case 'L': /* IL - Insert line */ 540 { 541 unsigned int nb_lines = argc ? argv[0] : 1; 542 for (j = bottom - 1; j >= (unsigned int)y + nb_lines; j--) 543 { 544 for (k = 0; k < width; k++) 545 { 546 caca_put_char(sc->cv, k, j, 547 caca_get_char(sc->cv, k, 548 j - nb_lines)); 549 caca_put_attr(sc->cv, k, j, 550 caca_get_attr(sc->cv, k, 551 j - nb_lines)); 552 } 553 caca_draw_line(sc->cv, 0, j - nb_lines, width, 554 j - nb_lines, ' '); 555 } 556 } 557 break; 558 case 'P': /* DCH (0x50) - Delete Character */ 559 if (!argc || argv[0] == 0) 560 argv[0] = 1; /* echo -ne 'foobar\r\e[0P\n' */ 561 /* Jylam : Start from x, not 0 */ 562 for (j = x; (unsigned int)(j + argv[0]) < width; j++) 563 { 564 caca_put_char(sc->cv, j, y, 565 caca_get_char(sc->cv, j + argv[0], y)); 566 caca_put_attr(sc->cv, j, y, 567 caca_get_attr(sc->cv, j + argv[0], y)); 568 } 569 break; /* Jylam: this one was missing I guess */ 570 #if 0 571 savedattr = caca_get_attr(sc->cv, -1, -1); 572 caca_set_attr(sc->cv, sc->clearattr); 573 for (; (unsigned int)j < width; j++) 574 caca_put_char(sc->cv, j, y, ' '); 575 caca_set_attr(sc->cv, savedattr); 576 #endif 577 case 'X': /* ECH (0x58) - Erase Character */ 578 if (argc && argv[0]) 579 { 580 savedattr = caca_get_attr(sc->cv, -1, -1); 581 caca_set_attr(sc->cv, sc->clearattr); 582 caca_draw_line(sc->cv, x, y, x + argv[0] - 1, y, ' '); 583 caca_set_attr(sc->cv, savedattr); 584 } 585 case 'd': /* VPA (0x64) - Line Position Absolute */ 586 y = (argc && argv[0] > 0) ? argv[0] - 1 : 0; 587 break; 588 case 'f': /* HVP (0x66) - Character And Line Position */ 589 x = (argc > 1 && argv[1] > 0) ? argv[1] - 1 : 0; 590 y = (argc > 0 && argv[0] > 0) ? argv[0] - 1 : 0; 591 break; 592 case 'r': /* FIXME */ 593 if (argc == 2) /* DCSTBM - Set top and bottom margin */ 594 { 595 debug("DCSTBM %d %d", argv[0], argv[1]); 596 top = argv[0]; 597 bottom = argv[1]; 598 } 599 else 600 debug("ansi import: command r with %d params", argc); 601 break; 602 case 'h': /* SM (0x68) - FIXME */ 603 debug("ansi import: set mode %i", argc ? (int)argv[0] : -1); 604 break; 605 case 'l': /* RM (0x6c) - FIXME */ 606 debug("ansi import: reset mode %i", argc ? (int)argv[0] : -1); 607 break; 608 case 'm': /* SGR (0x6d) - Select Graphic Rendition */ 609 if (argc) 610 ansi_parse_grcm(sc, argc, argv); 611 else 612 ansi_parse_grcm(sc, 1, &dummy); 613 break; 614 case 's': /* Private (save cursor position) */ 615 save_x = x; 616 save_y = y; 617 break; 618 case 'u': /* Private (reload cursor position) */ 619 x = save_x; 620 y = save_y; 621 break; 622 default: 623 debug("ansi import: unknown command \"^[[%.*s\"", 624 final - param + 1, buffer + i + param); 625 break; 626 } 627 } 644 } 645 case 'd': /* VPA (0x64) - Line Position Absolute */ 646 y = (argc && argv[0] > 0) ? argv[0] - 1 : 0; 647 break; 648 case 'f': /* HVP (0x66) - Character And Line Position */ 649 x = (argc > 1 && argv[1] > 0) ? argv[1] - 1 : 0; 650 y = (argc > 0 && argv[0] > 0) ? argv[0] - 1 : 0; 651 break; 652 case 'r': /* FIXME */ 653 if (argc == 2) /* DCSTBM - Set top and bottom margin */ 654 { 655 debug("DCSTBM %d %d", argv[0], argv[1]); 656 top = argv[0]; 657 bottom = argv[1]; 658 } 659 else 660 debug("ansi import: command r with %d params", argc); 661 break; 662 case 'h': /* SM (0x68) - FIXME */ 663 debug("ansi import: set mode %i", argc ? (int)argv[0] : -1); 664 break; 665 case 'l': /* RM (0x6c) - FIXME */ 666 debug("ansi import: reset mode %i", argc ? (int)argv[0] : -1); 667 break; 668 case 'm': /* SGR (0x6d) - Select Graphic Rendition */ 669 if (argc) 670 ansi_parse_grcm(sc, argc, argv); 671 else 672 ansi_parse_grcm(sc, 1, &dummy); 673 break; 674 case 's': /* Private (save cursor position) */ 675 save_x = x; 676 save_y = y; 677 break; 678 case 'u': /* Private (reload cursor position) */ 679 x = save_x; 680 y = save_y; 681 break; 682 default: 683 debug("ansi import: unknown command \"^[[%.*s\"", 684 final - param + 1, buffer + i + param); 685 break; 686 } 687 } 628 688 629 689 /* Parse OSC stuff. */ 630 else if (buffer[i] == '\033' && buffer[i + 1] == ']') 631 { 632 char *string; 633 unsigned int command = 0; 634 unsigned int mode = 2, semicolon, final; 635 636 for (semicolon = mode; i + semicolon < size; semicolon++) 637 { 638 if (buffer[i + semicolon] < '0' || buffer[i + semicolon] > '9') 639 break; 640 command = 10 * command + (buffer[i + semicolon] - '0'); 641 } 642 643 if (i + semicolon >= size || buffer[i + semicolon] != ';') 644 break; /* Invalid Mode */ 645 646 for (final = semicolon + 1; i + final < size; final++) 647 if (buffer[i + final] < 0x20) 648 break; 649 650 if (i + final >= size || buffer[i + final] != '\a') 651 break; /* Not enough data or no bell found */ 652 /* FIXME: XTerm also reacts to <ESC><backslash> and <ST> */ 653 /* FIXME: differenciate between not enough data (try again) and 654 invalid data (print shit) */ 655 656 skip += final; 657 658 string = malloc(final - (semicolon + 1) + 1); 659 memcpy(string, buffer + i + (semicolon + 1), 660 final - (semicolon + 1)); 661 string[final - (semicolon + 1)] = '\0'; 662 debug("ansi import: got OSC command %i string '%s'", command, 663 string); 664 if (command == 0 || command == 2) 665 { 666 if (sc->title) 667 free(sc->title); 668 sc->title = string; 669 } 670 else 671 free(string); 672 } 690 else if (buffer[i] == '\033' && buffer[i + 1] == ']') 691 { 692 char *string; 693 unsigned int command = 0; 694 unsigned int mode = 2, semicolon, final; 695 696 for (semicolon = mode; i + semicolon < size; semicolon++) 697 { 698 if (buffer[i + semicolon] < '0' || buffer[i + semicolon] > '9') 699 break; 700 command = 10 * command + (buffer[i + semicolon] - '0'); 701 } 702 703 if (i + semicolon >= size || buffer[i + semicolon] != ';') 704 break; /* Invalid Mode */ 705 706 for (final = semicolon + 1; i + final < size; final++) 707 if (buffer[i + final] < 0x20) 708 break; 709 710 if (i + final >= size || buffer[i + final] != '\a') 711 break; /* Not enough data or no bell found */ 712 /* FIXME: XTerm also reacts to <ESC><backslash> and <ST> */ 713 /* FIXME: differenciate between not enough data (try again) and 714 invalid data (print shit) */ 715 716 skip += final; 717 718 string = malloc(final - (semicolon + 1) + 1); 719 memcpy(string, buffer + i + (semicolon + 1), final - (semicolon + 1)); 720 string[final - (semicolon + 1)] = '\0'; 721 debug("ansi import: got OSC command %i string '%s'", command, string); 722 if (command == 0 || command == 2) 723 { 724 if (sc->title) 725 free(sc->title); 726 sc->title = string; 727 } 728 else 729 free(string); 730 } 673 731 674 732 /* Get the character we’re going to paste */ 733 else 734 { 735 size_t bytes; 736 737 if (i + 6 < size) 738 { 739 ch = caca_utf8_to_utf32((char const *)(buffer + i), &bytes); 740 } 675 741 else 676 742 { 677 size_t bytes; 678 679 if (i + 6 < size) 680 { 681 ch = caca_utf8_to_utf32((char const *)(buffer + i), &bytes); 682 } 683 else 684 { 685 /* Add a trailing zero to what we're going to read */ 686 char tmp[7]; 687 memcpy(tmp, buffer + i, size - i); 688 tmp[size - i] = '\0'; 689 ch = caca_utf8_to_utf32(tmp, &bytes); 690 } 691 692 if (!bytes) 693 { 694 /* If the Unicode is invalid, assume it was latin1. */ 695 ch = buffer[i]; 696 bytes = 1; 697 } 698 699 /* very incomplete ISO-2022 implementation tailored to DEC ACS */ 700 if (sc->conv_state.cs == '@') 701 { 702 if (((ch > ' ') && (ch <= '~')) 703 && 704 (sc->conv_state. 705 gn[sc->conv_state.ss ? sc->conv_state. 706 gn[sc->conv_state.ss] : sc->conv_state.glr[0]] == '0')) 707 { 708 ch = dec_acs(ch); 709 } 710 else if (((ch > 0x80) && (ch < 0xff)) 711 && (sc->conv_state.gn[sc->conv_state.glr[1]] == '0')) 712 { 713 ch = dec_acs(ch + ' ' - 0x80); 714 } 715 } 716 sc->conv_state.ss = 0; /* no single-shift (GL) */ 717 718 wch = caca_utf32_is_fullwidth(ch) ? 2 : 1; 719 720 skip += bytes - 1; 721 } 722 723 /* Wrap long lines or grow horizontally */ 724 while ((unsigned int)x + wch > width) 725 { 726 x -= width; 727 y++; 728 } 729 730 /* Scroll or grow vertically */ 731 if ((unsigned int)y >= bottom) 732 { 733 int lines = (y - bottom) + 1; 734 735 savedattr = caca_get_attr(sc->cv, -1, -1); 736 737 for (j = top - 1; j + lines < bottom; j++) 738 { 739 for (k = 0; k < width; k++) 740 { 741 caca_put_char(sc->cv, k, j, 742 caca_get_char(sc->cv, k, j + lines)); 743 caca_put_attr(sc->cv, k, j, 744 caca_get_attr(sc->cv, k, j + lines)); 745 } 746 } 747 caca_set_attr(sc->cv, sc->clearattr); 748 caca_fill_box(sc->cv, 0, bottom - lines, width, bottom - 1, ' '); 749 y -= lines; 750 caca_set_attr(sc->cv, savedattr); 751 } 743 /* Add a trailing zero to what we're going to read */ 744 char tmp[7]; 745 memcpy(tmp, buffer + i, size - i); 746 tmp[size - i] = '\0'; 747 ch = caca_utf8_to_utf32(tmp, &bytes); 748 } 749 750 if (!bytes) 751 { 752 /* If the Unicode is invalid, assume it was latin1. */ 753 ch = buffer[i]; 754 bytes = 1; 755 } 756 757 /* very incomplete ISO-2022 implementation tailored to DEC ACS */ 758 if (sc->conv_state.cs == '@') 759 { 760 if (((ch > ' ') && (ch <= '~')) 761 && 762 (sc->conv_state. 763 gn[sc->conv_state.ss ? sc->conv_state. 764 gn[sc->conv_state.ss] : sc->conv_state.glr[0]] == '0')) 765 { 766 ch = dec_acs(ch); 767 } 768 else if (((ch > 0x80) && (ch < 0xff)) 769 && (sc->conv_state.gn[sc->conv_state.glr[1]] == '0')) 770 { 771 ch = dec_acs(ch + ' ' - 0x80); 772 } 773 } 774 sc->conv_state.ss = 0; /* no single-shift (GL) */ 775 776 wch = caca_utf32_is_fullwidth(ch) ? 2 : 1; 777 778 skip += bytes - 1; 779 } 780 781 /* Wrap long lines or grow horizontally */ 782 while ((unsigned int)x + wch > width) 783 { 784 x -= width; 785 y++; 786 } 787 788 /* Scroll or grow vertically */ 789 if ((unsigned int)y >= bottom) 790 { 791 int lines = (y - bottom) + 1; 792 793 savedattr = caca_get_attr(sc->cv, -1, -1); 794 795 for (j = top - 1; j + lines < bottom; j++) 796 { 797 for (k = 0; k < width; k++) 798 { 799 caca_put_char(sc->cv, k, j, 800 caca_get_char(sc->cv, k, j + lines)); 801 caca_put_attr(sc->cv, k, j, 802 caca_get_attr(sc->cv, k, j + lines)); 803 } 804 } 805 caca_set_attr(sc->cv, sc->clearattr); 806 caca_fill_box(sc->cv, 0, bottom - lines, width, bottom - 1, ' '); 807 y -= lines; 808 caca_set_attr(sc->cv, savedattr); 809 } 752 810 753 811 /* Now paste our character, if any */
Note: See TracChangeset
for help on using the changeset viewer.
