sim

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

sim.c (24074B)


      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*, Rune);
     89 static String Strn(Rune*, ulong);
     90 static Rune* Strnstr(Rune*, Rune*, ulong);
     91 static String Utf(char*);
     92 static void blind_reader(Frame*, Posn);
     93 static void blind_writer(ushort, ushort, ushort, ushort);
     94 static void buf_add(String*, String*, uint, uint, uint);
     95 static void buf_free(Buffer*);
     96 static int c2r(Rune*, uchar, uchar*);
     97 static void change(int);
     98 static void count(int);
     99 static void curmov(ushort, ushort);
    100 static uint curpos(void);
    101 static void delete(int);
    102 static void dot(int);
    103 static void redo(int);
    104 static void escape(int);
    105 static uchar getc2(void);
    106 static Rune getr(void);
    107 static void init(void);
    108 static void input(String*, uint, char*);
    109 static void insert(int);
    110 static int  isword(uchar);
    111 static void file_close(int);
    112 static void file_init(File*);
    113 static void file_load(File*);
    114 static void file_open(int);
    115 static void file_save(int);
    116 static void fr_add(Frame*, Address);
    117 static void fr_calc(void);
    118 static void fr_close(Frame*);
    119 static void fr_init(Frame*);
    120 static void fr_insert(Frame*, Frame, ushort);
    121 static void fr_insure(Frame*, ushort);
    122 static void fr_update(void);
    123 static void fr_zero(Frame*);
    124 static void gmove(int);
    125 static void msg(uint, char*, ...);
    126 static void paste(int);
    127 static void pline(int);
    128 static uchar r2u(char*, Rune);
    129 static uint runesiz(Rune, ulong);
    130 static void search(int);
    131 static int  selection(int);
    132 static ulong str2u(char**, String);
    133 static void str_init(String*);
    134 static void str_close(String*);
    135 static void str_dup(String*, String);
    136 static void str_zero(String*);
    137 static void str_insure(String*, ulong);
    138 static void str_addr(String*, Rune);
    139 static void str_adds(String*, String);
    140 static void str_delr(String*);
    141 static void str_insert(String*, String, Posn);
    142 static void str_delete(String*, Posn, Posn);
    143 static void u2str(String*, char*);
    144 static void undo(int);
    145 static void move(int);
    146 static void quit(int);
    147 static void yank(int);
    148 
    149 static Frame frame[FILECOUNT], *fr = frame;
    150 static File file[FILECOUNT], *f = file;
    151 static String istr, srch;
    152 static Window w;
    153 static uint counter;
    154 static char *ctrune[0x20] = {
    155 	"nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
    156 	"bs" , "\\t", "\\n", "vt" , "ff" , "cr" , "so" , "si",
    157 	"dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb",
    158 	"can", "em" , "sub", "esc", "fs" , "gs" , "rs" , "us"
    159 };
    160 
    161 #include "config.h"
    162 
    163 extern void
    164 die(char* fmt, ...)
    165 {
    166 	static char *s;
    167 	va_list ap;
    168 	uint i;
    169 
    170 	win_end();
    171 	va_start(ap, fmt);
    172 	vfprintf(stderr, fmt, ap);
    173 	va_end(ap);
    174 	if (fmt[0] && fmt[strlen(fmt) - 1] == ':')
    175 		perror(NULL);
    176 	else
    177 		fputc('\n', stderr);
    178 	for (i = 0; i < FILECOUNT; ++i) {
    179 		f = file + i;
    180 		if (!f->s.n)
    181 			continue;
    182 		str_adds(&f->name, Utf(".swap"));
    183 		file_save(i);
    184 		str2u(&s, f->name);
    185 		fprintf(stderr, "file saved to %s\n", s);
    186 	}
    187 	abort();
    188 }
    189 
    190 extern void*
    191 emalloc(ulong n)
    192 {
    193 	void* p;
    194 
    195 	p = malloc(n);
    196 	if (!p)
    197 		die("malloc:");
    198 	memset(p, 0, n);
    199 	return p;
    200 }
    201 
    202 extern void*
    203 erealloc(void* p, ulong n)
    204 {
    205 	p = realloc(p, n);
    206 	if (!p)
    207 		die("realloc:");
    208 	return p;
    209 }
    210 
    211 extern void
    212 resize(void)
    213 {
    214 	Window wt;
    215 
    216 	win_query(&wt);
    217 	if (wt.wx != w.wx || wt.wy != w.wy) {
    218 		w.wx = wt.wx;
    219 		w.wy = wt.wy;
    220 		fr_zero(fr);
    221 		fr_update();
    222 	}
    223 }
    224 
    225 static Rune*
    226 Strchr(Rune *s, Rune r)
    227 {
    228 	for (;*s != '\0'; ++s)
    229 		if (*s == r)
    230 			return s;
    231 	return NULL;
    232 }
    233 
    234 static String
    235 Strn(Rune *r, ulong n)
    236 {
    237 	static String s;
    238 	ulong l;
    239 
    240 	l = (n + 1) * sizeof(*s.s);
    241 	s.s = erealloc(s.s, l);
    242 	s.n = n;
    243 	memcpy(s.s, r, l);
    244 	s.s[s.n] = '\0';
    245 	return s;
    246 }
    247 
    248 static Rune*
    249 Strnstr(Rune *s1, Rune *s2, ulong n)
    250 {
    251 	n *= sizeof(*s2);
    252 	do {
    253 		s1 = Strchr(s1, s2[0]);
    254 		if (s1 != NULL && !memcmp(s1, s2, n))
    255 			return s1;
    256 	} while (s1++ != NULL);
    257 	return NULL;
    258 }
    259 
    260 static String
    261 Utf(char* s)
    262 {
    263 	static String t;
    264 
    265 	u2str(&t, s);
    266 	return t;
    267 }
    268 
    269 static void
    270 blind_reader(Frame* fr, Posn p0)
    271 {
    272 	Address a;
    273 	uint wx;
    274 
    275 	a.p0 = a.p1 = p0;
    276 	do {
    277 		for (wx = 0; wx < w.wx && a.p1 < f->s.n;) {
    278 			if (f->s.s[a.p1] == '\n')
    279 				break;
    280 			wx += runesiz(f->s.s[a.p1], wx);
    281 			if (wx < w.wx)
    282 				++a.p1;
    283 			if (wx >= w.wx) {
    284 				if (f->s.s[a.p1] == '\t')
    285 					++a.p1;
    286 				if (f->s.s[a.p1 + 1] == '\n')
    287 					++a.p1;
    288 			}
    289 		}
    290 		fr_add(fr, a);
    291 		a.p0 = ++a.p1;
    292 	} while (a.p1 <= f->s.n && f->s.s[a.p1 - 1] != '\n');
    293 }
    294 
    295 static void
    296 blind_writer(ushort line, ushort offset, ushort top, ushort bot)
    297 {
    298 	static char *s;
    299 	Posn i, o;
    300 	ulong n;
    301 
    302 	i = o = 0;
    303 	if (offset >= top)
    304 		i = offset - top + 1;
    305 	if (fr->n - offset > bot)
    306 		o = offset + bot - 1;
    307 	else if (fr->n)
    308 		o = fr->n - 1;
    309 	curmov(0, offset > line ? 0 : line - offset);
    310 	i = fr->a[i].p0;
    311 	o = fr->a[o].p1;
    312 	n = str2u(&s, Strn(f->s.s + i, o - i));
    313 	fwrite(s, n, 1, stdout);
    314 }
    315 
    316 static void
    317 buf_add(String* is, String* ds, uint c, uint arg, uint count)
    318 {
    319 	if (f->b->next)
    320 		buf_free(f->b->next);
    321 	f->b->next = emalloc(sizeof(*f->b->next));
    322 	f->b->next->prev = f->b;
    323 	f->b = f->b->next;
    324 	if (is != NULL)
    325 		str_insert(&f->b->is, *is, 0);
    326 	if (ds != NULL)
    327 		str_insert(&f->b->ds, *ds, 0);
    328 	f->b->c = c;
    329 	f->b->arg = arg;
    330 	f->b->count = count;
    331 	f->b->p0 = f->dot.p0;
    332 	fr_zero(fr);
    333 }
    334 
    335 static void
    336 buf_free(Buffer* p)
    337 {
    338 	if (p->next != NULL)
    339 		buf_free(p->next);
    340 	str_close(&p->is);
    341 	str_close(&p->ds);
    342 	free(p);
    343 }
    344 
    345 static int
    346 c2r(Rune *r, uchar c, uchar *seq)
    347 {
    348 	if (*seq != 0) {
    349 		if ((c & 0xc0) != 0x80) {
    350 			*seq = 0;
    351 			return -1;
    352 		}
    353 		*r = (*r << 6) | (c & 0x3f);
    354 		--*seq;
    355 		return 0;
    356 	}
    357 	if ((c & 0x80) == 0) {
    358 		*r = c & 0x7f;
    359 		*seq = 0;
    360 	} else if ((c & 0xe0) == 0xc0) {
    361 		*r = c & 0x1f;
    362 		*seq = 1;
    363 	} else if ((c & 0xf0) == 0xe0) {
    364 		*r = c & 0x0f;
    365 		*seq = 2;
    366 	} else if ((c & 0xf8) == 0xf0) {
    367 		*r = c & 0x07;
    368 		*seq = 3;
    369 	} else if ((c & 0xfc) == 0xf8) {
    370 		*r = c & 0x03;
    371 		*seq = 4;
    372 	} else if ((c & 0xfe) == 0xfc) {
    373 		*r = c & 0x01;
    374 		*seq = 5;
    375 	} else {
    376 		*r = c;
    377 		*seq = 0;
    378 	}
    379 	return 0;
    380 }
    381 
    382 static void
    383 change(int arg)
    384 {
    385 	String s;
    386 	Address *a;
    387 	uint count;
    388 
    389 	if (!arg)
    390 		arg = getr();
    391 	switch (arg) {
    392 	case 'x': arg = Letter; break;
    393 	case 'c': arg = Line; break;
    394 	case 'G': arg = Bottom; break;
    395 	case 'g': arg = Top; break;
    396 	case 'w': arg = Word; break;
    397 	case 't': arg = Till; break;
    398 	}
    399 	count = counter;
    400 	arg = selection(arg);
    401 	if (arg == Word || arg == Letter || arg > 0x7f)
    402 		++f->dot.p1;
    403 	str_init(&s);
    404 	a = &f->dot;
    405 	if (a->p0 != a->p1) {
    406 		str_adds(&s, Strn(f->s.s + a->p0, a->p1 - a->p0));
    407 		str_delete(&f->s, a->p0, a->p1);
    408 		a->p1 = a->p0;
    409 	}
    410 	fr_zero(fr);
    411 	insert(0);
    412 	if (s.n)
    413 		str_insert(&f->b->ds, s, 0);
    414 	f->b->c = Change;
    415 	f->b->arg = arg;
    416 	f->b->count = count;
    417 	str_close(&s);
    418 	fr_update();
    419 }
    420 
    421 static void
    422 count(int arg)
    423 {
    424 	if (!counter && !arg) {
    425 		move(StartLine);
    426 		return;
    427 	}
    428 	counter *= 10;
    429 	counter += arg;
    430 }
    431 
    432 static void
    433 curmov(ushort x, ushort y)
    434 {
    435 	printf(CSI "%hu;%huH", y, x);
    436 }
    437 
    438 static uint
    439 curpos(void)
    440 {
    441 	ulong i, wx;
    442 
    443 	if (!fr->n)
    444 		return 0;
    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.n && 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 			fr_zero(&fr0);
    822 			for (p0 = fr->a[0].p0 - 1
    823 				; p0 && f->s.s[p0 - 1] != '\n'
    824 				; --p0
    825 			);
    826 			blind_reader(&fr0, p0);
    827 			fr_insert(fr, fr0, 0);
    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 }