sim.c (24293B)
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 wx = 0; 446 for (i = fr->a[fr->cur].p0; i < f->dot.p1; ++i) 447 wx += runesiz(f->s.s[i], wx); 448 return wx; 449 } 450 451 static void 452 delete(int arg) 453 { 454 String s; 455 Address *a; 456 uint count; 457 458 if (!f->s.n) 459 return; 460 if (!arg) { 461 switch (arg = getr()) { 462 case 'x': arg = Letter; break; 463 case 'd': arg = Line; break; 464 case 'G': arg = Bottom; break; 465 case 'g': arg = Top; break; 466 case 'w': arg = Word; break; 467 case 't': arg = Till; break; 468 default: 469 return; 470 } 471 } 472 count = counter; 473 if ((arg = selection(arg)) < 0) 474 return; 475 str_init(&s); 476 a = &f->dot; 477 str_adds(&s, Strn(f->s.s + a->p0, a->p1 + 1 - a->p0)); 478 str_dup(&istr, s); 479 buf_add(NULL, &s, Delete, arg, count); 480 str_delete(&f->s, a->p0, a->p1 + 1); 481 str_close(&s); 482 if (a->p0 == f->s.n && a->p0) 483 --a->p0; 484 a->p1 = a->p0; 485 fr_update(); 486 } 487 488 static void 489 dot(int arg) 490 { 491 String ds; 492 Address *a; 493 494 if (f->b->prev == NULL) 495 return; 496 a = &f->dot; 497 arg = f->b->arg; 498 counter = f->b->count; 499 switch (f->b->c) { 500 case Insert: 501 if (arg == Down) 502 move(EndLine); 503 else 504 move(arg); 505 str_insert(&f->s, f->b->is, a->p0); 506 buf_add(&f->b->is, NULL, Insert, arg, counter); 507 break; 508 case Delete: 509 delete(arg); 510 break; 511 case Change: 512 str_init(&ds); 513 if (f->b->ds.n) { 514 selection(arg); 515 if (arg == Word || arg == Letter || arg > 0x7f) 516 ++a->p1; 517 str_adds(&ds 518 , Strn(f->s.s + a->p0, a->p1 - a->p0) 519 ); 520 str_delete(&f->s, a->p0, a->p1); 521 } 522 if (f->b->is.n) 523 str_insert(&f->s, f->b->is, f->dot.p0); 524 buf_add(&f->b->is, &ds, Change, arg, f->b->count); 525 str_close(&ds); 526 f->dot.p1 = f->dot.p0; 527 break; 528 } 529 fr_update(); 530 } 531 532 static void 533 redo(int arg) 534 { 535 if (f->b->next == NULL) 536 return; 537 if (arg) { 538 for (;f->b->next != NULL;) 539 redo(0); 540 return; 541 } 542 f->b = f->b->next; 543 if (f->b->ds.n) 544 str_delete(&f->s, f->b->p0, f->b->p0 + f->b->ds.n); 545 if (f->b->is.n) 546 str_insert(&f->s, f->b->is, f->b->p0); 547 f->dot.p0 = f->dot.p1 = f->b->p0; 548 fr_zero(fr); 549 fr_update(); 550 } 551 552 static void 553 escape(int c) 554 { 555 counter = 0; 556 c = getc2() - 0x30; 557 if (c > 0 && c <= 8) { 558 --c; 559 f = &file[c]; 560 fr = &frame[c]; 561 return; 562 } 563 ungetc(c + 0x30, stdin); 564 } 565 566 static uchar 567 getc2(void) 568 { 569 uchar c; 570 571 get: 572 c = getchar(); 573 if (c == (uchar)EOF) { 574 if (!feof(stdin)) 575 goto get; 576 exit(0); 577 } 578 return c; 579 } 580 581 static Rune 582 getr(void) 583 { 584 Rune r; 585 uchar c, seq; 586 587 r = 0; 588 seq = 0; 589 do { 590 c = getc2(); 591 if (c2r(&r, c, &seq) == -1) { 592 seq = 0; 593 ungetc(c, stdin); 594 } 595 } while (seq != 0); 596 return r; 597 } 598 599 static void 600 input(String* s, uint line, char* prefix) 601 { 602 static char *t; 603 Rune r; 604 605 for (;;) { 606 str2u(&t, *s); 607 msg(line, "%s%s", prefix, t); 608 switch (r = getr()) { 609 case Esc: 610 str_zero(s); 611 case '\n': 612 return; 613 case Del: 614 str_delr(s); 615 break; 616 default: 617 str_addr(s, r); 618 } 619 } 620 s->s[s->n] = '\0'; 621 } 622 623 static int 624 isword(uchar c) 625 { 626 return strchr(" \t\n.(){}[]:;,<>#*+-!%\\/\"=", c) == NULL; 627 } 628 629 static void 630 insert(int arg) 631 { 632 String s, c; 633 634 if (f->s.s[f->s.n - 1] != '\n') 635 str_addr(&f->s, '\n'); 636 str_init(&s), str_init(&c); 637 str_addr(&c, '\0'); 638 switch (arg) { 639 case StartLine: 640 case EndLine: 641 case Right: 642 move(arg); 643 break; 644 case Down: 645 move(EndLine); 646 str_addr(&s, '\n'); 647 str_insert(&f->s, s, f->dot.p0); 648 ++f->dot.p1; 649 break; 650 } 651 for (;;) { 652 fr_update(); 653 switch (c.s[0] = getr()) { 654 case Esc: 655 goto endmode; 656 case Del: 657 if (f->dot.p1 != f->dot.p0) { 658 str_delr(&s); 659 str_delete(&f->s, f->dot.p1 - 1, f->dot.p1); 660 --f->dot.p1; 661 } 662 break; 663 default: 664 str_addr(&s, c.s[0]); 665 str_insert(&f->s, c, f->dot.p1); 666 } 667 f->dot.p1 = f->dot.p0 + s.n; 668 } 669 endmode: 670 str_dup(&istr, s); 671 for (counter ? --counter : 0; counter; --counter) { 672 str_insert(&istr, s, istr.n); 673 str_insert(&f->s, s, f->dot.p0); 674 } 675 buf_add(&istr, NULL, Insert, arg, counter); 676 str_close(&s), str_close(&c); 677 f->dot.p0 = f->dot.p1; 678 if (f->dot.p1 >= f->s.n) 679 move(Left); 680 } 681 682 static void 683 init(void) 684 { 685 uint i; 686 687 for (i = 0; i < FILECOUNT; ++i) { 688 file_init(&file[i]); 689 fr_init(&frame[i]); 690 } 691 str_init(&srch); 692 str_init(&istr); 693 win_init(&w); 694 } 695 696 static void 697 file_close(int arg) 698 { 699 static char *s; 700 701 if (arg != -1) 702 f = &file[arg]; 703 if (f->bd != f->b) { 704 str2u(&s, f->name); 705 msg(w.wy / 2, RED("Save %s?") " [y/n]" 706 , f->name.n ? s : "-unnamed-" 707 ); 708 if (getr() == 'y') 709 file_save(arg); 710 } 711 str_close(&f->s); 712 str_close(&f->name); 713 for (;f->b->prev != NULL; f->b = f->b->prev); 714 buf_free(f->b); 715 file_init(f); 716 fr_zero(fr); 717 } 718 719 static void 720 file_init(File* f) 721 { 722 str_init(&f->s); 723 str_init(&f->name); 724 f->dot.p0 = 0; 725 f->dot.p1 = 0; 726 f->b = emalloc(sizeof(*f->b)); 727 f->bd = f->b; 728 } 729 730 static void 731 file_load(File* f) 732 { 733 FILE *disk; 734 ulong n; 735 char *s; 736 737 s = NULL; 738 str2u(&s, f->name); 739 disk = fopen(s, "r"); 740 if (disk == NULL) 741 return; 742 s = NULL; 743 n = 0; 744 do { 745 s = erealloc(s, n + 4096); 746 n += fread(s + n, 1, 4096, disk); 747 } while (!feof(disk)); 748 s[n] = '\0'; 749 u2str(&f->s, s); 750 free(s); 751 } 752 753 static void 754 file_open(int arg) 755 { 756 file_close(-1); 757 input(&f->name, w.wy / 2, GREEN("$ ")); 758 file_load(f); 759 } 760 761 static void 762 file_save(int arg) 763 { 764 static char *s; 765 FILE *disk; 766 ulong n; 767 768 if (arg != -1) 769 f = &file[arg]; 770 if (!f->name.n) { 771 input(&f->name, w.wy / 2, "File name: "); 772 if (!f->name.n) 773 return; 774 } 775 str2u(&s, f->name); 776 disk = fopen(s, "w"); 777 n = str2u(&s, f->s); 778 fwrite(s, n, 1, disk); 779 fclose(disk); 780 f->bd = f->b; 781 } 782 783 static void 784 fr_add(Frame* fr, Address a) 785 { 786 fr_insure(fr, ++fr->n); 787 fr->a[fr->n - 1] = a; 788 } 789 790 static void 791 fr_calc(void) 792 { 793 Frame fr0; 794 Posn p0; 795 796 for (;f->dot.p1 < fr->a[fr->cur].p0 && fr->cur; --fr->cur); 797 for (;f->dot.p1 > fr->a[fr->cur].p1 && fr->cur + 1 < fr->n 798 ; ++fr->cur 799 ); 800 if (!fr->n 801 || f->dot.p1 != f->dot.p0 802 || f->dot.p1 < fr->a[0].p0 803 || f->dot.p1 > fr->a[fr->n - 1].p1 804 || (fr->cur < w.wy && fr->a[0].p0) 805 || (fr->cur + w.wy > fr->n 806 && fr->a[fr->n - 1].p1 + 1 < f->s.n 807 ) 808 ) { 809 /*dot + bottom addresses*/ 810 fr_zero(fr); 811 for (p0 = f->dot.p1; p0 && f->s.s[p0 - 1] != '\n'; --p0); 812 for (;p0 < f->s.n && fr->n < w.wy * 2;) { 813 blind_reader(fr, p0); 814 p0 = fr->a[fr->n - 1].p1 + 1; 815 } 816 /*top addresses*/ 817 for (fr_init(&fr0) 818 ; fr->a[0].p0 && fr->cur < w.wy 819 ; fr->cur += fr0.n 820 ) { 821 for (p0 = fr->a[0].p0 - 1 822 ; p0 && f->s.s[p0 - 1] != '\n' 823 ; --p0 824 ); 825 blind_reader(&fr0, p0); 826 fr_insert(fr, fr0, 0); 827 fr_zero(&fr0); 828 } 829 fr_close(&fr0); 830 for (; f->dot.p1 > fr->a[fr->cur].p1 && fr->cur < fr->n 831 ; ++fr->cur 832 ); 833 } 834 } 835 836 static void 837 fr_close(Frame* fr) 838 { 839 free(fr->a); 840 } 841 842 static void 843 fr_init(Frame* fr) 844 { 845 fr->a = emalloc(32 * sizeof(*fr->a)); 846 fr->cur = 0; 847 fr->n = 0; 848 fr->size = 32; 849 fr->a[fr->cur].p0 = 0; 850 fr->a[fr->cur].p1 = 0; 851 } 852 853 static void 854 fr_insert(Frame* p, Frame q, ushort n) 855 { 856 fr_insure(p, p->n + q.n); 857 memmove(p->a + n + q.n, p->a + n, (p->n - n) * sizeof(*p->a)); 858 memmove(p->a + n, q.a, q.n * sizeof(*p->a)); 859 p->n += q.n; 860 } 861 862 static void 863 fr_insure(Frame* fr, ushort n) 864 { 865 if (n > fr->size) { 866 fr->size += n + 32; 867 fr->a = erealloc(fr->a, fr->size * sizeof(*fr->a)); 868 } 869 } 870 871 static void 872 fr_update(void) 873 { 874 static char stat[128], u[UTFMAX + 1]; 875 static char *fname, *urune; 876 Rune rune; 877 uint half; 878 879 half = w.wy / 2; 880 if (f->s.n) { 881 fr_calc(); 882 printf(ED); 883 blind_writer(half, fr->cur, half, half + (w.wy % 2)); 884 } else 885 printf(ED); 886 str2u(&fname, f->name.n ? f->name : Utf("-unnamed-")); 887 rune = f->s.s[f->dot.p1]; 888 if (rune < 0x20) 889 urune = ctrune[rune]; 890 else if (rune == 0x7f) 891 urune = "del"; 892 else { 893 r2u(u, rune); 894 urune = u; 895 } 896 snprintf(stat, w.wx, STATUS); /*i dont care. TODO: care*/ 897 msg(w.wy, "%s", stat); 898 curmov(curpos() + 1, half); 899 } 900 901 static void 902 fr_zero(Frame* fr) 903 { 904 fr->n = 0; 905 fr->cur = 0; 906 fr->a[fr->cur].p0 = 0; 907 fr->a[fr->cur].p1 = 0; 908 } 909 910 static void 911 move(int arg) 912 { 913 switch (arg) { 914 case Left: 915 if (f->dot.p1) 916 --f->dot.p1; 917 break; 918 case Right: 919 if (f->dot.p1 + 1 < f->s.n) 920 ++f->dot.p1; 921 break; 922 case Up: 923 if (fr->cur) 924 f->dot.p1 = fr->a[fr->cur - 1].p0; 925 else 926 f->dot.p1 = 0; 927 break; 928 case Down: 929 if (!fr->a[fr->cur].p1) 930 return; 931 if (fr->cur < fr->n - 1) 932 f->dot.p1 = fr->a[fr->cur + 1].p0; 933 else 934 f->dot.p1 = fr->a[fr->cur].p1 - 1; 935 break; 936 case HalfUp: 937 if (fr->cur < w.wy/2) 938 f->dot.p1 = 0; 939 else 940 f->dot.p1 = fr->a[fr->cur - w.wy/2].p0; 941 break; 942 case HalfDown: 943 if (!f->s.n) 944 break; 945 if (fr->n - fr->cur <= w.wy/2) { 946 if (fr->a[fr->n - 1].p1 <= f->s.n) 947 f->dot.p1 = fr->a[fr->n - 1].p0; 948 else 949 f->dot.p1 = f->s.n; 950 } else 951 f->dot.p1 = fr->a[fr->cur + w.wy/2].p0; 952 break; 953 case Top: 954 f->dot.p1 = 0; 955 break; 956 case Bottom: 957 if (f->s.n) 958 f->dot.p1 = f->s.n - 1; 959 break; 960 case StartLine: 961 if (fr->cur) 962 for (;fr->cur > 1 963 && f->s.s[fr->a[fr->cur].p0 - 1] != '\n' 964 ; --fr->cur 965 ); 966 f->dot.p1 = fr->a[fr->cur].p0; 967 break; 968 case EndLine: 969 for (;f->dot.p1 + 1 < f->s.n && f->s.s[f->dot.p1] != '\n' 970 ; ++f->dot.p1 971 ); 972 break; 973 case Word: 974 for (;f->dot.p1 + 1 < f->s.n && isword(f->s.s[f->dot.p1]) 975 ; ++f->dot.p1 976 ); 977 for (;f->dot.p1 + 1 < f->s.n && !isword(f->s.s[f->dot.p1]) 978 ; ++f->dot.p1 979 ); 980 break; 981 case EndWord: 982 move(Right); 983 for (;f->dot.p1 < f->s.n && !isword(f->s.s[f->dot.p1]) 984 ; ++f->dot.p1 985 ); 986 for (;f->dot.p1 < f->s.n && isword(f->s.s[f->dot.p1]) 987 ; ++f->dot.p1 988 ); 989 move(Left); 990 break; 991 case PrevWord: 992 move(Left); 993 for (;f->dot.p1 > 0 && !isword(f->s.s[f->dot.p1]) 994 ; --f->dot.p1 995 ); 996 for (;f->dot.p1 > 0 && isword(f->s.s[f->dot.p1]) 997 ; --f->dot.p1 998 ); 999 if (f->dot.p1) 1000 move(Right); 1001 break; 1002 }; 1003 f->dot.p0 = f->dot.p1; 1004 fr_calc(); 1005 } 1006 1007 static void 1008 quit(int arg) 1009 { 1010 uint i; 1011 1012 for (i = 0; i < FILECOUNT; ++i) 1013 file_close(i); 1014 win_end(); 1015 exit(arg); 1016 } 1017 1018 static void 1019 gmove(int arg) 1020 { 1021 if (arg == Top) { 1022 move(Top); 1023 for (counter ? --counter : 0; counter; --counter) { 1024 move(EndLine); 1025 move(Right); 1026 } 1027 return; 1028 } 1029 for (!counter ? ++counter : 0; counter; --counter) 1030 move(arg); 1031 } 1032 1033 static void 1034 msg(uint line, char* fmt, ...) 1035 { 1036 va_list ap; 1037 1038 curmov(0, line); 1039 printf(EL); 1040 va_start(ap, fmt); 1041 vprintf(fmt, ap); 1042 va_end(ap); 1043 } 1044 1045 static void 1046 paste(int arg) 1047 { 1048 str_insert(&f->s, istr, f->dot.p0); 1049 buf_add(&istr, NULL, Insert, 0, 1); 1050 } 1051 1052 static void 1053 pline(int arg) 1054 { 1055 ulong i, l, h, t; 1056 1057 l = 1; 1058 t = fr->a[fr->cur].p0; 1059 for (i = 0; i < t; ++i) 1060 if (f->s.s[i] == '\n') 1061 ++l; 1062 h = w.wy / 2; 1063 for (i = 0; i < h; ++i) 1064 if (h - i < l) { 1065 curmov(0, i); 1066 printf("%4lu ", h - i); 1067 } 1068 t = fr->n - fr->cur; 1069 for (i = h + 1; i < w.wy; ++i) 1070 if (i - h < t) { 1071 curmov(0, i); 1072 printf("%4lu ", i - h); 1073 } 1074 curmov(0, h); 1075 printf("%-4lu ", l); 1076 i = getc2(); 1077 if (i != Esc) 1078 ungetc(i, stdin); 1079 } 1080 1081 static uchar 1082 r2u(char *s, Rune r) 1083 { 1084 char* p; 1085 1086 p = s; 1087 if (r < (1 << 7)) { 1088 *p++ = r; 1089 } else if (r < (1 << 11)) { 1090 *p++ = 0xc0 | (r >> 6); 1091 *p++ = 0x80 | (r & 0x3f); 1092 } else if (r < (1 << 16)) { 1093 *p++ = 0xe0 | (r >> 12); 1094 *p++ = 0x80 | ((r >> 6) & 0x3f); 1095 *p++ = 0x80 | (r & 0x3f); 1096 } else if (r < (1 << 21)) { 1097 *p++ = 0xf0 | (r >> 18); 1098 *p++ = 0x80 | ((r >> 12) & 0x3f); 1099 *p++ = 0x80 | ((r >> 6) & 0x3f); 1100 *p++ = 0x80 | (r & 0x3f); 1101 } else if (r < (1 << 26)) { 1102 *p++ = 0xf8 | (r >> 24); 1103 *p++ = 0x80 | ((r >> 18) & 0x3f); 1104 *p++ = 0x80 | ((r >> 12) & 0x3f); 1105 *p++ = 0x80 | ((r >> 6) & 0x3f); 1106 *p++ = 0x80 | (r & 0x3f); 1107 } else if (r < (1 << 31)) { 1108 *p++ = 0xfe | (r >> 30); 1109 *p++ = 0x80 | ((r >> 24) & 0x3f); 1110 *p++ = 0x80 | ((r >> 18) & 0x3f); 1111 *p++ = 0x80 | ((r >> 12) & 0x3f); 1112 *p++ = 0x80 | ((r >> 6) & 0x3f); 1113 *p++ = 0x80 | (r & 0x3f); 1114 } 1115 *p = '\0'; 1116 return p - s; 1117 } 1118 1119 static uint 1120 runesiz(Rune c, ulong wx) 1121 { 1122 if (c == '\n') 1123 die("runesiz(): newline."); 1124 return (c == '\t') ? w.t - (wx % w.t) : 1; 1125 } 1126 1127 static void 1128 search(int arg) 1129 { 1130 Posn pos; 1131 Rune *r; 1132 1133 f->s.s[f->s.n] = 0; 1134 if (arg == '/' || arg == '?') { 1135 str_zero(&srch); 1136 input(&srch, w.wy, "/"); 1137 for (pos = 0; pos < srch.n; ++pos) 1138 if (srch.s[pos] == '^') 1139 srch.s[pos] = '\n'; 1140 } 1141 if (arg == '/' || arg == 'n') { 1142 move(Right); 1143 r = Strnstr(f->s.s + f->dot.p0, srch.s, srch.n); 1144 if (r == NULL) { 1145 move(Left); 1146 return; 1147 } 1148 } else { 1149 pos = f->dot.p1; 1150 if (srch.s[0] == '\n' && srch.s[1] != '\n') 1151 move(Left); 1152 for (;;) { 1153 for (;move(Left), f->dot.p1 1154 && f->s.s[f->dot.p1] != srch.s[0] 1155 ; 1156 ); 1157 if (!memcmp(f->s.s + f->dot.p1 1158 , srch.s , srch.n * sizeof(*srch.s) 1159 )) 1160 break; 1161 if (!f->dot.p1) { 1162 f->dot.p0 = f->dot.p1 = pos; 1163 return; 1164 } 1165 } 1166 r = f->s.s + f->dot.p1; 1167 } 1168 f->dot.p0 = f->dot.p1 = r - f->s.s; 1169 if (srch.s[0] == '\n' && srch.s[1] != '\n') 1170 move(Right); 1171 fr_update(); 1172 } 1173 1174 static int 1175 selection(int arg) 1176 { 1177 Posn p0; 1178 1179 if (!counter) 1180 ++counter; 1181 if (arg > 0x7f) { 1182 arg -= 0x7f; 1183 goto till; 1184 } 1185 p0 = f->dot.p1 = f->dot.p0; 1186 switch (arg) { 1187 case Letter: 1188 p0 = f->dot.p0; 1189 for (;counter > 1; --counter) 1190 move(Right); 1191 break; 1192 case Line: 1193 move(StartLine); 1194 p0 = f->dot.p0; 1195 for (;counter; --counter) { 1196 move(EndLine); 1197 move(Right); 1198 } 1199 if (f->dot.p1 + 1 < f->s.n) 1200 move(Left); 1201 break; 1202 case Bottom: 1203 move(StartLine); 1204 move(Left); 1205 p0 = f->dot.p0; 1206 move(Bottom); 1207 break; 1208 case Top: 1209 p0 = 0; 1210 move(EndLine); 1211 break; 1212 case Word: 1213 p0 = f->dot.p0; 1214 for (;counter; --counter) 1215 move(EndWord); 1216 break; 1217 case Till: 1218 arg = getr(); 1219 if (arg == Esc) 1220 return 0; 1221 till: 1222 p0 = f->dot.p0; 1223 for (;counter && f->dot.p1 + 1 < f->s.n; --counter) 1224 for (++f->dot.p1 1225 ; f->dot.p1 + 1 < f->s.n 1226 && f->s.s[f->dot.p1 + 1] != arg 1227 ; ++f->dot.p1 1228 ); 1229 if (f->s.s[f->dot.p1 + 1] != arg) { 1230 f->dot.p1 = f->dot.p0; 1231 return -1; 1232 } 1233 arg += 0x7f; 1234 break; 1235 } 1236 f->dot.p0 = p0; 1237 counter = 0; 1238 return arg; 1239 } 1240 1241 static ulong 1242 str2u(char** u, String s) 1243 { 1244 ulong i, n; 1245 1246 n = 0; 1247 *u = erealloc(*u, (s.n + 1) * UTFMAX); 1248 for (i = 0; i < s.n; ++i) 1249 n += r2u(*u + n, s.s[i]); 1250 (*u)[n] = '\0'; 1251 return n; 1252 } 1253 1254 static void 1255 str_init(String* p) 1256 { 1257 p->s = emalloc(MINSIZE * sizeof(*p->s)); 1258 p->n = 0; 1259 p->size = MINSIZE; 1260 p->s[p->n] = '\0'; 1261 } 1262 1263 static void 1264 str_close(String* p) 1265 { 1266 free(p->s); 1267 } 1268 1269 static void 1270 str_dup(String* p, String q) 1271 { 1272 str_zero(p); 1273 str_adds(p, q); 1274 } 1275 1276 static void 1277 str_zero(String* p) 1278 { 1279 if (p->size > MAXEMPTY) { 1280 p->s = erealloc(p->s, MAXEMPTY * sizeof(*p->s)); 1281 p->size = MAXEMPTY; 1282 } 1283 p->n = 0; 1284 memset(p->s, 0, p->size * sizeof(*p->s)); 1285 } 1286 1287 static void 1288 str_insure(String* p, ulong n) 1289 { 1290 if (p->size < n + 1) { 1291 p->size = n + MAXEMPTY; 1292 p->s = erealloc(p->s, p->size * sizeof(*p->s)); 1293 } 1294 } 1295 1296 static void 1297 str_addr(String* p, Rune r) 1298 { 1299 str_insure(p, p->n + 1); 1300 p->s[p->n++] = r; 1301 p->s[p->n] = '\0'; 1302 } 1303 1304 static void 1305 str_adds(String *p, String q) 1306 { 1307 str_insure(p, p->n + q.n); 1308 memcpy(p->s + p->n, q.s, q.n * sizeof(*q.s)); 1309 p->n += q.n; 1310 p->s[p->n] = '\0'; 1311 } 1312 1313 static void 1314 str_delr(String* p) 1315 { 1316 if (p->n) 1317 p->s[--p->n] = '\0'; 1318 } 1319 1320 static void 1321 str_insert(String* p, String q, Posn p0) 1322 { 1323 str_insure(p, p->n + q.n); 1324 memmove(p->s + p0 + q.n, p->s + p0 1325 , (p->n - p0) * sizeof(*p->s) 1326 ); 1327 memmove(p->s + p0, q.s, q.n * sizeof(*q.s)); 1328 p->n += q.n; 1329 p->s[p->n] = '\0'; 1330 } 1331 1332 static void 1333 str_delete(String* p, Posn p0, Posn p1) 1334 { 1335 memmove(p->s + p0, p->s + p1, (p->n - p1) * sizeof(*p->s)); 1336 p->n -= p1 - p0; 1337 p->s[p->n] = '\0'; 1338 } 1339 1340 static void 1341 u2str(String *s, char *u) 1342 { 1343 Rune r; 1344 uchar seq; 1345 1346 str_zero(s); 1347 for (seq = 0; *u != '\0'; ++u) { 1348 if (c2r(&r, *u, &seq) == -1) 1349 --u; 1350 else if (seq == 0) 1351 str_addr(s, r); 1352 } 1353 } 1354 1355 static void 1356 undo(int arg) 1357 { 1358 if (f->b->prev == NULL) 1359 return; 1360 if (arg) { 1361 for (;f->b->prev != NULL;) 1362 undo(0); 1363 return; 1364 } 1365 if (f->b->is.n) 1366 str_delete(&f->s, f->b->p0, f->b->p0 + f->b->is.n); 1367 if (f->b->ds.n) 1368 str_insert(&f->s, f->b->ds, f->b->p0); 1369 f->dot.p0 = f->dot.p1 = f->b->p0; 1370 f->b = f->b->prev; 1371 fr_zero(fr); 1372 fr_update(); 1373 } 1374 1375 static void 1376 yank(int arg) 1377 { 1378 Address a; 1379 1380 if (!f->s.n) 1381 return; 1382 if (!arg) { 1383 switch (arg = getr()) { 1384 case 'y': arg = Line; break; 1385 case 'G': arg = Bottom; break; 1386 case 'g': arg = Top; break; 1387 case 'w': arg = Word; break; 1388 case 't': arg = Till; break; 1389 default: 1390 return; 1391 } 1392 } 1393 if ((arg = selection(arg)) < 0) 1394 return; 1395 a = f->dot; 1396 str_dup(&istr, Strn(f->s.s + a.p0, a.p1 + 1 - a.p0)); 1397 } 1398 1399 int 1400 main(int argc, char* argv[]) 1401 { 1402 uint i; 1403 uchar c; 1404 1405 init(); 1406 if (argv[1]) { 1407 str_adds(&f->name, Utf(argv[1])); 1408 file_load(f); 1409 } 1410 for (;;) { 1411 fr_update(); 1412 c = getr(); 1413 for (i = 0; i < LENGTH(keys); ++i) { 1414 if (keys[i].key == c) { 1415 keys[i].func(keys[i].value); 1416 break; 1417 } 1418 } 1419 } 1420 }