sim

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

sim.c (24541B)


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