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