1 /*
2 * device-independent TTY interface for JOE
3 * Copyright
4 * (C) 1992 Joseph H. Allen
5 *
6 * This file is part of JOE (Joe's Own Editor)
7 */
8 #include "config.h"
9 #include "types.h"
10
11 __RCSID("$MirOS: contrib/code/jupp/scrn.c,v 1.45 2018/06/28 03:11:13 tg Exp $");
12
13 #include <stdlib.h>
14 #include <string.h>
15
16 #include "bw.h"
17 #include "blocks.h"
18 #include "scrn.h"
19 #include "termcap.h"
20 #include "charmap.h"
21 #include "utils.h"
22
23 int skiptop = 0;
24 int lines = 0;
25 int columns = 0;
26 int notite = 0;
27 int pastetite = 0;
28 int usetabs = 0;
29 int assume_color = 0;
30
31 static int
xlat(int chkasis,int c,int * ap,struct charmap * map)32 xlat(int chkasis, int c, int *ap, struct charmap *map)
33 {
34 if (joe_isprint(map, c))
35 return (c);
36 if (chkasis && dspasis && c >= 128)
37 return (c);
38
39 if (c & 0x80) {
40 c &= 0x7F;
41 *ap ^= INVERSE;
42 }
43 if (c < 0x20 || c == 0x7F) {
44 c ^= 0x40;
45 *ap ^= UNDERLINE;
46 }
47 return (c);
48 }
49
50 /* Set attributes */
51
set_attr(SCRN * t,int c)52 int set_attr(SCRN *t, int c)
53 {
54 int e;
55
56 c &= ~255;
57
58 /* Attributes which have gone off */
59 e = ((AT_MASK|FG_NOT_DEFAULT|BG_NOT_DEFAULT)&t->attrib & ~c);
60
61 if (e) { /* If any attribute go off, switch them all off: fixes bug on PCs */
62 if (t->me)
63 texec(t->cap, t->me, 1, 0, 0, 0, 0);
64 else {
65 if (t->ue)
66 texec(t->cap, t->ue, 1, 0, 0, 0, 0);
67 if (t->se)
68 texec(t->cap, t->se, 1, 0, 0, 0, 0);
69 }
70 t->attrib = 0;
71 }
72
73 /* Attributes which have turned on */
74 e = (c & ~t->attrib);
75
76 if (e & INVERSE) {
77 if (t->mr)
78 texec(t->cap, t->mr, 1, 0, 0, 0, 0);
79 else if (t->so)
80 texec(t->cap, t->so, 1, 0, 0, 0, 0);
81 }
82
83 if (e & UNDERLINE)
84 if (t->us)
85 texec(t->cap, t->us, 1, 0, 0, 0, 0);
86 if (e & BLINK)
87 if (t->mb)
88 texec(t->cap, t->mb, 1, 0, 0, 0, 0);
89 if (e & BOLD)
90 if (t->md)
91 texec(t->cap, t->md, 1, 0, 0, 0, 0);
92 if (e & DIM)
93 if (t->mh)
94 texec(t->cap, t->mh, 1, 0, 0, 0, 0);
95
96 if ((t->attrib&FG_MASK)!=(c&FG_MASK))
97 if (t->Sf) texec(t->cap,t->Sf,1,7-(((c&FG_VALUE)>>FG_SHIFT)),0,0,0);
98
99 if ((t->attrib&BG_MASK)!=(c&BG_MASK))
100 if (t->Sb) texec(t->cap,t->Sb,1,((c&BG_VALUE)>>BG_SHIFT),0,0,0);
101
102 t->attrib = c;
103
104 return 0;
105 }
106
107 /* Output character with attributes */
108
109 void
outatr_help(SCRN * t,int * scrn,int * attrf,int xx,int yy,int c,int a)110 outatr_help(SCRN *t, int *scrn, int *attrf, int xx, int yy, int c, int a)
111 {
112 /* kludge for help_display() only */
113 if (locale_map->type)
114 c = xlat(0, c, &a, locale_map);
115 outatr(locale_map, t, scrn, attrf, xx, yy, c, a);
116 }
117
118 void
outatr(struct charmap * map,SCRN * t,int * scrn,int * attrf,int xx,int yy,int c,int a)119 outatr(struct charmap *map, SCRN *t, int *scrn, int *attrf, int xx, int yy, int c, int a)
120 {
121 int wid = 1;
122
123 if (locale_map->type) {
124 /* to UTF-8 terminal */
125 if (map->type) {
126 /* from UTF-8 file */
127 switch ((wid = unictrl(c))) {
128 case 0:
129 /* not a control character */
130 wid = joe_wcwidth(c);
131 break;
132 case 1:
133 c ^= 0x40;
134 /* FALLTHROUGH */
135 default:
136 a ^= UNDERLINE;
137 break;
138 }
139 } else {
140 /* from SBCS file */
141 c = to_uni(map, xlat(1, c, &a, map));
142 if (c < 32 || (c >= 0x7F && c < 0xA0)) {
143 c = 0xFFFD;
144 a = (a | UNDERLINE) ^ INVERSE;
145 }
146 }
147 } else {
148 /* to SBCS terminal */
149 if (map->type) {
150 /* from UTF-8 file */
151
152 /* don't convert control chars below 256 */
153 if ((c >= 0x20 && c < 0x7F) || c >= 0xA0) {
154 if (unictrl(c))
155 a ^= UNDERLINE;
156 if ((c = from_uni(locale_map, c)) == -1) {
157 c = '!';
158 a |= UNDERLINE;
159 }
160 }
161 }
162 c = xlat(1, c, &a, locale_map);
163 }
164
165 if (*scrn == c && *attrf == a)
166 return;
167
168 *scrn = c;
169 *attrf = a;
170 if (t->ins)
171 clrins(t);
172 if (t->x != xx || t->y != yy)
173 cpos(t, xx, yy);
174 if (t->attrib != a)
175 set_attr(t, a);
176 if (!locale_map->type) {
177 /* SBCS terminal */
178 ttputc(c);
179 } else if (map->type && *unictrlbuf) {
180 /* UTF-8 control char, masked */
181 ttputs(unictrlbuf);
182 } else {
183 unsigned char buf[7];
184
185 utf8_encode(buf, c);
186 ttputs(buf);
187 if (wid == 0 && xx > 0)
188 attrf[-1] |= HAS_COMBINING;
189 }
190 t->x += wid;
191 while (wid-- > 1) {
192 *++scrn = -1;
193 *++attrf = 0;
194 }
195 }
196
197 /* Set scrolling region */
198
setregn(SCRN * t,int top,int bot)199 static void setregn(SCRN *t, int top, int bot)
200 {
201 if (!t->cs) {
202 t->top = top;
203 t->bot = bot;
204 return;
205 }
206 if (t->top != top || t->bot != bot) {
207 t->top = top;
208 t->bot = bot;
209 texec(t->cap, t->cs, 1, top, bot - 1, 0, 0);
210 t->x = -1;
211 t->y = -1;
212 }
213 }
214
215 /* Enter insert mode */
216
setins(SCRN * t,int x)217 static void setins(SCRN *t, int x)
218 {
219 if (t->ins != 1 && t->im) {
220 t->ins = 1;
221 texec(t->cap, t->im, 1, x, 0, 0, 0);
222 }
223 }
224
225 /* Exit insert mode */
226
clrins(SCRN * t)227 int clrins(SCRN *t)
228 {
229 if (t->ins != 0) {
230 texec(t->cap, t->ei, 1, 0, 0, 0, 0);
231 t->ins = 0;
232 }
233 return 0;
234 }
235
236 /* Erase from given screen coordinate to end of line */
237
eraeol(SCRN * t,int x,int y)238 int eraeol(SCRN *t, int x, int y)
239 {
240 int *s, *ss, *a, *aa;
241 int w = t->co - x - 1; /* Don't worry about last column */
242
243 if (w <= 0)
244 return 0;
245 s = t->scrn + y * t->co + x;
246 a = t->attr + y * t->co + x;
247 ss = s + w;
248 aa = a + w;
249 do {
250 if (*--ss != ' ') {
251 ++ss;
252 break;
253 } else if (*--aa != 0) {
254 ++ss;
255 ++aa;
256 break;
257 }
258 } while (ss != s);
259 if ((ss - s > 3 || s[w] != ' ' || a[w] != 0) && t->ce) {
260 cpos(t, x, y);
261 set_attr(t, 0);
262 texec(t->cap, t->ce, 1, 0, 0, 0, 0);
263 msetI(s, ' ', w);
264 msetI(a, 0, w);
265 } else if (s != ss) {
266 if (t->ins)
267 clrins(t);
268 if (t->x != x || t->y != y)
269 cpos(t, x, y);
270 if (t->attrib)
271 set_attr(t, 0);
272 while (s != ss) {
273 *s = ' ';
274 *a = 0;
275 ttputc(' ');
276 ++t->x;
277 ++s;
278 ++a;
279 }
280 }
281 return 0;
282 }
283
out(unsigned char * t,unsigned char c)284 static void out(unsigned char *t, unsigned char c)
285 {
286 ttputc(c);
287 }
288
nopen(CAP * cap)289 SCRN *nopen(CAP *cap)
290 {
291 SCRN *t = calloc(1, sizeof(SCRN));
292 int x, y;
293
294 ttopen();
295
296 t->cap = cap;
297 setcap(cap, baud, out, NULL);
298
299 t->li = getnum(t->cap, UC "li");
300 if (t->li < 1)
301 t->li = 24;
302 t->co = getnum(t->cap, UC "co");
303 if (t->co < 2)
304 t->co = 80;
305 x = y = 0;
306 ttgtsz(&x, &y);
307 if (x > 7 && y > 3) {
308 t->li = y;
309 t->co = x;
310 }
311
312 t->haz = getflag(t->cap, UC "hz");
313 t->os = getflag(t->cap, UC "os");
314 t->eo = getflag(t->cap, UC "eo");
315 if (getflag(t->cap, UC "hc"))
316 t->os = 1;
317 if (t->os || getflag(t->cap, UC "ul"))
318 t->ul = 1;
319
320 t->xn = getflag(t->cap, UC "xn");
321 t->am = getflag(t->cap, UC "am");
322
323 t->cl = jgetstr(t->cap, UC "cl");
324 t->cd = jgetstr(t->cap, UC "cd");
325
326 if (!notite) {
327 t->ti = jgetstr(t->cap, UC "ti");
328 t->te = jgetstr(t->cap, UC "te");
329 }
330 if (pastetite && t->cap->paste_on && t->cap->paste_off) {
331 if (notite) {
332 t->ti = t->cap->paste_on;
333 t->te = t->cap->paste_off;
334 } else {
335 size_t n1, n2;
336 char *cp;
337
338 n1 = t->ti ? strlen(t->ti) : 0;
339 n2 = strlen(t->cap->paste_on);
340 cp = malloc(n1 + n2 + 1);
341 if (t->ti)
342 memcpy(cp, t->ti, n1);
343 memcpy(cp + n1, t->cap->paste_on, n2 + 1);
344 t->ti = cp;
345
346 n1 = t->te ? strlen(t->te) : 0;
347 n2 = strlen(t->cap->paste_off);
348 cp = malloc(n1 + n2 + 1);
349 memcpy(cp, t->cap->paste_off, n2 + 1);
350 if (t->te)
351 memcpy(cp + n2, t->te, n1 + 1);
352 t->te = cp;
353 }
354 }
355
356 t->ut = getflag(t->cap, UC "ut");
357 t->Sb = jgetstr(t->cap, UC "AB");
358 if (!t->Sb) t->Sb = jgetstr(t->cap, UC "Sb");
359 t->Sf = jgetstr(t->cap, UC "AF");
360 if (!t->Sf) t->Sf = jgetstr(t->cap, UC "Sf");
361
362 if (!(t->me = jgetstr(t->cap, UC "me")))
363 goto oops;
364 if ((t->mb = jgetstr(t->cap, UC "mb")))
365 t->avattr |= BLINK;
366 if ((t->md = jgetstr(t->cap, UC "md")))
367 t->avattr |= BOLD;
368 if ((t->mh = jgetstr(t->cap, UC "mh")))
369 t->avattr |= DIM;
370 if ((t->mr = jgetstr(t->cap, UC "mr")))
371 t->avattr |= INVERSE;
372 oops:
373
374 if (assume_color && !t->Sf && t->md) {
375 /*
376 * Install colour support if this looks like an ANSI
377 * terminal — that is, it’s got bold with ESC ‘[’…
378 */
379 if (t->md[0] == '\\' && t->md[1] == 'E' && t->md[2] == '[') {
380 t->ut = 1;
381 t->Sf = UC "\\E[3%dm";
382 t->Sb = UC "\\E[4%dm";
383 } else if (t->md[0] == '\033' && t->md[1] == '[') {
384 t->ut = 1;
385 t->Sf = UC "\033[3%p1%dm";
386 t->Sb = UC "\033[4%p1%dm";
387 }
388 }
389
390 if (getnum(t->cap, UC "sg") <= 0 && !t->mr && jgetstr(t->cap, UC "se")) {
391 if ((t->so = jgetstr(t->cap, UC "so")) != NULL)
392 t->avattr |= INVERSE;
393 t->se = jgetstr(t->cap, UC "se");
394 }
395 if (getflag(t->cap, UC "xs") || getflag(t->cap, UC "xt"))
396 t->so = NULL;
397
398 if (getnum(t->cap, UC "ug") <= 0 && jgetstr(t->cap, UC "ue")) {
399 if ((t->us = jgetstr(t->cap, UC "us")) != NULL)
400 t->avattr |= UNDERLINE;
401 t->ue = jgetstr(t->cap, UC "ue");
402 }
403
404 if (!(t->uc = jgetstr(t->cap, UC "uc")))
405 if (t->ul)
406 t->uc = UC "_";
407 if (t->uc)
408 t->avattr |= UNDERLINE;
409
410 t->ms = getflag(t->cap, UC "ms");
411
412 t->da = getflag(t->cap, UC "da");
413 t->db = getflag(t->cap, UC "db");
414 t->cs = jgetstr(t->cap, UC "cs");
415 t->rr = getflag(t->cap, UC "rr");
416 t->sf = jgetstr(t->cap, UC "sf");
417 t->sr = jgetstr(t->cap, UC "sr");
418 t->SF = jgetstr(t->cap, UC "SF");
419 t->SR = jgetstr(t->cap, UC "SR");
420 t->al = jgetstr(t->cap, UC "al");
421 t->dl = jgetstr(t->cap, UC "dl");
422 t->AL = jgetstr(t->cap, UC "AL");
423 t->DL = jgetstr(t->cap, UC "DL");
424 if (!getflag(t->cap, UC "ns") && !t->sf)
425 t->sf = UC "\12";
426
427 if (!getflag(t->cap, UC "in") && baud < 38400) {
428 t->dc = jgetstr(t->cap, UC "dc");
429 t->DC = jgetstr(t->cap, UC "DC");
430 t->dm = jgetstr(t->cap, UC "dm");
431 t->ed = jgetstr(t->cap, UC "ed");
432
433 t->im = jgetstr(t->cap, UC "im");
434 t->ei = jgetstr(t->cap, UC "ei");
435 t->ic = jgetstr(t->cap, UC "ic");
436 t->IC = jgetstr(t->cap, UC "IC");
437 t->ip = jgetstr(t->cap, UC "ip");
438 t->mi = getflag(t->cap, UC "mi");
439 }
440
441 if (jgetstr(t->cap, UC "bc"))
442 t->bs = jgetstr(t->cap, UC "bc");
443 else if (jgetstr(t->cap, UC "le"))
444 t->bs = jgetstr(t->cap, UC "le");
445 if (getflag(t->cap, UC "bs"))
446 t->bs = UC "\10";
447
448 t->cbs = tcost(t->cap, t->bs, 1, 2, 2, 0, 0);
449
450 t->lf = UC "\12";
451 if (jgetstr(t->cap, UC "do"))
452 t->lf = jgetstr(t->cap, UC "do");
453 t->clf = tcost(t->cap, t->lf, 1, 2, 2, 0, 0);
454
455 t->up = jgetstr(t->cap, UC "up");
456 t->cup = tcost(t->cap, t->up, 1, 2, 2, 0, 0);
457
458 t->nd = jgetstr(t->cap, UC "nd");
459
460 t->tw = 8;
461 if (getnum(t->cap, UC "it") > 0)
462 t->tw = getnum(t->cap, UC "it");
463 else if (getnum(t->cap, UC "tw") > 0)
464 t->tw = getnum(t->cap, UC "tw");
465
466 if (!(t->ta = jgetstr(t->cap, UC "ta")))
467 if (getflag(t->cap, UC "pt"))
468 t->ta = UC "\11";
469 t->bt = jgetstr(t->cap, UC "bt");
470 if (getflag(t->cap, UC "xt") || !usetabs) {
471 t->ta = NULL;
472 t->bt = NULL;
473 }
474
475 t->cta = tcost(t->cap, t->ta, 1, 2, 2, 0, 0);
476 t->cbt = tcost(t->cap, t->bt, 1, 2, 2, 0, 0);
477
478 t->ho = jgetstr(t->cap, UC "ho");
479 t->cho = tcost(t->cap, t->ho, 1, 2, 2, 0, 0);
480 t->ll = jgetstr(t->cap, UC "ll");
481 t->cll = tcost(t->cap, t->ll, 1, 2, 2, 0, 0);
482
483 t->cr = UC "\15";
484 if (jgetstr(t->cap, UC "cr"))
485 t->cr = jgetstr(t->cap, UC "cr");
486 if (getflag(t->cap, UC "nc") || getflag(t->cap, UC "xr"))
487 t->cr = NULL;
488 t->ccr = tcost(t->cap, t->cr, 1, 2, 2, 0, 0);
489
490 t->cRI = tcost(t->cap, t->RI = jgetstr(t->cap, UC "RI"), 1, 2, 2, 0, 0);
491 t->cLE = tcost(t->cap, t->LE = jgetstr(t->cap, UC "LE"), 1, 2, 2, 0, 0);
492 t->cUP = tcost(t->cap, t->UP = jgetstr(t->cap, UC "UP"), 1, 2, 2, 0, 0);
493 t->cDO = tcost(t->cap, t->DO = jgetstr(t->cap, UC "DO"), 1, 2, 2, 0, 0);
494 t->cch = tcost(t->cap, t->ch = jgetstr(t->cap, UC "ch"), 1, 2, 2, 0, 0);
495 t->ccv = tcost(t->cap, t->cv = jgetstr(t->cap, UC "cv"), 1, 2, 2, 0, 0);
496 t->ccV = tcost(t->cap, t->cV = jgetstr(t->cap, UC "cV"), 1, 2, 2, 0, 0);
497 t->ccm = tcost(t->cap, t->cm = jgetstr(t->cap, UC "cm"), 1, 2, 2, 0, 0);
498
499 t->cce = tcost(t->cap, t->ce = jgetstr(t->cap, UC "ce"), 1, 2, 2, 0, 0);
500
501 /* Make sure terminal can do absolute positioning */
502 if (t->cm)
503 goto ok;
504 if (t->ch && t->cv)
505 goto ok;
506 if (t->ho && (t->lf || t->DO || t->cv))
507 goto ok;
508 if (t->ll && (t->up || t->UP || t->cv))
509 goto ok;
510 if (t->cr && t->cv)
511 goto ok;
512 leave = 1;
513 ttclose();
514 signrm(0);
515 free(t);
516 fprintf(stderr,"Sorry, your terminal can't do absolute cursor positioning.\nIt's broken\n");
517 return NULL;
518 ok:
519
520 /* Determine if we can scroll */
521 if (((t->sr || t->SR) && (t->sf || t->SF) && t->cs) || ((t->al || t->AL) && (t->dl || t->DL)))
522 t->scroll = 1;
523 else if (baud < 38400)
524 mid = 1;
525
526 /* Determine if we can ins/del within lines */
527 if ((t->im || t->ic || t->IC) && (t->dc || t->DC))
528 t->insdel = 1;
529
530 /* Adjust for high baud rates */
531 if (baud >= 38400) {
532 t->scroll = 0;
533 t->insdel = 0;
534 }
535
536 /* Send out terminal initialisation string */
537 if (t->ti)
538 texec(t->cap, t->ti, 1, 0, 0, 0, 0);
539 if (!skiptop && t->cl)
540 texec(t->cap, t->cl, 1, 0, 0, 0, 0);
541
542 /* Initialise variable screen size-dependent vars */
543 t->htab = ralloc(256, sizeof(struct s_hentry));
544
545 nresize(t, t->co, t->li);
546
547 return t;
548 }
549
550 /* Change size of screen */
551
nresize(SCRN * t,int w,int h)552 void nresize(SCRN *t, int w, int h)
553 {
554 if (h < 4)
555 h = 4;
556 if (w < 8)
557 w = 8;
558 t->li = h;
559 t->co = w;
560 if (notoktomul((size_t)t->li, (size_t)t->co)) {
561 /* who has THAT large screens? */
562 ttabrt(0, "screen too large");
563 exit(255);
564 }
565 if (t->sary)
566 free(t->sary);
567 if (t->updtab)
568 free(t->updtab);
569 if (t->syntab)
570 free(t->syntab);
571 if (t->scrn)
572 free(t->scrn);
573 if (t->attr)
574 free(t->attr);
575 if (t->compose)
576 free(t->compose);
577 if (t->ofst)
578 free(t->ofst);
579 if (t->ary)
580 free(t->ary);
581 t->scrn = ralloc((size_t)t->li * (size_t)t->co, sizeof(int));
582 t->attr = ralloc((size_t)t->li * (size_t)t->co, sizeof(int));
583 t->sary = calloc(t->li, sizeof(int));
584 t->updtab = ralloc((size_t)t->li, sizeof(int));
585 t->syntab = ralloc((size_t)t->li, sizeof(int));
586 t->compose = ralloc((size_t)t->co, sizeof(int));
587 t->ofst = ralloc((size_t)t->co, sizeof(int));
588 t->ary = ralloc((size_t)t->co, sizeof(struct s_hentry));
589
590 if (!t->htab || !t->scrn || !t->attr || !t->sary || !t->updtab ||
591 !t->syntab || !t->compose || !t->ofst || !t->ary) {
592 ttabrt(0, "screen allocation failed");
593 exit(255);
594 }
595
596 nredraw(t);
597 }
598
599 /*
600 * Calculate cost of positioning the cursor using only relative cursor
601 * positioning functions: t->(lf, DO, up, UP, bs, LE, RI, ta, bt) and
602 * rewriting characters (to move right)
603 *
604 * This doesn't use the am and bw capabilities although it probably could.
605 */
606
relcost(register SCRN * t,register int x,register int y,register int ox,register int oy)607 static int relcost(register SCRN *t, register int x, register int y, register int ox, register int oy)
608 {
609 int cost = 0;
610
611 /* If we don't know the cursor position, force use of absolute positioning */
612 if (oy == -1 || ox == -1)
613 return 10000;
614
615 /* First adjust row */
616 if (y > oy) {
617 int dist = y - oy;
618
619 /* Have to go down */
620 if (t->lf) {
621 int mult = dist * t->clf;
622
623 if (dist < 10 && t->cDO < mult)
624 cost += t->cDO;
625 else if (dist >= 10 && t->cDO + 1 < mult)
626 cost += t->cDO + 1;
627 else
628 cost += mult;
629 } else if (t->DO)
630 if (dist < 10)
631 cost += t->cDO;
632 else
633 cost += t->cDO + 1;
634 else
635 return 10000;
636 } else if (y < oy) {
637 int dist = oy - y;
638
639 /* Have to go up */
640 if (t->up) {
641 int mult = dist * t->cup;
642
643 if (dist < 10 && t->cUP < mult)
644 cost += t->cUP;
645 else if (dist >= 10 && t->cUP < mult)
646 cost += t->cUP + 1;
647 else
648 cost += mult;
649 } else if (t->UP)
650 if (dist < 10)
651 cost += t->cUP;
652 else
653 cost += t->cUP + 1;
654 else
655 return 10000;
656 }
657
658 /* Now adjust column */
659
660 /* Use tabs */
661 if (x > ox && t->ta) {
662 int dist = x - ox;
663 int ntabs = (dist + ox % t->tw) / t->tw;
664 int cstunder = x % t->tw + t->cta * ntabs;
665 int cstover;
666
667 if (x + t->tw < t->co && t->bs)
668 cstover = t->cbs * (t->tw - x % t->tw) + t->cta * (ntabs + 1);
669 else
670 cstover = 10000;
671 if (dist < 10 && cstunder < t->cRI && cstunder < x - ox && cstover > cstunder)
672 return cost + cstunder;
673 else if (cstunder < t->cRI + 1 && cstunder < x - ox && cstover > cstunder)
674 return cost + cstunder;
675 else if (dist < 10 && cstover < t->cRI && cstover < x - ox)
676 return cost + cstover;
677 else if (cstover < t->cRI + 1 && cstover < x - ox)
678 return cost + cstover;
679 } else if (x < ox && t->bt) {
680 int dist = ox - x;
681 int ntabs = (dist + t->tw - ox % t->tw) / t->tw;
682 int cstunder, cstover;
683
684 if (t->bs)
685 cstunder = t->cbt * ntabs + t->cbs * (t->tw - x % t->tw);
686 else
687 cstunder = 10000;
688 if (x - t->tw >= 0)
689 cstover = t->cbt * (ntabs + 1) + x % t->tw;
690 else
691 cstover = 10000;
692 if (dist < 10 && cstunder < t->cLE && (t->bs ? cstunder < (ox - x) * t->cbs : 1)
693 && cstover > cstunder)
694 return cost + cstunder;
695 if (cstunder < t->cLE + 1 && (t->bs ? cstunder < (ox - x) * t->cbs : 1)
696 && cstover > cstunder)
697 return cost + cstunder;
698 else if (dist < 10 && cstover < t->cRI && (t->bs ? cstover < (ox - x) * t->cbs : 1))
699 return cost + cstover;
700 else if (cstover < t->cRI + 1 && (t->bs ? cstover < (ox - x) * t->cbs : 1))
701 return cost + cstover;
702 }
703
704 /* Use simple motions */
705 if (x < ox) {
706 int dist = ox - x;
707
708 /* Have to go left */
709 if (t->bs) {
710 int mult = dist * t->cbs;
711
712 if (t->cLE < mult && dist < 10)
713 cost += t->cLE;
714 else if (t->cLE + 1 < mult)
715 cost += t->cLE + 1;
716 else
717 cost += mult;
718 } else if (t->LE)
719 cost += t->cLE;
720 else
721 return 10000;
722 } else if (x > ox) {
723 int dist = x - ox;
724
725 /* Have to go right */
726 /* Hmm.. this should take into account possible attribute changes */
727 if (t->cRI < dist && dist < 10)
728 cost += t->cRI;
729 else if (t->cRI + 1 < dist)
730 cost += t->cRI + 1;
731 else
732 cost += dist;
733 }
734
735 return cost;
736 }
737
738 /* Find optimal set of cursor positioning commands to move from the current
739 * cursor row and column (either or both of which might be unknown) to the
740 * given new row and column and execute them.
741 */
742
cposs(register SCRN * t,register int x,register int y)743 static void cposs(register SCRN *t, register int x, register int y)
744 {
745 register int bestcost, cost;
746 int bestway;
747 int hy;
748 int hl;
749
750 /*
751 * Home y position is usually 0, but it is 'top' if we have
752 * scrolling region relative addressing
753 */
754 if (t->rr) {
755 hy = t->top;
756 hl = t->bot - 1;
757 } else {
758 hy = 0;
759 hl = t->li - 1;
760 }
761
762 /* Assume best way is with only using relative cursor positioning */
763
764 bestcost = relcost(t, x, y, t->x, t->y);
765 bestway = 0;
766
767 /*
768 * Now check if combinations of absolute cursor positioning
769 * functions are better (or necessary in case one or both cursor
770 * positions are unknown)
771 */
772
773 if (t->ccm < bestcost) {
774 cost = tcost(t->cap, t->cm, 1, y, x, 0, 0);
775 if (cost < bestcost) {
776 bestcost = cost;
777 bestway = 6;
778 }
779 }
780 if (t->ccr < bestcost) {
781 cost = relcost(t, x, y, 0, t->y) + t->ccr;
782 if (cost < bestcost) {
783 bestcost = cost;
784 bestway = 1;
785 }
786 }
787 if (t->cho < bestcost) {
788 cost = relcost(t, x, y, 0, hy) + t->cho;
789 if (cost < bestcost) {
790 bestcost = cost;
791 bestway = 2;
792 }
793 }
794 if (t->cll < bestcost) {
795 cost = relcost(t, x, y, 0, hl) + t->cll;
796 if (cost < bestcost) {
797 bestcost = cost;
798 bestway = 3;
799 }
800 }
801 if (t->cch < bestcost && x != t->x) {
802 cost = relcost(t, x, y, x, t->y) + tcost(t->cap, t->ch, 1, x, 0, 0, 0);
803 if (cost < bestcost) {
804 bestcost = cost;
805 bestway = 4;
806 }
807 }
808 if (t->ccv < bestcost && y != t->y) {
809 cost = relcost(t, x, y, t->x, y) + tcost(t->cap, t->cv, 1, y, 0, 0, 0);
810 if (cost < bestcost) {
811 bestcost = cost;
812 bestway = 5;
813 }
814 }
815 if (t->ccV < bestcost) {
816 cost = relcost(t, x, y, 0, y) + tcost(t->cap, t->cV, 1, y, 0, 0, 0);
817 if (cost < bestcost) {
818 bestcost = cost;
819 bestway = 13;
820 }
821 }
822 if (t->cch + t->ccv < bestcost && x != t->x && y != t->y) {
823 cost = tcost(t->cap, t->cv, 1, y - hy, 0, 0, 0) + tcost(t->cap, t->ch, 1, x, 0, 0, 0);
824 if (cost < bestcost) {
825 bestcost = cost;
826 bestway = 7;
827 }
828 }
829 if (t->ccv + t->ccr < bestcost && y != t->y) {
830 cost = tcost(t->cap, t->cv, 1, y, 0, 0, 0) + tcost(t->cap, t->cr, 1, 0, 0, 0, 0) + relcost(t, x, y, 0, y);
831 if (cost < bestcost) {
832 bestcost = cost;
833 bestway = 8;
834 }
835 }
836 if (t->cll + t->cch < bestcost) {
837 cost = tcost(t->cap, t->ll, 1, 0, 0, 0, 0) + tcost(t->cap, t->ch, 1, x, 0, 0, 0) + relcost(t, x, y, x, hl);
838 if (cost < bestcost) {
839 bestcost = cost;
840 bestway = 9;
841 }
842 }
843 if (t->cll + t->ccv < bestcost) {
844 cost = tcost(t->cap, t->ll, 1, 0, 0, 0, 0) + tcost(t->cap, t->cv, 1, y, 0, 0, 0) + relcost(t, x, y, 0, y);
845 if (cost < bestcost) {
846 bestcost = cost;
847 bestway = 10;
848 }
849 }
850 if (t->cho + t->cch < bestcost) {
851 cost = tcost(t->cap, t->ho, 1, 0, 0, 0, 0) + tcost(t->cap, t->ch, 1, x, 0, 0, 0) + relcost(t, x, y, x, hy);
852 if (cost < bestcost) {
853 bestcost = cost;
854 bestway = 11;
855 }
856 }
857 if (t->cho + t->ccv < bestcost) {
858 cost = tcost(t->cap, t->ho, 1, 0, 0, 0, 0) + tcost(t->cap, t->cv, 1, y, 0, 0, 0) + relcost(t, x, y, 0, y);
859 if (cost < bestcost) {
860 /* dead store: bestcost = cost; */
861 bestway = 12;
862 }
863 }
864
865 /*
866 * Do absolute cursor positioning if we don't know the cursor
867 * position or if it is faster than doing only relative cursor
868 * positioning
869 */
870
871 switch (bestway) {
872 case 1:
873 texec(t->cap, t->cr, 1, 0, 0, 0, 0);
874 t->x = 0;
875 break;
876 case 2:
877 texec(t->cap, t->ho, 1, 0, 0, 0, 0);
878 t->x = 0;
879 t->y = hy;
880 break;
881 case 3:
882 texec(t->cap, t->ll, 1, 0, 0, 0, 0);
883 t->x = 0;
884 t->y = hl;
885 break;
886 case 9:
887 texec(t->cap, t->ll, 1, 0, 0, 0, 0);
888 t->x = 0;
889 t->y = hl;
890 goto doch;
891 case 11:
892 texec(t->cap, t->ho, 1, 0, 0, 0, 0);
893 t->x = 0;
894 t->y = hy;
895 /* FALLTHROUGH */
896 doch:
897 /* FALLTHROUGH */
898 case 4:
899 texec(t->cap, t->ch, 1, x, 0, 0, 0);
900 t->x = x;
901 break;
902 case 10:
903 texec(t->cap, t->ll, 1, 0, 0, 0, 0);
904 t->x = 0;
905 t->y = hl;
906 goto docv;
907 case 12:
908 texec(t->cap, t->ho, 1, 0, 0, 0, 0);
909 t->x = 0;
910 t->y = hy;
911 goto docv;
912 case 8:
913 texec(t->cap, t->cr, 1, 0, 0, 0, 0);
914 t->x = 0;
915 /* FALLTHROUGH */
916 docv:
917 /* FALLTHROUGH */
918 case 5:
919 texec(t->cap, t->cv, 1, y, 0, 0, 0);
920 t->y = y;
921 break;
922 case 6:
923 texec(t->cap, t->cm, 1, y, x, 0, 0);
924 t->y = y;
925 t->x = x;
926 break;
927 case 7:
928 texec(t->cap, t->cv, 1, y, 0, 0, 0);
929 t->y = y;
930 texec(t->cap, t->ch, 1, x, 0, 0, 0);
931 t->x = x;
932 break;
933 case 13:
934 texec(t->cap, t->cV, 1, y, 0, 0, 0);
935 t->y = y;
936 t->x = 0;
937 break;
938 }
939
940 /* Use relative cursor position functions if we're not there yet */
941
942 /* First adjust row */
943 if (y > t->y) {
944 /* Have to go down */
945 if (!t->lf || t->cDO < (y - t->y) * t->clf) {
946 texec(t->cap, t->DO, 1, y - t->y, 0, 0, 0);
947 t->y = y;
948 } else
949 while (y > t->y) {
950 texec(t->cap, t->lf, 1, 0, 0, 0, 0);
951 ++t->y;
952 }
953 } else if (y < t->y) {
954 /* Have to go up */
955 if (!t->up || t->cUP < (t->y - y) * t->cup) {
956 texec(t->cap, t->UP, 1, t->y - y, 0, 0, 0);
957 t->y = y;
958 } else
959 while (y < t->y) {
960 texec(t->cap, t->up, 1, 0, 0, 0, 0);
961 --t->y;
962 }
963 }
964
965 /* Use tabs */
966 if (x > t->x && t->ta) {
967 int ntabs = (x - t->x + t->x % t->tw) / t->tw;
968 int cstunder = x % t->tw + t->cta * ntabs;
969 int cstover;
970
971 if (x + t->tw < t->co && t->bs)
972 cstover = t->cbs * (t->tw - x % t->tw) + t->cta * (ntabs + 1);
973 else
974 cstover = 10000;
975 if (cstunder < t->cRI && cstunder < x - t->x && cstover > cstunder) {
976 if (ntabs) {
977 t->x = x - x % t->tw;
978 do {
979 texec(t->cap, t->ta, 1, 0, 0, 0, 0);
980 } while (--ntabs);
981 }
982 } else if (cstover < t->cRI && cstover < x - t->x) {
983 t->x = t->tw + x - x % t->tw;
984 ++ntabs;
985 do {
986 texec(t->cap, t->ta, 1, 0, 0, 0, 0);
987 } while (--ntabs);
988 }
989 } else if (x < t->x && t->bt) {
990 int ntabs = ((t->x + t->tw - 1) - (t->x + t->tw - 1) % t->tw - ((x + t->tw - 1) - (x + t->tw - 1) % t->tw)) / t->tw;
991 int cstunder, cstover;
992
993 if (t->bs)
994 cstunder = t->cbt * ntabs + t->cbs * (t->tw - x % t->tw);
995 else
996 cstunder = 10000;
997 if (x - t->tw >= 0)
998 cstover = t->cbt * (ntabs + 1) + x % t->tw;
999 else
1000 cstover = 10000;
1001 if (cstunder < t->cLE && (t->bs ? cstunder < (t->x - x) * t->cbs : 1)
1002 && cstover > cstunder) {
1003 if (ntabs) {
1004 do {
1005 texec(t->cap, t->bt, 1, 0, 0, 0, 0);
1006 } while (--ntabs);
1007 t->x = x + t->tw - x % t->tw;
1008 }
1009 } else if (cstover < t->cRI && (t->bs ? cstover < (t->x - x) * t->cbs : 1)) {
1010 t->x = x - x % t->tw;
1011 ++ntabs;
1012 do {
1013 texec(t->cap, t->bt, 1, 0, 0, 0, 0);
1014 } while (--ntabs);
1015 }
1016 }
1017
1018 /* Now adjust column */
1019 if (x < t->x) {
1020 /* Have to go left */
1021 if (!t->bs || t->cLE < (t->x - x) * t->cbs) {
1022 texec(t->cap, t->LE, 1, t->x - x, 0, 0, 0);
1023 t->x = x;
1024 } else
1025 while (x < t->x) {
1026 texec(t->cap, t->bs, 1, 0, 0, 0, 0);
1027 --t->x;
1028 }
1029 } else if (x > t->x) {
1030 /* Have to go right */
1031 /* Hmm.. this should take into account possible attribute changes */
1032 if (x-t->x>1 && t->RI) {
1033 texec(t->cap, t->RI, 1, x - t->x, 0, 0, 0);
1034 t->x = x;
1035 } else {
1036 while(x>t->x) {
1037 texec(t->cap, t->nd, 1, 0, 0, 0, 0);
1038 ++t->x;
1039 }
1040 }
1041 }
1042 }
1043
cpos(register SCRN * t,register int x,register int y)1044 int cpos(register SCRN *t, register int x, register int y)
1045 {
1046 /* Move cursor quickly if we can */
1047 if (y == t->y) {
1048 if (x > t->x && x - t->x < 4 && !t->ins) {
1049 int *cs = t->scrn + t->x + t->co * t->y;
1050 int *as = t->attr + t->x + t->co * t->y;
1051 do {
1052 /* We used to space over unknown chars, but they now could be
1053 the right half of a UTF-8 two column character, so we can't.
1054 Also do not try to emit utf-8 sequences here. */
1055 if(*cs<32 || *cs>=127)
1056 break;
1057
1058 /* has a combining character attached? */
1059 if (*as & HAS_COMBINING)
1060 break;
1061
1062 if (*as != t->attrib)
1063 set_attr(t, *as);
1064
1065 ttputc(*cs);
1066
1067 ++cs;
1068 ++as;
1069 ++t->x;
1070
1071 } while (x != t->x);
1072 }
1073 if (x == t->x)
1074 return 0;
1075 }
1076 if ((!t->ms && t->attrib & (INVERSE | UNDERLINE | BG_NOT_DEFAULT)) ||
1077 (t->ut && (t->attrib & BG_NOT_DEFAULT)))
1078 set_attr(t, t->attrib & ~(INVERSE | UNDERLINE | BG_MASK));
1079
1080 /* Should be in cposs */
1081 if (y < t->top || y >= t->bot)
1082 setregn(t, 0, t->li);
1083
1084 cposs(t, x, y);
1085 return 0;
1086 }
1087
doinschr(SCRN * t,int x,int y,int * s,int * as,int n)1088 static void doinschr(SCRN *t, int x, int y, int *s, int *as, int n)
1089 {
1090 int a;
1091
1092 if (x < 0) {
1093 s -= x;
1094 as -= x;
1095 x = 0;
1096 }
1097 if (x >= t->co - 1 || n <= 0)
1098 return;
1099 if (t->im || t->ic || t->IC) {
1100 cpos(t, x, y);
1101 if ((n == 1 && t->ic) || !t->IC) {
1102 if (!t->ic)
1103 setins(t, x);
1104 for (a = 0; a != n; ++a) {
1105 texec(t->cap, t->ic, 1, x, 0, 0, 0);
1106 texec(t->cap, t->ip, 1, x, 0, 0, 0);
1107 }
1108 if (!t->mi)
1109 clrins(t);
1110 } else {
1111 texec(t->cap, t->IC, 1, n, 0, 0, 0);
1112 }
1113 }
1114 mmove(t->scrn + x + t->co * y + n, t->scrn + x + t->co * y, (t->co - (x + n)) * sizeof(int));
1115 mmove(t->attr + x + t->co * y + n, t->attr + x + t->co * y, (t->co - (x + n)) * sizeof(int));
1116 mmove(t->scrn + x + t->co * y, s, n * sizeof(int));
1117 mmove(t->attr + x + t->co * y, s, n * sizeof(int));
1118 }
1119
dodelchr(SCRN * t,int x,int y,int n)1120 static void dodelchr(SCRN *t, int x, int y, int n)
1121 {
1122 int a;
1123
1124 if (x < 0)
1125 x = 0;
1126 if (!n || x >= t->co - 1)
1127 return;
1128 if (t->dc || t->DC) {
1129 cpos(t, x, y);
1130 texec(t->cap, t->dm, 1, x, 0, 0, 0); /* Enter delete mode */
1131 if ((n == 1 && t->dc) || !t->DC)
1132 for (a = n; a; --a)
1133 texec(t->cap, t->dc, 1, x, 0, 0, 0);
1134 else
1135 texec(t->cap, t->DC, 1, n, 0, 0, 0);
1136 texec(t->cap, t->ed, 1, x, 0, 0, 0); /* Exit delete mode */
1137 }
1138 mmove(t->scrn + t->co * y + x, t->scrn + t->co * y + x + n, (t->co - (x + n)) * sizeof(int));
1139 mmove(t->attr + t->co * y + x, t->attr + t->co * y + x + n, (t->co - (x + n)) * sizeof(int));
1140 msetI(t->scrn + t->co * y + t->co - n, ' ', n);
1141 msetI(t->attr + t->co * y + t->co - n, 0, n);
1142 }
1143
1144 /* Insert/Delete within line */
1145 /* FIXME: doesn't know about attr */
1146
magic(SCRN * t,int y,int * cs,int * ca,int * s,int * a,int placex)1147 void magic(SCRN *t, int y, int *cs, int *ca,int *s, int *a, int placex)
1148 {
1149 struct s_hentry *htab = t->htab;
1150 int *ofst = t->ofst;
1151 int aryx = 1;
1152 int x;
1153
1154 if (!(t->im || t->ic || t->IC) || !(t->dc || t->DC))
1155 return;
1156 mset(htab, 0, 256 * sizeof(struct s_hentry));
1157
1158 msetI(ofst, 0, t->co);
1159
1160 /* Build hash table */
1161 for (x = 0; x != t->co - 1; ++x) {
1162 t->ary[aryx].next = htab[cs[x] & 255].next;
1163 t->ary[aryx].loc = x;
1164 ++htab[cs[x] & 255].loc;
1165 htab[cs[x] & 255].next = aryx++;
1166 }
1167
1168 /* Build offset table */
1169 for (x = 0; x < t->co - 1;)
1170 if (htab[s[x] & 255].loc >= 15)
1171 ofst[x++] = t->co - 1;
1172 else {
1173 int aryy;
1174 int maxaryy = 0;
1175 int maxlen = 0;
1176 int best = 0;
1177 int bestback = 0;
1178 int z;
1179
1180 for (aryy = htab[s[x] & 255].next; aryy; aryy = t->ary[aryy].next) {
1181 int amnt, back;
1182 int tsfo = t->ary[aryy].loc - x;
1183 int cst = -abs(tsfo);
1184 int pre = 32;
1185
1186 for (amnt = 0; x + amnt < t->co - 1 && x + tsfo + amnt < t->co - 1; ++amnt) {
1187 if (cs[x + tsfo + amnt] != s[x + amnt])
1188 break;
1189 else if ((s[x + amnt] & 255) != 32 || pre != 32)
1190 ++cst;
1191 pre = s[x + amnt] & 255;
1192 }
1193 pre = 32;
1194 for (back = 0; back + x > 0 && back + tsfo + x > 0; --back) {
1195 if (cs[x + tsfo + back - 1] != s[x + back - 1])
1196 break;
1197 else if ((s[x + back - 1] & 255) != 32 || pre != 32)
1198 ++cst;
1199 pre = s[x + back - 1] & 255;
1200 }
1201 if (cst > best) {
1202 maxaryy = aryy;
1203 maxlen = amnt;
1204 best = cst;
1205 bestback = back;
1206 }
1207 }
1208 if (!maxlen) {
1209 ofst[x] = t->co - 1;
1210 maxlen = 1;
1211 } else if (best < 2)
1212 for (z = 0; z != maxlen; ++z)
1213 ofst[x + z] = t->co - 1;
1214 else
1215 for (z = 0; z != maxlen - bestback; ++z)
1216 ofst[x + z + bestback] = t->ary[maxaryy].loc - x;
1217 x += maxlen;
1218 }
1219
1220 /* Apply scrolling commands */
1221
1222 for (x = 0; x != t->co - 1; ++x) {
1223 int q = ofst[x];
1224
1225 if (q && q != t->co - 1) {
1226 if (q > 0) {
1227 int z, fu;
1228
1229 for (z = x; z != t->co - 1 && ofst[z] == q; ++z)
1230 ;
1231 while (s[x] == cs[x] && x < placex)
1232 ++x;
1233 dodelchr(t, x, y, q);
1234 for (fu = x; fu != t->co - 1; ++fu)
1235 if (ofst[fu] != t->co - 1)
1236 ofst[fu] -= q;
1237 x = z - 1;
1238 } else {
1239 int z, fu;
1240
1241 for (z = x; z != t->co - 1 && ofst[z] == q; ++z)
1242 ;
1243 while (s[x + q] == cs[x + q] && x - q < placex)
1244 ++x;
1245 doinschr(t, x + q, y, s + x + q, a + x + q, -q);
1246 for (fu = x; fu != t->co - 1; ++fu)
1247 if (ofst[fu] != t->co - 1)
1248 ofst[fu] -= q;
1249 x = z - 1;
1250 }
1251 }
1252 }
1253 }
1254
doupscrl(SCRN * t,int top,int bot,int amnt)1255 static void doupscrl(SCRN *t, int top, int bot, int amnt)
1256 {
1257 int a = amnt;
1258
1259 if (!amnt)
1260 return;
1261 set_attr(t, 0);
1262 if (top == 0 && bot == t->li && (t->sf || t->SF)) {
1263 setregn(t, 0, t->li);
1264 cpos(t, 0, t->li - 1);
1265 if ((amnt == 1 && t->sf) || !t->SF)
1266 while (a--)
1267 texec(t->cap, t->sf, 1, t->li - 1, 0, 0, 0);
1268 else
1269 texec(t->cap, t->SF, a, a, 0, 0, 0);
1270 goto done;
1271 }
1272 if (bot == t->li && (t->dl || t->DL)) {
1273 setregn(t, 0, t->li);
1274 cpos(t, 0, top);
1275 if ((amnt == 1 && t->dl) || !t->DL)
1276 while (a--)
1277 texec(t->cap, t->dl, 1, top, 0, 0, 0);
1278 else
1279 texec(t->cap, t->DL, a, a, 0, 0, 0);
1280 goto done;
1281 }
1282 if (t->cs && (t->sf || t->SF)) {
1283 setregn(t, top, bot);
1284 cpos(t, 0, bot - 1);
1285 if ((amnt == 1 && t->sf) || !t->SF)
1286 while (a--)
1287 texec(t->cap, t->sf, 1, bot - 1, 0, 0, 0);
1288 else
1289 texec(t->cap, t->SF, a, a, 0, 0, 0);
1290 goto done;
1291 }
1292 if ((t->dl || t->DL) && (t->al || t->AL)) {
1293 cpos(t, 0, top);
1294 if ((amnt == 1 && t->dl) || !t->DL)
1295 while (a--)
1296 texec(t->cap, t->dl, 1, top, 0, 0, 0);
1297 else
1298 texec(t->cap, t->DL, a, a, 0, 0, 0);
1299 a = amnt;
1300 cpos(t, 0, bot - amnt);
1301 if ((amnt == 1 && t->al) || !t->AL)
1302 while (a--)
1303 texec(t->cap, t->al, 1, bot - amnt, 0, 0, 0);
1304 else
1305 texec(t->cap, t->AL, a, a, 0, 0, 0);
1306 goto done;
1307 }
1308 msetI(t->updtab + top, 1, bot - top);
1309 msetI(t->syntab + top, -1, bot - top);
1310 return;
1311
1312 done:
1313 mmove(t->scrn + top * t->co, t->scrn + (top + amnt) * t->co, (bot - top - amnt) * t->co * sizeof(int));
1314 mmove(t->attr + top * t->co, t->attr + (top + amnt) * t->co, (bot - top - amnt) * t->co * sizeof(int));
1315
1316 if (bot == t->li && t->db) {
1317 msetI(t->scrn + (t->li - amnt) * t->co, -1, amnt * t->co);
1318 msetI(t->attr + (t->li - amnt) * t->co, 0, amnt * t->co);
1319 msetI(t->updtab + t->li - amnt, 1, amnt);
1320 msetI(t->syntab + t->li - amnt, -1, amnt);
1321 } else {
1322 msetI(t->scrn + (bot - amnt) * t->co, ' ', amnt * t->co);
1323 msetI(t->attr + (bot - amnt) * t->co, 0, amnt * t->co);
1324 }
1325 }
1326
dodnscrl(SCRN * t,int top,int bot,int amnt)1327 static void dodnscrl(SCRN *t, int top, int bot, int amnt)
1328 {
1329 int a = amnt;
1330
1331 if (!amnt)
1332 return;
1333 set_attr(t, 0);
1334 if (top == 0 && bot == t->li && (t->sr || t->SR)) {
1335 setregn(t, 0, t->li);
1336 cpos(t, 0, 0);
1337 if ((amnt == 1 && t->sr) || !t->SR)
1338 while (a--)
1339 texec(t->cap, t->sr, 1, 0, 0, 0, 0);
1340 else
1341 texec(t->cap, t->SR, a, a, 0, 0, 0);
1342 goto done;
1343 }
1344 if (bot == t->li && (t->al || t->AL)) {
1345 setregn(t, 0, t->li);
1346 cpos(t, 0, top);
1347 if ((amnt == 1 && t->al) || !t->AL)
1348 while (a--)
1349 texec(t->cap, t->al, 1, top, 0, 0, 0);
1350 else
1351 texec(t->cap, t->AL, a, a, 0, 0, 0);
1352 goto done;
1353 }
1354 if (t->cs && (t->sr || t->SR)) {
1355 setregn(t, top, bot);
1356 cpos(t, 0, top);
1357 if ((amnt == 1 && t->sr) || !t->SR)
1358 while (a--)
1359 texec(t->cap, t->sr, 1, top, 0, 0, 0);
1360 else
1361 texec(t->cap, t->SR, a, a, 0, 0, 0);
1362 goto done;
1363 }
1364 if ((t->dl || t->DL) && (t->al || t->AL)) {
1365 cpos(t, 0, bot - amnt);
1366 if ((amnt == 1 && t->dl) || !t->DL)
1367 while (a--)
1368 texec(t->cap, t->dl, 1, bot - amnt, 0, 0, 0);
1369 else
1370 texec(t->cap, t->DL, a, a, 0, 0, 0);
1371 a = amnt;
1372 cpos(t, 0, top);
1373 if ((amnt == 1 && t->al) || !t->AL)
1374 while (a--)
1375 texec(t->cap, t->al, 1, top, 0, 0, 0);
1376 else
1377 texec(t->cap, t->AL, a, a, 0, 0, 0);
1378 goto done;
1379 }
1380 msetI(t->updtab + top, 1, bot - top);
1381 msetI(t->syntab + top, -1, bot - top);
1382 return;
1383 done:
1384 mmove(t->scrn + (top + amnt) * t->co, t->scrn + top * t->co, (bot - top - amnt) * t->co * sizeof(int));
1385 mmove(t->attr + (top + amnt) * t->co, t->attr + top * t->co, (bot - top - amnt) * t->co * sizeof(int));
1386
1387 if (!top && t->da) {
1388 msetI(t->scrn, -1, amnt * t->co);
1389 msetI(t->attr, 0, amnt * t->co);
1390 msetI(t->updtab, 1, amnt);
1391 msetI(t->syntab, -1, amnt);
1392 } else {
1393 msetI(t->scrn + t->co * top, ' ', amnt * t->co);
1394 msetI(t->attr + t->co * top, 0, amnt * t->co);
1395 }
1396 }
1397
nscroll(SCRN * t)1398 void nscroll(SCRN *t)
1399 {
1400 int y, z, q, r, p;
1401
1402 for (y = 0; y != t->li; ++y) {
1403 q = t->sary[y];
1404 if (have)
1405 return;
1406 if (q && q != t->li) {
1407 if (q > 0) {
1408 for (z = y; z != t->li && t->sary[z] == q; ++z)
1409 t->sary[z] = 0;
1410 doupscrl(t, y, z + q, q);
1411 y = z - 1;
1412 } else {
1413 for (r = y; r != t->li && (t->sary[r] < 0 || t->sary[r] == t->li); ++r)
1414 ;
1415 p = r - 1;
1416 do {
1417 q = t->sary[p];
1418 if (q && q != t->li) {
1419 for (z = p; t->sary[z] = 0, (z && t->sary[z - 1] == q); --z)
1420 ;
1421 dodnscrl(t, z + q, p + 1, -q);
1422 p = z + 1;
1423 }
1424 } while (p-- != y);
1425 y = r - 1;
1426 }
1427 }
1428 }
1429 msetI(t->sary, 0, t->li);
1430 }
1431
npartial(SCRN * t)1432 void npartial(SCRN *t)
1433 {
1434 set_attr(t, 0);
1435 clrins(t);
1436 setregn(t, 0, t->li);
1437 }
1438
nescape(SCRN * t)1439 void nescape(SCRN *t)
1440 {
1441 npartial(t);
1442 cpos(t, 0, t->li - 1);
1443 eraeol(t, 0, t->li - 1);
1444 if (t->te)
1445 texec(t->cap, t->te, 1, 0, 0, 0, 0);
1446 }
1447
nreturn(SCRN * t)1448 void nreturn(SCRN *t)
1449 {
1450 if (t->ti)
1451 texec(t->cap, t->ti, 1, 0, 0, 0, 0);
1452 if (!skiptop && t->cl)
1453 texec(t->cap, t->cl, 1, 0, 0, 0, 0);
1454 nredraw(t);
1455 }
1456
nclose(SCRN * t)1457 void nclose(SCRN *t)
1458 {
1459 leave = 1;
1460 set_attr(t, 0);
1461 clrins(t);
1462 setregn(t, 0, t->li);
1463 cpos(t, 0, t->li - 1);
1464 if (t->te)
1465 texec(t->cap, t->te, 1, 0, 0, 0, 0);
1466 ttclose();
1467 rmcap(t->cap);
1468 free(t->scrn);
1469 free(t->attr);
1470 free(t->sary);
1471 free(t->ofst);
1472 free(t->htab);
1473 free(t->ary);
1474 free(t);
1475 }
1476
nscrldn(SCRN * t,int top,int bot,int amnt)1477 void nscrldn(SCRN *t, int top, int bot, int amnt)
1478 {
1479 int x;
1480
1481 if (!amnt || top >= bot || bot > t->li)
1482 return;
1483 if ((amnt < bot - top && bot - top - amnt < amnt / 2) || !t->scroll)
1484 amnt = bot - top;
1485 if (amnt < bot - top) {
1486 for (x = bot; x != top + amnt; --x) {
1487 t->sary[x - 1] = (t->sary[x - amnt - 1] == t->li ? t->li : t->sary[x - amnt - 1] - amnt);
1488 t->updtab[x - 1] = t->updtab[x - amnt - 1];
1489 t->syntab[x - 1] = t->syntab[x - amnt - 1];
1490 }
1491 for (x = top; x != top + amnt; ++x) {
1492 t->updtab[x] = 1;
1493 t->syntab[x] = -1;
1494 }
1495 }
1496 if (amnt > bot - top)
1497 amnt = bot - top;
1498 msetI(t->sary + top, t->li, amnt);
1499 if (amnt == bot - top) {
1500 msetI(t->updtab + top, 1, amnt);
1501 msetI(t->syntab + top, -1, amnt);
1502 }
1503 }
1504
nscrlup(SCRN * t,int top,int bot,int amnt)1505 void nscrlup(SCRN *t, int top, int bot, int amnt)
1506 {
1507 int x;
1508
1509 if (!amnt || top >= bot || bot > t->li)
1510 return;
1511 if ((amnt < bot - top && bot - top - amnt < amnt / 2) || !t->scroll)
1512 amnt = bot - top;
1513 if (amnt < bot - top) {
1514 for (x = top + amnt; x != bot; ++x) {
1515 t->sary[x - amnt] = (t->sary[x] == t->li ? t->li : t->sary[x] + amnt);
1516 t->updtab[x - amnt] = t->updtab[x];
1517 t->syntab[x - amnt] = t->syntab[x];
1518 }
1519 for (x = bot - amnt; x != bot; ++x) {
1520 t->updtab[x] = 1;
1521 t->syntab[x] = -1;
1522 }
1523 }
1524 if (amnt > bot - top)
1525 amnt = bot - top;
1526 msetI(t->sary + bot - amnt, t->li, amnt);
1527 if (amnt == bot - top) {
1528 msetI(t->updtab + bot - amnt, 1, amnt);
1529 msetI(t->syntab + bot - amnt, -1, amnt);
1530 }
1531 }
1532
1533 extern volatile int dostaupd;
1534
nredraw(SCRN * t)1535 void nredraw(SCRN *t)
1536 {
1537 dostaupd = 1;
1538 msetI(t->scrn, ' ', t->co * skiptop);
1539 msetI(t->attr, 0, t->co * skiptop);
1540 msetI(t->scrn + skiptop * t->co, -1, (t->li - skiptop) * t->co);
1541 msetI(t->attr + skiptop * t->co, 0, (t->li - skiptop) * t->co);
1542 msetI(t->sary, 0, t->li);
1543 msetI(t->updtab + skiptop, -1, t->li - skiptop);
1544 msetI(t->syntab + skiptop, -1, t->li - skiptop);
1545 t->x = -1;
1546 t->y = -1;
1547 t->top = t->li;
1548 t->bot = 0;
1549 t->attrib = -1;
1550 t->ins = -1;
1551 set_attr(t, 0);
1552 clrins(t);
1553 setregn(t, 0, t->li);
1554
1555 if (!skiptop) {
1556 if (t->cl) {
1557 texec(t->cap, t->cl, 1, 0, 0, 0, 0);
1558 t->x = 0;
1559 t->y = 0;
1560 msetI(t->scrn, ' ', t->li * t->co);
1561 msetI(t->attr, 0, t->li * t->co);
1562 } else if (t->cd) {
1563 cpos(t, 0, 0);
1564 texec(t->cap, t->cd, 1, 0, 0, 0, 0);
1565 msetI(t->scrn, ' ', t->li * t->co);
1566 msetI(t->attr, 0, t->li * t->co);
1567 }
1568 }
1569 }
1570
1571 /* Convert color/attribute name into internal code */
1572
meta_color(unsigned char * s)1573 int meta_color(unsigned char *s)
1574 {
1575 if(!strcmp((char *)s,"inverse"))
1576 return INVERSE;
1577 else if(!strcmp((char *)s,"underline"))
1578 return UNDERLINE;
1579 else if(!strcmp((char *)s,"bold"))
1580 return BOLD;
1581 else if(!strcmp((char *)s,"blink"))
1582 return BLINK;
1583 else if(!strcmp((char *)s,"dim"))
1584 return DIM;
1585 else if(!strcmp((char *)s,"white"))
1586 return FG_WHITE;
1587 else if(!strcmp((char *)s,"cyan"))
1588 return FG_CYAN;
1589 else if(!strcmp((char *)s,"magenta"))
1590 return FG_MAGENTA;
1591 else if(!strcmp((char *)s,"blue"))
1592 return FG_BLUE;
1593 else if(!strcmp((char *)s,"yellow"))
1594 return FG_YELLOW;
1595 else if(!strcmp((char *)s,"green"))
1596 return FG_GREEN;
1597 else if(!strcmp((char *)s,"red"))
1598 return FG_RED;
1599 else if(!strcmp((char *)s,"black"))
1600 return FG_BLACK;
1601 else if(!strcmp((char *)s,"bg_white"))
1602 return BG_WHITE;
1603 else if(!strcmp((char *)s,"bg_cyan"))
1604 return BG_CYAN;
1605 else if(!strcmp((char *)s,"bg_magenta"))
1606 return BG_MAGENTA;
1607 else if(!strcmp((char *)s,"bg_blue"))
1608 return BG_BLUE;
1609 else if(!strcmp((char *)s,"bg_yellow"))
1610 return BG_YELLOW;
1611 else if(!strcmp((char *)s,"bg_green"))
1612 return BG_GREEN;
1613 else if(!strcmp((char *)s,"bg_red"))
1614 return BG_RED;
1615 else if(!strcmp((char *)s,"bg_black"))
1616 return BG_BLACK;
1617 else
1618 return 0;
1619 }
1620
1621 /* Generate a field
1622 *
1623 * 't' is SCRN to write to.
1624 * 'scrn' is address of field in character buffer
1625 * 'attr' is address of field in attribute buffer
1626 * 'x', 'y' are starting column and line numbers of field
1627 * 'ofst' is first column within string to display
1628 * 's', 'len' is string to generate in field
1629 * 'atr' is screeen attributes (and color) which should be used
1630 * 'width' is column width of field
1631 * 'flg' if set, erases to end of line
1632 */
1633
genfield(SCRN * t,int * scrn,int * attr,int x,int y,int ofst,unsigned char * s,int len,int atr,int width,int flg,int * fmt)1634 void genfield(SCRN *t,int *scrn,int *attr,int x,int y,int ofst,unsigned char *s,int len,int atr,int width,int flg,int *fmt)
1635 {
1636 int col;
1637 struct utf8_sm sm;
1638 int last_col = x + width;
1639
1640 utf8_init(&sm);
1641
1642 for (col = 0;len != 0 && x < last_col; len--) {
1643 int c = *s++;
1644 int wid = -1;
1645 int my_atr = atr;
1646 if (fmt) my_atr |= *fmt++;
1647 if (locale_map->type) {
1648 /* UTF-8 mode: decode character and determine its width */
1649 c = utf8_decode(&sm,c);
1650 if (c >= 0)
1651 wid = joe_wcwidth(c);
1652 } else {
1653 /* Byte mode: character is one column wide */
1654 wid = 1;
1655 }
1656 if (wid >= 0) {
1657 if (col >= ofst) {
1658 if (x + wid > last_col) {
1659 /* Character crosses end of field, so fill balance of field with '>' characters instead */
1660 while (x < last_col) {
1661 outatr(utf8_map, t, scrn, attr, x, y, '>', my_atr);
1662 ++scrn;
1663 ++attr;
1664 ++x;
1665 }
1666 } else /* if (wid >(=) 0) */ {
1667 /* Emit character */
1668 outatr(locale_map, t, scrn, attr, x, y, c, my_atr);
1669 x += wid;
1670 scrn += wid;
1671 attr += wid;
1672 }
1673 } else if ((col + wid) > ofst) {
1674 /* Wide character crosses left side of field */
1675 wid -= ofst - col;
1676 col = ofst;
1677 while (wid) {
1678 outatr(utf8_map, t, scrn, attr, x, y, '<', my_atr);
1679 ++scrn;
1680 ++attr;
1681 ++x;
1682 ++col;
1683 --wid;
1684 }
1685 } else
1686 col += wid;
1687 }
1688 }
1689 /* Fill balance of field with spaces */
1690 while (x < last_col) {
1691 outatr(utf8_map, t, scrn, attr, x, y, ' ', 0);
1692 ++x;
1693 ++scrn;
1694 ++attr;
1695 }
1696 /* Erase to end of line */
1697 if (flg)
1698 eraeol(t, x, y);
1699 }
1700
1701 /* Width function for above */
1702
txtwidth(unsigned char * s,int len)1703 int txtwidth(unsigned char *s,int len)
1704 {
1705 if (locale_map->type) {
1706 int col=0;
1707 struct utf8_sm sm;
1708 utf8_init(&sm);
1709
1710 while(len--) {
1711 int d = utf8_decode(&sm,*s++);
1712 if (d >= 0)
1713 col += joe_wcwidth(d);
1714 }
1715
1716 return col;
1717 } else
1718 return len;
1719 }
1720
1721 /* Generate text with formatting escape sequences */
1722
genfmt(SCRN * t,int x,int y,int ofst,const unsigned char * s,int flg)1723 void genfmt(SCRN *t, int x, int y, int ofst, const unsigned char *s, int flg)
1724 {
1725 int *scrn = t->scrn + y * t->co + x;
1726 int *attr = t->attr + y * t->co + x;
1727 int atr = 0;
1728 int col = 0;
1729 int c;
1730 struct utf8_sm sm;
1731
1732 utf8_init(&sm);
1733
1734 while ((c = *s++) != '\0')
1735 if (c == '\\') {
1736 switch ((c = *s++) | 0x20) {
1737 case 'u':
1738 atr ^= UNDERLINE;
1739 break;
1740 case 'i':
1741 atr ^= INVERSE;
1742 break;
1743 case 'b':
1744 atr ^= BOLD;
1745 break;
1746 case 'd':
1747 atr ^= DIM;
1748 break;
1749 case 'f':
1750 atr ^= BLINK;
1751 break;
1752 default: {
1753 if (!c)
1754 --s;
1755 else if (col++ >= ofst) {
1756 outatr(locale_map, t, scrn, attr, x, y, (c&0x7F), atr);
1757 ++scrn;
1758 ++attr;
1759 ++x;
1760 }
1761 break;
1762 }
1763 }
1764 } else {
1765 int wid = -1;
1766 if (locale_map->type) {
1767 /* UTF-8 mode: decode character and determine its width */
1768 c = utf8_decode(&sm,c);
1769 if (c >= 0) {
1770 wid = joe_wcwidth(c);
1771 }
1772 } else {
1773 /* Byte mode: character is one column wide */
1774 wid = 1;
1775 }
1776
1777 if (wid >= 0) {
1778 if (col >= ofst) {
1779 outatr(locale_map, t, scrn, attr, x, y, c, atr);
1780 scrn += wid;
1781 attr += wid;
1782 x += wid;
1783 col += wid;
1784 } else if (col+wid>ofst) {
1785 while (col<ofst) {
1786 ++col;
1787 --wid;
1788 }
1789 while (wid) {
1790 outatr(utf8_map, t, scrn, attr, x, y, '<', atr);
1791 ++scrn;
1792 ++attr;
1793 ++x;
1794 ++col;
1795 --wid;
1796 }
1797 } else
1798 col += wid;
1799 }
1800 }
1801 if (flg)
1802 eraeol(t, x, y);
1803 }
1804
1805 /* Determine column width of string with format codes */
1806
fmtlen(const unsigned char * s)1807 int fmtlen(const unsigned char *s)
1808 {
1809 int col = 0;
1810 struct utf8_sm sm;
1811 int c;
1812
1813 utf8_init(&sm);
1814
1815 while ((c = (*s++))) {
1816 if (c == '\\') {
1817 switch (*s++) {
1818 case 'u':
1819 case 'i':
1820 case 'd':
1821 case 'f':
1822 case 'b':
1823 case 'U':
1824 case 'I':
1825 case 'D':
1826 case 'F':
1827 case 'B':
1828 continue;
1829 case 0:
1830 return col;
1831 default:
1832 ++col;
1833 continue;
1834 }
1835 } else {
1836 int wid = 0;
1837 if(locale_map->type) {
1838 c = utf8_decode(&sm,c);
1839 if (c>=0)
1840 wid = joe_wcwidth(c);
1841 } else {
1842 wid = 1;
1843 }
1844 col += wid;
1845 }
1846 }
1847 return col;
1848 }
1849
1850 /* Return offset within format string which corresponds to a particular
1851 column */
1852
1853 /* FIXME: this is not valid if we land in the middle of a double-wide character */
1854
fmtpos(unsigned char * s,int goal)1855 int fmtpos(unsigned char *s, int goal)
1856 {
1857 unsigned char *org = s;
1858 int col = 0;
1859 int c;
1860 struct utf8_sm sm;
1861
1862 utf8_init(&sm);
1863
1864 while ((c= *s) && col<goal) {
1865 s++;
1866 if (c == '\\') {
1867 switch (*s++) {
1868 case 'u':
1869 case 'i':
1870 case 'd':
1871 case 'f':
1872 case 'b':
1873 case 'U':
1874 case 'I':
1875 case 'D':
1876 case 'F':
1877 case 'B':
1878 continue;
1879 case 0:
1880 --s;
1881 break;
1882 default:
1883 ++col;
1884 continue;
1885 }
1886 } else {
1887 int wid = 0;
1888 if(locale_map->type) {
1889 c = utf8_decode(&sm,c);
1890 if (c>=0)
1891 wid = joe_wcwidth(c);
1892 } else {
1893 wid = 1;
1894 }
1895 col += wid;
1896 }
1897 }
1898
1899 return s - org + goal - col;
1900 }
1901