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