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