sim

the sim text editor
git clone git://ssnf.xyz/sim
Log | Files | Refs | README

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 }