sim.c (20496B)
1 #include <stdio.h> 2 #include <stdarg.h> 3 #include <stdlib.h> 4 #include <string.h> 5 6 #include "sim.h" 7 8 #define MINSIZE 16 9 #define MAXEMPTY 256 10 #define FILECOUNT 8 11 #define LENGTH(a) (sizeof(a)/sizeof(a[0])) 12 13 typedef long Posn; 14 15 enum { 16 Up = 1, 17 Down, 18 Left, 19 Right, 20 HalfUp, 21 HalfDown, 22 Top, 23 Bottom, 24 Letter, 25 Word, 26 EndWord, 27 PrevWord, 28 Till, 29 Line, 30 StartLine, 31 EndLine, 32 Insert, 33 Delete, 34 Change, 35 Ctrl = -0x60, 36 Esc = 0x1b, 37 Del = 0x7f 38 }; 39 40 typedef struct { 41 Posn p0, p1; 42 } Address; 43 44 typedef struct { 45 char* s; 46 ulong n; /*number of filled characters*/ 47 ulong size; 48 } String; 49 50 typedef struct { 51 String is[2048]; 52 String ds[2048]; 53 uint c[2048]; 54 uint arg[2048]; 55 uint count[2048]; 56 Posn p0[2048]; 57 short n; 58 } Buffer; 59 60 typedef struct { 61 String* s; 62 String* name; 63 Address dot; 64 short i; /*buffer index*/ 65 uchar dirty; 66 } File; 67 68 typedef struct { 69 uchar key; 70 void (*func)(int); 71 int value; 72 } Key; 73 74 typedef struct { 75 Address* a; 76 ushort dot; 77 ushort n; 78 ushort size; 79 } Frame; 80 81 void die(char*, ...); 82 void* emalloc(ulong); 83 void* erealloc(void*, ulong); 84 static void blind_reader(Frame* fr, String* s, Posn p0); 85 static void blind_writer( 86 String* s, Frame* fr, 87 ushort line, ushort offset, ushort top, ushort bot 88 ); 89 static void buf_add( 90 Buffer* b, String* is, String* ds, 91 uint c, uint arg, uint count, Posn p0 92 ); 93 static void change(int arg); 94 static void count(int arg); 95 static void delete(int arg); 96 static void dot(int arg); 97 static void redo(int arg); 98 static void escape(int c); 99 static void init(); 100 static void input(String* s, ushort line, char* msg); 101 static void insert(int arg); 102 static int isword(uchar c); 103 static void file_close(int arg); 104 static void file_init(File* f); 105 static void file_load(File* f); 106 static void file_open(int c); 107 static void file_save(int arg); 108 static void fr_add(Frame* fr, Posn p0, Posn p1); 109 static void fr_close(Frame* fr); 110 static void fr_init(Frame* fr); 111 static void fr_insert(Frame* p, Frame* q, ushort n); 112 static void fr_insure(Frame* fr, ushort n); 113 static void fr_update(); 114 static void fr_zero(Frame*); 115 static void gmove(int arg); 116 static void paste(int arg); 117 static void pline(); 118 static void resize(); 119 static void search(int arg); 120 static int selection(int arg); 121 static void str_init(String* p); 122 static void str_close(String* p); 123 static void str_zero(String* p); 124 static void str_insure(String* p, ulong n); 125 static void str_addc(String* p, int c); 126 static void str_adds(String* p, char* s, ulong n); 127 static void str_delc(String* p); 128 static void str_insert(String* p, String* q, Posn p0); 129 static void str_delete(String* p, Posn p0, Posn p1); 130 static void undo(int arg); 131 static void move(int); 132 static void quit(int); 133 static void yank(int arg); 134 135 static Frame* fr, frame[FILECOUNT]; 136 static File* f, file[FILECOUNT]; 137 static Buffer* buf, buffer[FILECOUNT]; 138 static String istr, srch; 139 static Window w; 140 static uint counter; 141 142 #include "config.h" 143 144 void 145 die(char* fmt, ...) 146 { 147 uint i; 148 va_list ap; 149 150 win_end(); 151 va_start(ap, fmt); 152 vfprintf(stderr, fmt, ap); 153 va_end(ap); 154 if (fmt[0] && fmt[strlen(fmt) - 1] == ':') 155 perror(NULL); 156 else 157 fputc('\n', stderr); 158 for (i = 0; i < FILECOUNT; ++i) { 159 if (!file[i].s->n) 160 continue; 161 str_adds(file[i].name, ".swap", 5); 162 file_save(i); 163 fprintf(stderr, "file saved to %s\n", file[i].name->s); 164 } 165 *fmt = *(char*)NULL; 166 } 167 168 void* 169 emalloc(ulong n) 170 { 171 void* p; 172 173 p = malloc(n); 174 if (!p) 175 die("malloc:"); 176 memset(p, 0, n); 177 return p; 178 } 179 180 void* 181 erealloc(void* p, ulong n) 182 { 183 p = realloc(p, n); 184 if (!p) 185 die("realloc:"); 186 return p; 187 } 188 189 static void 190 blind_reader(Frame* fr, String* s, Posn p0) 191 { 192 Posn p1; 193 uint wx; 194 195 p1 = p0; 196 do { 197 for (wx = 0; wx < w.wx && p1 < s->n;) { 198 switch (s->s[p1]) { 199 case '\t': 200 wx += w.t - (wx % w.t); 201 break; 202 case '\n': 203 goto endloop; 204 default: 205 ++wx; 206 } 207 if (wx < w.wx) 208 ++p1; 209 if (wx >= w.wx) { 210 if (s->s[p1] == '\t') 211 ++p1; 212 if (s->s[p1 + 1] == '\n') 213 ++p1; 214 } 215 } 216 endloop: 217 fr_add(fr, p0, p1); 218 p0 = ++p1; 219 } while (p1 <= s->n && s->s[p1 - 1] != '\n'); 220 } 221 222 static void 223 blind_writer( 224 String* s, Frame* fr, 225 ushort line, ushort offset, ushort top, ushort bot 226 ) { 227 ushort i, o; 228 229 i = o = 0; 230 if (offset >= top) 231 i = offset - top + 1; 232 if (fr->n - offset > bot) 233 o = offset + bot - 1; 234 else if (fr->n) 235 o = fr->n - 1; 236 printf(CSI "%uH", offset > line ? 0 : line - offset); 237 fwrite(&s->s[fr->a[i].p0], fr->a[o].p1 - fr->a[i].p0, 1, stdout); 238 } 239 240 static void 241 buf_add( 242 Buffer* b, String* is, String* ds, 243 uint c, uint arg, uint count, Posn p0 244 ) { 245 b->n = ++f->i + 1; 246 str_zero(&b->is[f->i]); 247 str_zero(&b->ds[f->i]); 248 if (is != NULL) 249 str_insert(&b->is[f->i], is, 0); 250 if (ds != NULL) 251 str_insert(&b->ds[f->i], ds, 0); 252 b->c[f->i] = c; 253 b->arg[f->i] = arg; 254 b->count[f->i] = count; 255 b->p0[f->i] = p0; 256 f->dirty = '*'; 257 fr_zero(fr); 258 } 259 260 static void 261 change(int arg) 262 { 263 String s; 264 uint count; 265 266 if (!arg) 267 arg = fgetc(stdin); 268 switch (arg) { 269 case 'x': arg = Letter; break; 270 case 'c': arg = Line; break; 271 case 'G': arg = Bottom; break; 272 case 'g': arg = Top; break; 273 case 'w': arg = Word; break; 274 case 't': arg = Till; break; 275 } 276 count = counter; 277 arg = selection(arg); 278 if (arg == Word || arg == Letter || arg > 0x7f) 279 ++f->dot.p1; 280 str_init(&s); 281 if (f->dot.p0 != f->dot.p1) { 282 str_adds(&s, f->s->s + f->dot.p0, f->dot.p1 - f->dot.p0); 283 str_delete(f->s, f->dot.p0, f->dot.p1); 284 } 285 f->dot.p0 = f->dot.p1 = f->dot.p0; 286 fr_zero(fr); 287 insert(0); 288 if (s.n) 289 str_insert(&buf->ds[f->i], &s, 0); 290 str_close(&s); 291 buf->c[f->i] = Change; 292 buf->arg[f->i] = arg; 293 buf->count[f->i] = count; 294 fr_update(); 295 } 296 297 static void 298 count(int arg) 299 { 300 if (!counter && !arg) { 301 move(StartLine); 302 return; 303 } 304 counter *= 10; 305 counter += arg; 306 } 307 308 static void 309 delete(int arg) 310 { 311 String s; 312 uint count; 313 314 if (!f->s->n) 315 return; 316 if (!arg) { 317 switch (arg = fgetc(stdin)) { 318 case 'x': arg = Letter; break; 319 case 'd': arg = Line; break; 320 case 'G': arg = Bottom; break; 321 case 'g': arg = Top; break; 322 case 'w': arg = Word; break; 323 case 't': arg = Till; break; 324 default: 325 return; 326 } 327 } 328 count = counter; 329 if ((arg = selection(arg)) < 0) 330 return; 331 str_init(&s); 332 str_zero(&istr); 333 str_adds(&s, f->s->s + f->dot.p0, f->dot.p1 + 1 - f->dot.p0); 334 str_adds(&istr, f->s->s + f->dot.p0, f->dot.p1 + 1 - f->dot.p0); 335 buf_add(buf, NULL, &s, Delete, arg, count, f->dot.p0); 336 str_delete(f->s, f->dot.p0, f->dot.p1 + 1); 337 str_close(&s); 338 if (f->dot.p0 == f->s->n && f->dot.p0) 339 --f->dot.p0; 340 f->dot.p1 = f->dot.p0; 341 fr_update(); 342 } 343 344 static void 345 dot(int arg) 346 { 347 String ds; 348 349 if (f->i < 0) 350 f->i = 0; 351 arg = buf->arg[f->i]; 352 counter = buf->count[f->i]; 353 switch (buf->c[f->i]) { 354 case Insert: 355 if (arg == Down) 356 move(EndLine); 357 else 358 move(arg); 359 str_insert(f->s, &istr, f->dot.p0); 360 buf_add(buf, &istr, NULL, Insert, arg, counter, f->dot.p0); 361 break; 362 case Delete: 363 delete(arg); 364 break; 365 case Change: 366 str_init(&ds); 367 if (buf->ds[f->i].n) { 368 selection(arg); 369 if (arg == Word || arg == Letter || arg > 0x7f) 370 ++f->dot.p1; 371 str_adds( 372 &ds, f->s->s + f->dot.p0, f->dot.p1 - f->dot.p0 373 ); 374 str_delete(f->s, f->dot.p0, f->dot.p1); 375 } 376 if (buf->is[f->i].n) 377 str_insert(f->s, &buf->is[f->i], f->dot.p0); 378 buf_add( 379 buf, &buf->is[f->i], &ds, Change, arg, 380 buf->count[f->i], f->dot.p0 381 ); 382 str_close(&ds); 383 f->dot.p1 = f->dot.p0; 384 break; 385 } 386 fr_update(); 387 } 388 389 static void 390 redo(int arg) 391 { 392 if (f->i == buf->n - 1) 393 return; 394 if (buf->ds[++f->i].n) 395 str_delete( 396 f->s, buf->p0[f->i], buf->p0[f->i] + buf->ds[f->i].n 397 ); 398 if (buf->is[f->i].n) 399 str_insert(f->s, &buf->is[f->i], buf->p0[f->i]); 400 f->dot.p0 = f->dot.p1 = buf->p0[f->i]; 401 f->dirty = '*'; 402 fr_zero(fr); 403 fr_update(); 404 } 405 406 static void 407 escape(int c) 408 { 409 counter = 0; 410 c = fgetc(stdin) - 0x30; 411 if (c > 0 && c <= 8) { 412 --c; 413 f = &file[c]; 414 fr = &frame[c]; 415 buf = &buffer[c]; 416 return; 417 } 418 ungetc(c + 0x30, stdin); 419 } 420 421 static void 422 input(String* s, ushort line, char* msg) 423 { 424 uchar c; 425 426 for (;;) { 427 printf(CSI "%uH" EL "%s%s", line, msg, s->s); 428 switch (c = fgetc(stdin)) { 429 case Esc: 430 str_zero(s); 431 case '\n': 432 return; 433 case Del: 434 str_delc(s); 435 break; 436 default: 437 str_addc(s, c); 438 } 439 } 440 } 441 442 static int 443 isword(uchar c) 444 { 445 switch (c) { 446 case ' ': case '\t': case '\n': case '.': 447 case '(': case ')': case '{': case '}': 448 case '[': case ']': case ':': case ';': 449 case ',': case '<': case '>': case '#': 450 case '*': case '+': case '-': case '!': 451 case '%': case '\\': case '/': case '"': 452 case '=': 453 return 0; 454 } 455 return 1; 456 } 457 458 static void 459 insert(int arg) 460 { 461 String s, c; 462 463 if (f->s->s[f->s->n - 1] != '\n') 464 str_addc(f->s, '\n'); 465 str_init(&s), str_init(&c); 466 str_addc(&c, '\0'); 467 switch (arg) { 468 case StartLine: 469 case EndLine: 470 case Right: 471 move(arg); 472 break; 473 case Down: 474 move(EndLine); 475 str_addc(&s, '\n'); 476 str_insert(f->s, &s, f->dot.p0); 477 ++f->dot.p1; 478 break; 479 } 480 for (;;) { 481 resize(); 482 fr_update(); 483 switch (c.s[0] = fgetc(stdin)) { 484 case Esc: 485 goto endmode; 486 case Del: 487 if (f->dot.p1 != f->dot.p0) { 488 str_delc(&s); 489 str_delete(f->s, f->dot.p1 - 1, f->dot.p1); 490 --f->dot.p1; 491 } 492 break; 493 default: 494 str_addc(&s, c.s[0]); 495 str_insert(f->s, &c, f->dot.p1); 496 } 497 f->dot.p1 = f->dot.p0 + s.n; 498 } 499 endmode: 500 str_zero(&istr); 501 str_insert(&istr, &s, 0); 502 for (counter ? --counter : 0; counter; --counter) { 503 str_insert(&istr, &s, istr.n); 504 str_insert(f->s, &s, f->dot.p0); 505 } 506 buf_add(buf, &istr, NULL, Insert, arg, counter, f->dot.p0); 507 str_close(&s), str_close(&c); 508 f->dot.p0 = f->dot.p1; 509 if (f->dot.p1 >= f->s->n) 510 move(Left); 511 } 512 513 static void 514 init() 515 { 516 uint i; 517 518 win_init(&w); 519 for (i = 0; i < FILECOUNT; ++i) { 520 file_init(&file[i]); 521 fr_init(&frame[i]); 522 } 523 f = &file[0]; 524 fr = &frame[0]; 525 buf = &buffer[0]; 526 str_init(&srch); 527 str_init(&istr); 528 } 529 530 static void 531 file_close(int arg) 532 { 533 if (arg == -1) 534 arg = f - file; 535 if (file[arg].dirty) { 536 printf( 537 CSI "%uH" EL CSI "31mSave %s?" CSI "0m [y/n]", w.wy/2, 538 file[arg].name->n ? file[arg].name->s : "-unnamed-" 539 ); 540 if (fgetc(stdin) == 'y') 541 file_save(arg); 542 } 543 str_zero(f->s); 544 str_zero(f->name); 545 f->dot.p0 = f->dot.p1 = 0; 546 } 547 548 static void 549 file_init(File* f) 550 { 551 f->s = emalloc(sizeof(String)); 552 f->name = emalloc(sizeof(String)); 553 str_init(f->s); 554 str_init(f->name); 555 f->dirty = f->dot.p0 = f->dot.p1 = 0; 556 f->i = -1; 557 } 558 559 static void 560 file_load(File* f) 561 { 562 FILE* disk; 563 564 if (!(disk = fopen(f->name->s, "r"))) 565 return; 566 fseek(disk, 0, SEEK_END); 567 if ((f->s->n = ftell(disk))) { 568 str_insure(f->s, f->s->n); 569 rewind(disk); 570 fread(f->s->s, f->s->n, 1, disk); 571 } 572 fclose(disk); 573 f->dot.p0 = f->dot.p1 = 0; 574 f->i = -1; 575 fr_zero(fr); 576 } 577 578 static void 579 file_open(int c) 580 { 581 if (f->dirty) { 582 printf( 583 CSI "%uH" EL CSI "31mSave %s?" CSI "0m [y/n]", w.wy/2, 584 f->name->s 585 ); 586 if (fgetc(stdin) == 'y') 587 file_save(f - file); 588 } 589 input(f->name, w.wy/2, CSI "32m$ " CSI "m"); 590 file_load(f); 591 } 592 593 static void 594 file_save(int arg) 595 { 596 FILE* disk; 597 598 if (arg == -1) 599 arg = f - file; 600 if (!file[arg].name->n) { 601 input(file[arg].name, w.wy/2, "File name: "); 602 if (!file[arg].name->n) 603 return; 604 } 605 disk = fopen(file[arg].name->s, "w"); 606 fwrite(file[arg].s->s, file[arg].s->n, 1, disk); 607 fclose(disk); 608 file[arg].dirty = 0; 609 } 610 611 static void 612 fr_add(Frame* fr, Posn p0, Posn p1) 613 { 614 fr_insure(fr, fr->n + 1); 615 fr->a[fr->n].p0 = p0; 616 fr->a[fr->n].p1 = p1; 617 ++fr->n; 618 } 619 620 static void 621 fr_calc(Frame* fr) 622 { 623 Frame fr0; 624 Posn p0, p1; 625 ushort half; 626 627 half = w.wy >> 1; 628 if (!fr->n 629 || f->dot.p1 != f->dot.p0 630 || f->dot.p1 < fr->a[0].p0 631 || f->dot.p1 > fr->a[fr->n ? fr->n - 1 : 0].p1 632 || (fr->dot < half && fr->a[0].p0) 633 || (fr->dot + half + 1 > fr->n 634 && fr->a[fr->n ? fr->n - 1 : 0].p1 + 1 < f->s->n 635 ) 636 ) { 637 fr_zero(fr); 638 for (p0 = f->dot.p1; p0; --p0) 639 if (f->s->s[p0 - 1] == '\n') 640 break; 641 p1 = p0; 642 if (p1) { 643 fr_init(&fr0); 644 for (--p1; p1 && fr->n < w.wy;) { 645 for (;p1 && f->s->s[p1 - 1] != '\n'; --p1); 646 blind_reader(&fr0, f->s, p1); 647 p1 = fr0.a[0].p0; 648 if (p1) 649 --p1; 650 fr_insert(fr, &fr0, 0); 651 fr_zero(&fr0); 652 } 653 fr_close(&fr0); 654 } 655 for (p1 = p0; p1 < f->s->n && fr->n < w.wy * 3;) { 656 blind_reader(fr, f->s, p1); 657 p1 = fr->a[fr->n - 1].p1 + 1; 658 } 659 } 660 for (;f->dot.p1 < fr->a[fr->dot].p0 && fr->dot; --fr->dot); 661 for (;f->dot.p1 > fr->a[fr->dot].p1; ++fr->dot); 662 } 663 664 static void 665 fr_close(Frame* fr) 666 { 667 free(fr->a); 668 } 669 670 static void 671 fr_init(Frame* fr) 672 { 673 fr->a = emalloc(32 * sizeof(*fr->a)); 674 fr->dot = 0; 675 fr->n = 0; 676 fr->size = 32; 677 } 678 679 static void 680 fr_insert(Frame* p, Frame* q, ushort n) 681 { 682 fr_insure(p, p->n + q->n); 683 memmove(p->a + n + q->n, p->a + n, (p->n - n) * sizeof(*p->a)); 684 memmove(p->a + n, q->a, q->n * sizeof(*p->a)); 685 p->n += q->n; 686 } 687 688 static void 689 fr_insure(Frame* fr, ushort n) 690 { 691 if (n > fr->size) { 692 fr->size += n + 32; 693 fr->a = erealloc(fr->a, fr->size * sizeof(*fr->a)); 694 } 695 } 696 697 static void 698 fr_update() 699 { 700 Posn p0, p1; 701 uint half; 702 703 half = w.wy >> 1; 704 if (!f->s->n) { 705 fr->a[0].p0 = fr->a[0].p1 = 0; 706 printf(ED); 707 goto status; 708 } 709 fr_calc(fr); 710 fwrite(ED, sizeof(ED), 1, stdout); 711 blind_writer(f->s, fr, half, fr->dot, half, half + (w.wy % 2)); 712 status: 713 printf(CSI "%uH", w.wy); 714 printf(STATUS); 715 for (p0 = fr->a[fr->dot].p0, p1 = 1; p0 < f->dot.p1; ++p0) { 716 if (f->s->s[p0] == '\t' && p1 % w.t) 717 p1 += (w.t + 1) - (p1 % w.t); 718 else 719 ++p1; 720 } 721 printf(CSI "%u;%luH", half, p1); 722 return; 723 } 724 725 static void 726 fr_zero(Frame* fr) 727 { 728 fr->n = 0; 729 fr->dot = 0; 730 } 731 732 static void 733 move(int arg) 734 { 735 switch (arg) { 736 case Left: 737 if (f->dot.p1) 738 --f->dot.p1; 739 break; 740 case Right: 741 if (f->dot.p1 + 1 < f->s->n) 742 ++f->dot.p1; 743 break; 744 case Up: 745 if (fr->dot) 746 f->dot.p1 = fr->a[fr->dot - 1].p0; 747 else 748 f->dot.p1 = 0; 749 break; 750 case Down: 751 if (!f->s->n) 752 return; 753 if (fr->dot < fr->n - 1) 754 f->dot.p1 = fr->a[fr->dot + 1].p0; 755 else 756 f->dot.p1 = fr->a[fr->dot].p1 - 1; 757 break; 758 case HalfUp: 759 if (fr->dot < w.wy/2) 760 f->dot.p1 = 0; 761 else 762 f->dot.p1 = fr->a[fr->dot - w.wy/2].p0; 763 break; 764 case HalfDown: 765 if (!f->s->n) 766 break; 767 if (fr->n - fr->dot <= w.wy/2) { 768 if (fr->a[fr->n - 1].p1 <= f->s->n) 769 f->dot.p1 = fr->a[fr->n - 1].p0; 770 else 771 f->dot.p1 = f->s->n; 772 } else 773 f->dot.p1 = fr->a[fr->dot + w.wy/2].p0; 774 break; 775 case Top: 776 f->dot.p1 = 0; 777 break; 778 case Bottom: 779 if (f->s->n) 780 f->dot.p1 = f->s->n - 1; 781 break; 782 case StartLine: 783 if (fr->dot) 784 for (;fr->dot > 1 785 && f->s->s[fr->a[fr->dot].p0 - 1] != '\n' 786 ; --fr->dot 787 ); 788 f->dot.p1 = fr->a[fr->dot].p0; 789 break; 790 case EndLine: 791 for (;f->dot.p1 + 1 < f->s->n && f->s->s[f->dot.p1] != '\n' 792 ; ++f->dot.p1 793 ); 794 break; 795 case Word: 796 for (;f->dot.p1 + 1 < f->s->n && isword(f->s->s[f->dot.p1]) 797 ; ++f->dot.p1 798 ); 799 for (;f->dot.p1 + 1 < f->s->n && !isword(f->s->s[f->dot.p1]) 800 ; ++f->dot.p1 801 ); 802 break; 803 case EndWord: 804 move(Right); 805 for (;f->dot.p1 < f->s->n && !isword(f->s->s[f->dot.p1]) 806 ; ++f->dot.p1 807 ); 808 for (;f->dot.p1 < f->s->n && isword(f->s->s[f->dot.p1]) 809 ; ++f->dot.p1 810 ); 811 move(Left); 812 break; 813 case PrevWord: 814 move(Left); 815 for (;f->dot.p1 > 0 && !isword(f->s->s[f->dot.p1]) 816 ; --f->dot.p1 817 ); 818 for (;f->dot.p1 > 0 && isword(f->s->s[f->dot.p1]) 819 ; --f->dot.p1 820 ); 821 if (f->dot.p1) 822 move(Right); 823 break; 824 }; 825 f->dot.p0 = f->dot.p1; 826 fr_calc(fr); 827 } 828 829 static void 830 quit(int arg) 831 { 832 uint i; 833 834 for (i = 0; i < FILECOUNT; ++i) 835 file_close(i); 836 win_end(); 837 exit(arg); 838 } 839 840 static void 841 gmove(int arg) 842 { 843 if (arg == Top) { 844 move(Top); 845 for (counter ? --counter : 0; counter; --counter) { 846 move(EndLine); 847 move(Right); 848 } 849 return; 850 } 851 for (!counter ? ++counter : 0; counter; --counter) 852 move(arg); 853 } 854 855 static void 856 paste(int arg) 857 { 858 str_insert(f->s, &istr, f->dot.p0); 859 buf_add(buf, &istr, NULL, Insert, 0, 1, f->dot.p0); 860 } 861 862 static void 863 pline() 864 { 865 ulong i, j, c, l; 866 867 for (l = f->dot.p1 = 0; f->dot.p1 < f->dot.p0; ++l) { 868 for (;f->dot.p1 + 1 < f->s->n && f->s->s[f->dot.p1] != '\n'; 869 ++f->dot.p1 870 ); 871 if (f->dot.p1 + 1 < f->s->n) 872 ++f->dot.p1; 873 } 874 ++l; 875 j = 1; 876 if (!counter) 877 counter = 1; 878 for (;;) { 879 for (i = 0; i < j * counter && i < w.wy/2 ; ++i) 880 printf(CSI "%luH" EL "%lu", w.wy/2 + i, i ? i : l); 881 switch (c = fgetc(stdin)) { 882 case '!': 883 ++j; 884 break; 885 case '+': 886 ++counter; 887 break; 888 case '-': 889 if (counter > 1) 890 --counter; 891 default: 892 counter = 0; 893 return; 894 } 895 } 896 } 897 898 static void 899 resize() 900 { 901 Window wt; 902 903 win_query(&wt); 904 if (wt.wx != w.wx || wt.wy != w.wy) { 905 w.wx = wt.wx; 906 w.wy = wt.wy; 907 fr_zero(fr); 908 } 909 } 910 911 static void 912 search(int arg) 913 { 914 Posn pos; 915 char* p; 916 917 f->s->s[f->s->n] = 0; 918 if (arg == '/' || arg == '?') { 919 str_zero(&srch); 920 input(&srch, w.wy, "/"); 921 for (pos = 0; pos < srch.n; ++pos) 922 if (srch.s[pos] == '^') 923 srch.s[pos] = '\n'; 924 } 925 if (arg == '/' || arg == 'n') { 926 move(Right); 927 p = strstr(f->s->s + f->dot.p0, srch.s); 928 if (p == NULL) { 929 move(Left); 930 return; 931 } 932 } else { 933 pos = f->dot.p1; 934 if (srch.s[0] == '\n' && srch.s[1] != '\n') 935 move(Left); 936 for (;;) { 937 for (;move(Left), f->dot.p1 938 && f->s->s[f->dot.p1] != srch.s[0] 939 ; 940 ); 941 if (!strncmp(f->s->s + f->dot.p1, srch.s, srch.n)) 942 break; 943 if (!f->dot.p1) { 944 f->dot.p0 = f->dot.p1 = pos; 945 return; 946 } 947 } 948 p = f->s->s + f->dot.p1; 949 } 950 f->dot.p0 = f->dot.p1 = p - f->s->s; 951 if (srch.s[0] == '\n' && srch.s[1] != '\n') 952 move(Right); 953 fr_update(); 954 } 955 956 static int 957 selection(int arg) 958 { 959 Posn p0; 960 961 if (!counter) 962 ++counter; 963 if (arg > 0x7f) { 964 arg -= 0x7f; 965 goto till; 966 } 967 p0 = f->dot.p1 = f->dot.p0; 968 switch (arg) { 969 case Letter: 970 p0 = f->dot.p0; 971 for (;counter > 1; --counter) 972 move(Right); 973 break; 974 case Line: 975 move(StartLine); 976 p0 = f->dot.p0; 977 for (;counter; --counter) { 978 move(EndLine); 979 move(Right); 980 } 981 if (f->dot.p1 + 1 < f->s->n) 982 move(Left); 983 break; 984 case Bottom: 985 move(StartLine); 986 move(Left); 987 p0 = f->dot.p0; 988 move(Bottom); 989 break; 990 case Top: 991 p0 = 0; 992 move(EndLine); 993 break; 994 case Word: 995 p0 = f->dot.p0; 996 for (;counter; --counter) 997 move(EndWord); 998 break; 999 case Till: 1000 arg = fgetc(stdin); 1001 if (arg == Esc) 1002 return 0; 1003 till: 1004 p0 = f->dot.p0; 1005 for (;counter && f->dot.p1 + 1 < f->s->n; --counter) 1006 for (++f->dot.p1 1007 ; f->dot.p1 + 1 < f->s->n 1008 && f->s->s[f->dot.p1 + 1] != arg 1009 ; ++f->dot.p1 1010 ); 1011 if (f->s->s[f->dot.p1 + 1] != arg) { 1012 f->dot.p1 = f->dot.p0; 1013 return -1; 1014 } 1015 arg += 0x7f; 1016 break; 1017 } 1018 f->dot.p0 = p0; 1019 counter = 0; 1020 return arg; 1021 } 1022 1023 static void 1024 str_init(String* p) 1025 { 1026 p->s = emalloc(MINSIZE * sizeof(*p->s)); 1027 p->n = 0; 1028 p->size = MINSIZE; 1029 } 1030 1031 static void 1032 str_close(String* p) 1033 { 1034 free(p->s); 1035 } 1036 1037 static void 1038 str_zero(String* p) 1039 { 1040 if (p->size > MAXEMPTY) { 1041 p->s = erealloc(p->s, MAXEMPTY * sizeof(*p->s)); 1042 p->size = MAXEMPTY; 1043 } 1044 p->n = 0; 1045 memset(p->s, 0, p->size); 1046 } 1047 1048 static void 1049 str_insure(String* p, ulong n) 1050 { 1051 if (p->size < n) { 1052 p->size = n + MAXEMPTY; 1053 p->s = erealloc(p->s, p->size * sizeof(*p->s)); 1054 } 1055 } 1056 1057 static void 1058 str_addc(String* p, int c) 1059 { 1060 str_insure(p, p->n + 2); 1061 p->s[p->n++] = c; 1062 p->s[p->n] = '\0'; 1063 } 1064 1065 static void 1066 str_adds(String* p, char* s, ulong n) 1067 { 1068 str_insure(p, p->n + n + 1); 1069 memmove(p->s + p->n, s, n); 1070 p->n += n; 1071 p->s[p->n] = '\0'; 1072 } 1073 1074 static void 1075 str_delc(String* p) 1076 { 1077 if (p->n) 1078 p->s[--p->n] = 0; 1079 } 1080 1081 static void 1082 str_insert(String* p, String* q, Posn p0) 1083 { 1084 str_insure(p, p->n + q->n + 1); 1085 memmove(p->s + p0 + q->n, p->s + p0, p->n - p0); 1086 memmove(p->s + p0, q->s, q->n); 1087 p->n += q->n; 1088 p->s[p->n] = '\0'; 1089 } 1090 1091 static void 1092 str_delete(String* p, Posn p0, Posn p1) 1093 { 1094 memmove(p->s + p0, p->s + p1, p->n - p1); 1095 p->n -= p1 - p0; 1096 } 1097 1098 static void 1099 undo(int arg) 1100 { 1101 if (f->i < 0) 1102 return; 1103 if (buf->is[f->i].n) 1104 str_delete( 1105 f->s, buf->p0[f->i], buf->p0[f->i] + buf->is[f->i].n 1106 ); 1107 if (buf->ds[f->i].n) 1108 str_insert(f->s, &buf->ds[f->i], buf->p0[f->i]); 1109 f->dot.p0 = f->dot.p1 = buf->p0[f->i--]; 1110 f->dirty = '*'; 1111 fr_zero(fr); 1112 fr_update(); 1113 } 1114 1115 static void 1116 yank(int arg) 1117 { 1118 if (!f->s->n) 1119 return; 1120 if (!arg) { 1121 switch (arg = fgetc(stdin)) { 1122 case 'y': arg = Line; break; 1123 case 'G': arg = Bottom; break; 1124 case 'g': arg = Top; break; 1125 case 'w': arg = Word; break; 1126 case 't': arg = Till; break; 1127 default: 1128 return; 1129 } 1130 } 1131 if ((arg = selection(arg)) < 0) 1132 return; 1133 str_zero(&istr); 1134 str_adds(&istr, f->s->s + f->dot.p0, f->dot.p1 + 1 - f->dot.p0); 1135 } 1136 1137 int 1138 main(int argc, char* argv[]) 1139 { 1140 uint i; 1141 uchar c; 1142 1143 init(); 1144 if (argv[1]) { 1145 str_adds(f->name, argv[1], strlen(argv[1])); 1146 file_load(f); 1147 } 1148 for (;;) { 1149 resize(); 1150 fr_update(); 1151 c = fgetc(stdin); 1152 for (i = 0; i < LENGTH(keys); ++i) { 1153 if (keys[i].key == c) { 1154 keys[i].func(keys[i].value); 1155 break; 1156 } 1157 } 1158 } 1159 }