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