2 * Device independant TTY interface for JOE
4 * (C) 1992 Joseph H. Allen
6 * This file is part of JOE (Joe's Own Editor)
11 __RCSID("$MirOS: contrib/code/jupp/scrn.c,v 1.30 2017/12/02 04:49:46 tg Exp $");
33 /* How to display characters (especially the control ones) */
34 /* here are characters ... */
35 static const unsigned char xlatc[256] = {
36 64, 65, 66, 67, 68, 69, 70, 71, /* 8 */
37 72, 73, 74, 75, 76, 77, 78, 79, /* 16 */
38 80, 81, 82, 83, 84, 85, 86, 87, /* 24 */
39 88, 89, 90, 91, 92, 93, 94, 95, /* 32 */
40 32, 33, 34, 35, 36, 37, 38, 39, /* 40 */
41 40, 41, 42, 43, 44, 45, 46, 47, /* 48 */
42 48, 49, 50, 51, 52, 53, 54, 55, /* 56 */
43 56, 57, 58, 59, 60, 61, 62, 63, /* 64 */
45 64, 65, 66, 67, 68, 69, 70, 71, /* 72 */
46 72, 73, 74, 75, 76, 77, 78, 79, /* 80 */
47 80, 81, 82, 83, 84, 85, 86, 87, /* 88 */
48 88, 89, 90, 91, 92, 93, 94, 95, /* 96 */
49 96, 97, 98, 99, 100, 101, 102, 103, /* 104 */
50 104, 105, 106, 107, 108, 109, 110, 111, /* 112 */
51 112, 113, 114, 115, 116, 117, 118, 119, /* 120 */
52 120, 121, 122, 123, 124, 125, 126, 63, /* 128 */
54 64, 65, 66, 67, 68, 69, 70, 71, /* 136 */
55 72, 73, 74, 75, 76, 77, 78, 79, /* 144 */
56 80, 81, 82, 83, 84, 85, 86, 87, /* 152 */
57 88, 89, 90, 91, 92, 93, 94, 95, /* 160 */
58 32, 33, 34, 35, 36, 37, 38, 39, /* 168 */
59 40, 41, 42, 43, 44, 45, 46, 47, /* 176 */
60 48, 49, 50, 51, 52, 53, 54, 55, /* 184 */
61 56, 57, 58, 59, 60, 61, 62, 63, /* 192 */
63 64, 65, 66, 67, 68, 69, 70, 71, /* 200 */
64 72, 73, 74, 75, 76, 77, 78, 79, /* 208 */
65 80, 81, 82, 83, 84, 85, 86, 87, /* 216 */
66 88, 89, 90, 91, 92, 93, 94, 95, /* 224 */
67 96, 97, 98, 99, 100, 101, 102, 103, /* 232 */
68 104, 105, 106, 107, 108, 109, 110, 111, /* 240 */
69 112, 113, 114, 115, 116, 117, 118, 119, /* 248 */
70 120, 121, 122, 123, 124, 125, 126, 63 /* 256 */
72 /* ... and here their attributes */
73 static const unsigned short xlata[256] = {
74 UNDERLINE, UNDERLINE, UNDERLINE, UNDERLINE, /* 4 */
75 UNDERLINE, UNDERLINE, UNDERLINE, UNDERLINE, /* 8 */
76 UNDERLINE, UNDERLINE, UNDERLINE, UNDERLINE, /* 12 */
77 UNDERLINE, UNDERLINE, UNDERLINE, UNDERLINE, /* 16 */
78 UNDERLINE, UNDERLINE, UNDERLINE, UNDERLINE, /* 20 */
79 UNDERLINE, UNDERLINE, UNDERLINE, UNDERLINE, /* 24 */
80 UNDERLINE, UNDERLINE, UNDERLINE, UNDERLINE, /* 28 */
81 UNDERLINE, UNDERLINE, UNDERLINE, UNDERLINE, /* 32 */
82 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 48 */
83 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 64 */
84 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 */
85 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 96 */
86 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112 */
87 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, UNDERLINE, /* 128 */
89 INVERSE + UNDERLINE, INVERSE + UNDERLINE, /* 130 */
90 INVERSE + UNDERLINE, INVERSE + UNDERLINE, /* 132 */
91 INVERSE + UNDERLINE, INVERSE + UNDERLINE, /* 134 */
92 INVERSE + UNDERLINE, INVERSE + UNDERLINE, /* 136 */
93 INVERSE + UNDERLINE, INVERSE + UNDERLINE, /* 138 */
94 INVERSE + UNDERLINE, INVERSE + UNDERLINE, /* 140 */
95 INVERSE + UNDERLINE, INVERSE + UNDERLINE, /* 142 */
96 INVERSE + UNDERLINE, INVERSE + UNDERLINE, /* 144 */
97 INVERSE + UNDERLINE, INVERSE + UNDERLINE, /* 146 */
98 INVERSE + UNDERLINE, INVERSE + UNDERLINE, /* 148 */
99 INVERSE + UNDERLINE, INVERSE + UNDERLINE, /* 150 */
100 INVERSE + UNDERLINE, INVERSE + UNDERLINE, /* 152 */
101 INVERSE + UNDERLINE, INVERSE + UNDERLINE, /* 154 */
102 INVERSE + UNDERLINE, INVERSE + UNDERLINE, /* 156 */
103 INVERSE + UNDERLINE, INVERSE + UNDERLINE, /* 158 */
104 INVERSE + UNDERLINE, INVERSE + UNDERLINE, /* 160 */
106 INVERSE, INVERSE, INVERSE, INVERSE, /* 164 */
107 INVERSE, INVERSE, INVERSE, INVERSE, /* 168 */
108 INVERSE, INVERSE, INVERSE, INVERSE, /* 172 */
109 INVERSE, INVERSE, INVERSE, INVERSE, /* 176 */
110 INVERSE, INVERSE, INVERSE, INVERSE, /* 180 */
111 INVERSE, INVERSE, INVERSE, INVERSE, /* 184 */
112 INVERSE, INVERSE, INVERSE, INVERSE, /* 188 */
113 INVERSE, INVERSE, INVERSE, INVERSE, /* 192 */
114 INVERSE, INVERSE, INVERSE, INVERSE, /* 196 */
115 INVERSE, INVERSE, INVERSE, INVERSE, /* 200 */
116 INVERSE, INVERSE, INVERSE, INVERSE, /* 204 */
117 INVERSE, INVERSE, INVERSE, INVERSE, /* 208 */
118 INVERSE, INVERSE, INVERSE, INVERSE, /* 212 */
119 INVERSE, INVERSE, INVERSE, INVERSE, /* 216 */
120 INVERSE, INVERSE, INVERSE, INVERSE, /* 220 */
121 INVERSE, INVERSE, INVERSE, INVERSE, /* 224 */
122 INVERSE, INVERSE, INVERSE, INVERSE, /* 228 */
123 INVERSE, INVERSE, INVERSE, INVERSE, /* 232 */
124 INVERSE, INVERSE, INVERSE, INVERSE, /* 236 */
125 INVERSE, INVERSE, INVERSE, INVERSE, /* 240 */
126 INVERSE, INVERSE, INVERSE, INVERSE, /* 244 */
127 INVERSE, INVERSE, INVERSE, INVERSE, /* 248 */
128 INVERSE, INVERSE, INVERSE, INVERSE, /* 252 */
129 INVERSE, INVERSE, INVERSE, INVERSE + UNDERLINE /* 256 */
134 int set_attr(SCRN *t, int c)
140 /* Attributes which have gone off */
141 e = ((AT_MASK|FG_NOT_DEFAULT|BG_NOT_DEFAULT)&t->attrib & ~c);
143 if (e) { /* If any attribute go off, switch them all off: fixes bug on PCs */
145 texec(t->cap, t->me, 1, 0, 0, 0, 0);
148 texec(t->cap, t->ue, 1, 0, 0, 0, 0);
150 texec(t->cap, t->se, 1, 0, 0, 0, 0);
155 /* Attributes which have turned on */
156 e = (c & ~t->attrib);
160 texec(t->cap, t->mr, 1, 0, 0, 0, 0);
162 texec(t->cap, t->so, 1, 0, 0, 0, 0);
167 texec(t->cap, t->us, 1, 0, 0, 0, 0);
170 texec(t->cap, t->mb, 1, 0, 0, 0, 0);
173 texec(t->cap, t->md, 1, 0, 0, 0, 0);
176 texec(t->cap, t->mh, 1, 0, 0, 0, 0);
178 if ((t->attrib&FG_MASK)!=(c&FG_MASK))
179 if (t->Sf) texec(t->cap,t->Sf,1,7-(((c&FG_VALUE)>>FG_SHIFT)),0,0,0);
181 if ((t->attrib&BG_MASK)!=(c&BG_MASK))
182 if (t->Sb) texec(t->cap,t->Sb,1,((c&BG_VALUE)>>BG_SHIFT),0,0,0);
189 /* Output character with attributes */
191 void outatr_help(SCRN *t,int *scrn,int *attrf,int xx,int yy,int c,int a)
193 /* kludge for help_display() only */
194 if (locale_map->type && !joe_isprint(locale_map,c)) {
198 outatr(locale_map, t, scrn, attrf, xx, yy, c, a);
201 void outatr(struct charmap *map,SCRN *t,int *scrn,int *attrf,int xx,int yy,int c,int a)
204 if(locale_map->type) {
205 /* UTF-8 char to UTF-8 terminal */
208 switch ((wid = unictrl(c))) {
210 /* not a control character */
211 wid = joe_wcwidth(1, c);
221 if(*scrn==c && *attrf==a)
228 if(t->x != xx || t->y != yy)
235 unsigned char buf[7];
239 if (wid == 0 && xx > 0)
240 attrf[-1] |= HAS_COMBINING;
249 /* UTF-8 char to non-UTF-8 terminal */
250 /* Don't convert control chars below 256 */
251 if ((c>=32 && c<=126) || c>=160) {
254 c = from_uni(locale_map,c);
259 /* Deal with control characters */
260 if (!joe_isprint(locale_map,c) && !(dspasis && c>=128)) {
265 if(*scrn==c && *attrf==a)
272 if(t->x != xx || t->y != yy)
280 if (!locale_map->type) {
281 /* Non UTF-8 char to non UTF-8 terminal */
282 /* Byte-byte Translate? */
284 /* Deal with control characters */
285 if (!joe_isprint(locale_map,c) && !(dspasis && c>=128)) {
290 if (*scrn==c && *attrf==a)
298 if(t->x != xx || t->y != yy)
305 /* Non UTF-8 char to UTF-8 terminal */
306 unsigned char buf[7];
309 /* Deal with control characters */
310 if (!(dspasis && c>=128) && !joe_isprint(map,c)) {
316 if (c < 32 || (c >= 0x7F && c < 0xA0)) {
318 a = (a | UNDERLINE) ^ INVERSE;
322 if (*scrn == c && *attrf == a)
325 wid = joe_wcwidth(0,c);
330 if(t->x != xx || t->y != yy)
344 /* Set scrolling region */
346 static void setregn(SCRN *t, int top, int bot)
353 if (t->top != top || t->bot != bot) {
356 texec(t->cap, t->cs, 1, top, bot - 1, 0, 0);
362 /* Enter insert mode */
364 static void setins(SCRN *t, int x)
366 if (t->ins != 1 && t->im) {
368 texec(t->cap, t->im, 1, x, 0, 0, 0);
372 /* Exit insert mode */
377 texec(t->cap, t->ei, 1, 0, 0, 0, 0);
383 /* Erase from given screen coordinate to end of line */
385 int eraeol(SCRN *t, int x, int y)
387 int *s, *ss, *a, *aa;
388 int w = t->co - x - 1; /* Don't worry about last column */
392 s = t->scrn + y * t->co + x;
393 a = t->attr + y * t->co + x;
400 } else if (*--aa != 0) {
406 if ((ss - s > 3 || s[w] != ' ' || a[w] != 0) && t->ce) {
409 texec(t->cap, t->ce, 1, 0, 0, 0, 0);
412 } else if (s != ss) {
415 if (t->x != x || t->y != y)
431 static void out(unsigned char *t, unsigned char c)
436 SCRN *nopen(CAP *cap)
438 SCRN *t = calloc(1, sizeof(SCRN));
444 setcap(cap, baud, out, NULL);
446 t->li = getnum(t->cap,US "li");
449 t->co = getnum(t->cap,US "co");
454 if (x > 7 && y > 3) {
459 t->haz = getflag(t->cap,US "hz");
460 t->os = getflag(t->cap,US "os");
461 t->eo = getflag(t->cap,US "eo");
462 if (getflag(t->cap,US "hc"))
464 if (t->os || getflag(t->cap,US "ul"))
467 t->xn = getflag(t->cap,US "xn");
468 t->am = getflag(t->cap,US "am");
470 t->cl = jgetstr(t->cap,US "cl");
471 t->cd = jgetstr(t->cap,US "cd");
474 t->ti = jgetstr(t->cap,US "ti");
475 t->te = jgetstr(t->cap,US "te");
477 if (pastetite && t->cap->paste_on && t->cap->paste_off) {
479 t->ti = (void *)strdup(t->cap->paste_on);
480 t->te = (void *)strdup(t->cap->paste_off);
485 n1 = t->ti ? strlen(t->ti) : 0;
486 n2 = strlen(t->cap->paste_on);
487 cp = joe_malloc(n1 + n2 + 1);
489 memcpy(cp, t->ti, n1);
490 memcpy(cp + n1, t->cap->paste_on, n2 + 1);
493 n1 = t->te ? strlen(t->te) : 0;
494 n2 = strlen(t->cap->paste_off);
495 cp = joe_malloc(n1 + n2 + 1);
496 memcpy(cp, t->cap->paste_off, n2 + 1);
498 memcpy(cp + n2, t->te, n1 + 1);
503 t->ut = getflag(t->cap,US "ut");
504 t->Sb = jgetstr(t->cap,US "AB");
505 if (!t->Sb) t->Sb = jgetstr(t->cap,US "Sb");
506 t->Sf = jgetstr(t->cap,US "AF");
507 if (!t->Sf) t->Sf = jgetstr(t->cap,US "Sf");
509 if (!(t->me = jgetstr(t->cap,US "me")))
511 if ((t->mb = jgetstr(t->cap,US "mb")))
513 if ((t->md = jgetstr(t->cap,US "md")))
515 if ((t->mh = jgetstr(t->cap,US "mh")))
517 if ((t->mr = jgetstr(t->cap,US "mr")))
518 t->avattr |= INVERSE;
521 if (assume_color && !t->Sf && t->md) {
523 * Install colour support if this looks like an ANSI
524 * terminal — that is, it’s got bold with ESC ‘[’…
526 if (t->md[0] == '\\' && t->md[1] == 'E' && t->md[2] == '[') {
528 t->Sf =US "\\E[3%dm";
529 t->Sb =US "\\E[4%dm";
530 } else if (t->md[0] == '\033' && t->md[1] == '[') {
532 t->Sf =US "\033[3%p1%dm";
533 t->Sb =US "\033[4%p1%dm";
537 if (getnum(t->cap,US "sg") <= 0 && !t->mr && jgetstr(t->cap,US "se")) {
538 if ((t->so = jgetstr(t->cap,US "so")) != NULL)
539 t->avattr |= INVERSE;
540 t->se = jgetstr(t->cap,US "se");
542 if (getflag(t->cap,US "xs") || getflag(t->cap,US "xt"))
545 if (getnum(t->cap,US "ug") <= 0 && jgetstr(t->cap,US "ue")) {
546 if ((t->us = jgetstr(t->cap,US "us")) != NULL)
547 t->avattr |= UNDERLINE;
548 t->ue = jgetstr(t->cap,US "ue");
551 if (!(t->uc = jgetstr(t->cap,US "uc")))
555 t->avattr |= UNDERLINE;
557 t->ms = getflag(t->cap,US "ms");
559 t->da = getflag(t->cap,US "da");
560 t->db = getflag(t->cap,US "db");
561 t->cs = jgetstr(t->cap,US "cs");
562 t->rr = getflag(t->cap,US "rr");
563 t->sf = jgetstr(t->cap,US "sf");
564 t->sr = jgetstr(t->cap,US "sr");
565 t->SF = jgetstr(t->cap,US "SF");
566 t->SR = jgetstr(t->cap,US "SR");
567 t->al = jgetstr(t->cap,US "al");
568 t->dl = jgetstr(t->cap,US "dl");
569 t->AL = jgetstr(t->cap,US "AL");
570 t->DL = jgetstr(t->cap,US "DL");
571 if (!getflag(t->cap,US "ns") && !t->sf)
574 if (!getflag(t->cap,US "in") && baud < 38400) {
575 t->dc = jgetstr(t->cap,US "dc");
576 t->DC = jgetstr(t->cap,US "DC");
577 t->dm = jgetstr(t->cap,US "dm");
578 t->ed = jgetstr(t->cap,US "ed");
580 t->im = jgetstr(t->cap,US "im");
581 t->ei = jgetstr(t->cap,US "ei");
582 t->ic = jgetstr(t->cap,US "ic");
583 t->IC = jgetstr(t->cap,US "IC");
584 t->ip = jgetstr(t->cap,US "ip");
585 t->mi = getflag(t->cap,US "mi");
588 if (jgetstr(t->cap,US "bc"))
589 t->bs = jgetstr(t->cap,US "bc");
590 else if (jgetstr(t->cap,US "le"))
591 t->bs = jgetstr(t->cap,US "le");
592 if (getflag(t->cap,US "bs"))
595 t->cbs = tcost(t->cap, t->bs, 1, 2, 2, 0, 0);
598 if (jgetstr(t->cap,US "do"))
599 t->lf = jgetstr(t->cap,US "do");
600 t->clf = tcost(t->cap, t->lf, 1, 2, 2, 0, 0);
602 t->up = jgetstr(t->cap,US "up");
603 t->cup = tcost(t->cap, t->up, 1, 2, 2, 0, 0);
605 t->nd = jgetstr(t->cap,US "nd");
608 if (getnum(t->cap,US "it") > 0)
609 t->tw = getnum(t->cap,US "it");
610 else if (getnum(t->cap,US "tw") > 0)
611 t->tw = getnum(t->cap,US "tw");
613 if (!(t->ta = jgetstr(t->cap,US "ta")))
614 if (getflag(t->cap,US "pt"))
616 t->bt = jgetstr(t->cap,US "bt");
617 if (getflag(t->cap,US "xt") || !usetabs) {
622 t->cta = tcost(t->cap, t->ta, 1, 2, 2, 0, 0);
623 t->cbt = tcost(t->cap, t->bt, 1, 2, 2, 0, 0);
625 t->ho = jgetstr(t->cap,US "ho");
626 t->cho = tcost(t->cap, t->ho, 1, 2, 2, 0, 0);
627 t->ll = jgetstr(t->cap,US "ll");
628 t->cll = tcost(t->cap, t->ll, 1, 2, 2, 0, 0);
631 if (jgetstr(t->cap,US "cr"))
632 t->cr = jgetstr(t->cap,US "cr");
633 if (getflag(t->cap,US "nc") || getflag(t->cap,US "xr"))
635 t->ccr = tcost(t->cap, t->cr, 1, 2, 2, 0, 0);
637 t->cRI = tcost(t->cap, t->RI = jgetstr(t->cap,US "RI"), 1, 2, 2, 0, 0);
638 t->cLE = tcost(t->cap, t->LE = jgetstr(t->cap,US "LE"), 1, 2, 2, 0, 0);
639 t->cUP = tcost(t->cap, t->UP = jgetstr(t->cap,US "UP"), 1, 2, 2, 0, 0);
640 t->cDO = tcost(t->cap, t->DO = jgetstr(t->cap,US "DO"), 1, 2, 2, 0, 0);
641 t->cch = tcost(t->cap, t->ch = jgetstr(t->cap,US "ch"), 1, 2, 2, 0, 0);
642 t->ccv = tcost(t->cap, t->cv = jgetstr(t->cap,US "cv"), 1, 2, 2, 0, 0);
643 t->ccV = tcost(t->cap, t->cV = jgetstr(t->cap,US "cV"), 1, 2, 2, 0, 0);
644 t->ccm = tcost(t->cap, t->cm = jgetstr(t->cap,US "cm"), 1, 2, 2, 0, 0);
646 t->cce = tcost(t->cap, t->ce = jgetstr(t->cap,US "ce"), 1, 2, 2, 0, 0);
648 /* Make sure terminal can do absolute positioning */
653 if (t->ho && (t->lf || t->DO || t->cv))
655 if (t->ll && (t->up || t->UP || t->cv))
663 /* these are strings, but I do not know if %s is appropriate -mirabilos */
664 fprintf(stderr,"cm=%d ch=%d cv=%d ho=%d lf=%d DO=%d ll=%d up=%d UP=%d cr=%d\n",
665 t->cm, t->ch, t->cv, t->ho, t->lf, t->DO, t->ll, t->up, t->UP, t->cr);
667 fprintf(stderr,"Sorry, your terminal can't do absolute cursor positioning.\nIt's broken\n");
671 /* Determine if we can scroll */
672 if (((t->sr || t->SR) && (t->sf || t->SF) && t->cs) || ((t->al || t->AL) && (t->dl || t->DL)))
674 else if (baud < 38400)
677 /* Determine if we can ins/del within lines */
678 if ((t->im || t->ic || t->IC) && (t->dc || t->DC))
681 /* Adjust for high baud rates */
687 /* Send out terminal initialization string */
689 texec(t->cap, t->ti, 1, 0, 0, 0, 0);
690 if (!skiptop && t->cl)
691 texec(t->cap, t->cl, 1, 0, 0, 0, 0);
693 /* Initialize variable screen size dependant vars */
694 t->htab = calloc(256, sizeof(struct hentry));
696 nresize(t, t->co, t->li);
701 /* Change size of screen */
703 void nresize(SCRN *t, int w, int h)
722 joe_free(t->compose);
727 t->scrn = calloc(t->li * t->co, sizeof(int));
728 t->attr = calloc(t->li * t->co, sizeof(int));
729 t->sary = calloc(t->li, sizeof(int));
730 t->updtab = calloc(t->li, sizeof(int));
731 t->syntab = calloc(t->li, sizeof(int));
732 t->compose = calloc(t->co, sizeof(int));
733 t->ofst = calloc(t->co, sizeof(int));
734 t->ary = calloc(t->co, sizeof(struct hentry));
739 /* Calculate cost of positioning the cursor using only relative cursor
740 * positioning functions: t->(lf, DO, up, UP, bs, LE, RI, ta, bt) and rewriting
741 * characters (to move right)
743 * This doesn't use the am and bw capabilities although it probably could.
746 static int relcost(register SCRN *t, register int x, register int y, register int ox, register int oy)
750 /* If we don't know the cursor position, force use of absolute positioning */
751 if (oy == -1 || ox == -1)
754 /* First adjust row */
758 /* Have to go down */
760 int mult = dist * t->clf;
762 if (dist < 10 && t->cDO < mult)
764 else if (dist >= 10 && t->cDO + 1 < mult)
780 int mult = dist * t->cup;
782 if (dist < 10 && t->cUP < mult)
784 else if (dist >= 10 && t->cUP < mult)
797 /* Now adjust column */
800 if (x > ox && t->ta) {
802 int ntabs = (dist + ox % t->tw) / t->tw;
803 int cstunder = x % t->tw + t->cta * ntabs;
806 if (x + t->tw < t->co && t->bs)
807 cstover = t->cbs * (t->tw - x % t->tw) + t->cta * (ntabs + 1);
810 if (dist < 10 && cstunder < t->cRI && cstunder < x - ox && cstover > cstunder)
811 return cost + cstunder;
812 else if (cstunder < t->cRI + 1 && cstunder < x - ox && cstover > cstunder)
813 return cost + cstunder;
814 else if (dist < 10 && cstover < t->cRI && cstover < x - ox)
815 return cost + cstover;
816 else if (cstover < t->cRI + 1 && cstover < x - ox)
817 return cost + cstover;
818 } else if (x < ox && t->bt) {
820 int ntabs = (dist + t->tw - ox % t->tw) / t->tw;
821 int cstunder, cstover;
824 cstunder = t->cbt * ntabs + t->cbs * (t->tw - x % t->tw);
828 cstover = t->cbt * (ntabs + 1) + x % t->tw;
831 if (dist < 10 && cstunder < t->cLE && (t->bs ? cstunder < (ox - x) * t->cbs : 1)
832 && cstover > cstunder)
833 return cost + cstunder;
834 if (cstunder < t->cLE + 1 && (t->bs ? cstunder < (ox - x) * t->cbs : 1)
835 && cstover > cstunder)
836 return cost + cstunder;
837 else if (dist < 10 && cstover < t->cRI && (t->bs ? cstover < (ox - x) * t->cbs : 1))
838 return cost + cstover;
839 else if (cstover < t->cRI + 1 && (t->bs ? cstover < (ox - x) * t->cbs : 1))
840 return cost + cstover;
843 /* Use simple motions */
847 /* Have to go left */
849 int mult = dist * t->cbs;
851 if (t->cLE < mult && dist < 10)
853 else if (t->cLE + 1 < mult)
864 /* Have to go right */
865 /* Hmm.. this should take into account possible attribute changes */
866 if (t->cRI < dist && dist < 10)
868 else if (t->cRI + 1 < dist)
877 /* Find optimal set of cursor positioning commands to move from the current
878 * cursor row and column (either or both of which might be unknown) to the
879 * given new row and column and execute them.
882 static void cposs(register SCRN *t, register int x, register int y)
884 register int bestcost, cost;
889 /* Home y position is usually 0, but it is 'top' if we have scrolling region
890 * relative addressing
900 /* Assume best way is with only using relative cursor positioning */
902 bestcost = relcost(t, x, y, t->x, t->y);
905 /* Now check if combinations of absolute cursor positioning functions are
906 * better (or necessary in case one or both cursor positions are unknown)
909 if (t->ccm < bestcost) {
910 cost = tcost(t->cap, t->cm, 1, y, x, 0, 0);
911 if (cost < bestcost) {
916 if (t->ccr < bestcost) {
917 cost = relcost(t, x, y, 0, t->y) + t->ccr;
918 if (cost < bestcost) {
923 if (t->cho < bestcost) {
924 cost = relcost(t, x, y, 0, hy) + t->cho;
925 if (cost < bestcost) {
930 if (t->cll < bestcost) {
931 cost = relcost(t, x, y, 0, hl) + t->cll;
932 if (cost < bestcost) {
937 if (t->cch < bestcost && x != t->x) {
938 cost = relcost(t, x, y, x, t->y) + tcost(t->cap, t->ch, 1, x, 0, 0, 0);
939 if (cost < bestcost) {
944 if (t->ccv < bestcost && y != t->y) {
945 cost = relcost(t, x, y, t->x, y) + tcost(t->cap, t->cv, 1, y, 0, 0, 0);
946 if (cost < bestcost) {
951 if (t->ccV < bestcost) {
952 cost = relcost(t, x, y, 0, y) + tcost(t->cap, t->cV, 1, y, 0, 0, 0);
953 if (cost < bestcost) {
958 if (t->cch + t->ccv < bestcost && x != t->x && y != t->y) {
959 cost = tcost(t->cap, t->cv, 1, y - hy, 0, 0, 0) + tcost(t->cap, t->ch, 1, x, 0, 0, 0);
960 if (cost < bestcost) {
965 if (t->ccv + t->ccr < bestcost && y != t->y) {
966 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);
967 if (cost < bestcost) {
972 if (t->cll + t->cch < bestcost) {
973 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);
974 if (cost < bestcost) {
979 if (t->cll + t->ccv < bestcost) {
980 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);
981 if (cost < bestcost) {
986 if (t->cho + t->cch < bestcost) {
987 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);
988 if (cost < bestcost) {
993 if (t->cho + t->ccv < bestcost) {
994 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);
995 if (cost < bestcost) {
996 /* dead store: bestcost = cost; */
1001 /* Do absolute cursor positioning if we don't know the cursor position or
1002 * if it is faster than doing only relative cursor positioning
1007 texec(t->cap, t->cr, 1, 0, 0, 0, 0);
1011 texec(t->cap, t->ho, 1, 0, 0, 0, 0);
1016 texec(t->cap, t->ll, 1, 0, 0, 0, 0);
1021 texec(t->cap, t->ll, 1, 0, 0, 0, 0);
1026 texec(t->cap, t->ho, 1, 0, 0, 0, 0);
1033 texec(t->cap, t->ch, 1, x, 0, 0, 0);
1037 texec(t->cap, t->ll, 1, 0, 0, 0, 0);
1042 texec(t->cap, t->ho, 1, 0, 0, 0, 0);
1047 texec(t->cap, t->cr, 1, 0, 0, 0, 0);
1053 texec(t->cap, t->cv, 1, y, 0, 0, 0);
1057 texec(t->cap, t->cm, 1, y, x, 0, 0);
1062 texec(t->cap, t->cv, 1, y, 0, 0, 0);
1064 texec(t->cap, t->ch, 1, x, 0, 0, 0);
1068 texec(t->cap, t->cV, 1, y, 0, 0, 0);
1074 /* Use relative cursor position functions if we're not there yet */
1076 /* First adjust row */
1078 /* Have to go down */
1079 if (!t->lf || t->cDO < (y - t->y) * t->clf) {
1080 texec(t->cap, t->DO, 1, y - t->y, 0, 0, 0);
1084 texec(t->cap, t->lf, 1, 0, 0, 0, 0);
1087 } else if (y < t->y) {
1089 if (!t->up || t->cUP < (t->y - y) * t->cup) {
1090 texec(t->cap, t->UP, 1, t->y - y, 0, 0, 0);
1094 texec(t->cap, t->up, 1, 0, 0, 0, 0);
1100 if (x > t->x && t->ta) {
1101 int ntabs = (x - t->x + t->x % t->tw) / t->tw;
1102 int cstunder = x % t->tw + t->cta * ntabs;
1105 if (x + t->tw < t->co && t->bs)
1106 cstover = t->cbs * (t->tw - x % t->tw) + t->cta * (ntabs + 1);
1109 if (cstunder < t->cRI && cstunder < x - t->x && cstover > cstunder) {
1111 t->x = x - x % t->tw;
1113 texec(t->cap, t->ta, 1, 0, 0, 0, 0);
1116 } else if (cstover < t->cRI && cstover < x - t->x) {
1117 t->x = t->tw + x - x % t->tw;
1120 texec(t->cap, t->ta, 1, 0, 0, 0, 0);
1123 } else if (x < t->x && t->bt) {
1124 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;
1125 int cstunder, cstover;
1128 cstunder = t->cbt * ntabs + t->cbs * (t->tw - x % t->tw);
1132 cstover = t->cbt * (ntabs + 1) + x % t->tw;
1135 if (cstunder < t->cLE && (t->bs ? cstunder < (t->x - x) * t->cbs : 1)
1136 && cstover > cstunder) {
1139 texec(t->cap, t->bt, 1, 0, 0, 0, 0);
1141 t->x = x + t->tw - x % t->tw;
1143 } else if (cstover < t->cRI && (t->bs ? cstover < (t->x - x) * t->cbs : 1)) {
1144 t->x = x - x % t->tw;
1147 texec(t->cap, t->bt, 1, 0, 0, 0, 0);
1152 /* Now adjust column */
1154 /* Have to go left */
1155 if (!t->bs || t->cLE < (t->x - x) * t->cbs) {
1156 texec(t->cap, t->LE, 1, t->x - x, 0, 0, 0);
1160 texec(t->cap, t->bs, 1, 0, 0, 0, 0);
1163 } else if (x > t->x) {
1164 /* Have to go right */
1165 /* Hmm.. this should take into account possible attribute changes */
1166 if (x-t->x>1 && t->RI) {
1167 texec(t->cap, t->RI, 1, x - t->x, 0, 0, 0);
1171 texec(t->cap, t->nd, 1, 0, 0, 0, 0);
1176 /* if (t->cRI < x - t->x) { */
1178 int *s = t->scrn + t->x + t->y * t->co;
1179 int *a = t->attr + t->x + t->y * t->co;
1185 if(*s==-1) c=' ', atr=0;
1186 else c= *s, atr= *a;
1188 if (atr != t->attrib)
1200 int cpos(register SCRN *t, register int x, register int y)
1202 /* Move cursor quickly if we can */
1204 if (x > t->x && x - t->x < 4 && !t->ins) {
1205 int *cs = t->scrn + t->x + t->co * t->y;
1206 int *as = t->attr + t->x + t->co * t->y;
1208 /* We used to space over unknown chars, but they now could be
1209 the right half of a UTF-8 two column character, so we can't.
1210 Also do not try to emit utf-8 sequences here. */
1211 if(*cs<32 || *cs>=127)
1214 /* has a combining character attached? */
1215 if (*as & HAS_COMBINING)
1218 if (*as != t->attrib)
1227 } while (x != t->x);
1232 if ((!t->ms && t->attrib & (INVERSE | UNDERLINE | BG_NOT_DEFAULT)) ||
1233 (t->ut && (t->attrib & BG_NOT_DEFAULT)))
1234 set_attr(t, t->attrib & ~(INVERSE | UNDERLINE | BG_MASK));
1236 /* Should be in cposs */
1237 if (y < t->top || y >= t->bot)
1238 setregn(t, 0, t->li);
1244 static void doinschr(SCRN *t, int x, int y, int *s, int *as, int n)
1253 if (x >= t->co - 1 || n <= 0)
1255 if (t->im || t->ic || t->IC) {
1257 if ((n == 1 && t->ic) || !t->IC) {
1260 for (a = 0; a != n; ++a) {
1261 texec(t->cap, t->ic, 1, x, 0, 0, 0);
1262 texec(t->cap, t->ip, 1, x, 0, 0, 0);
1267 texec(t->cap, t->IC, 1, n, 0, 0, 0);
1270 mmove(t->scrn + x + t->co * y + n, t->scrn + x + t->co * y, (t->co - (x + n)) * sizeof(int));
1271 mmove(t->attr + x + t->co * y + n, t->attr + x + t->co * y, (t->co - (x + n)) * sizeof(int));
1272 mmove(t->scrn + x + t->co * y, s, n * sizeof(int));
1273 mmove(t->attr + x + t->co * y, s, n * sizeof(int));
1276 static void dodelchr(SCRN *t, int x, int y, int n)
1282 if (!n || x >= t->co - 1)
1284 if (t->dc || t->DC) {
1286 texec(t->cap, t->dm, 1, x, 0, 0, 0); /* Enter delete mode */
1287 if ((n == 1 && t->dc) || !t->DC)
1289 texec(t->cap, t->dc, 1, x, 0, 0, 0);
1291 texec(t->cap, t->DC, 1, n, 0, 0, 0);
1292 texec(t->cap, t->ed, 1, x, 0, 0, 0); /* Exit delete mode */
1294 mmove(t->scrn + t->co * y + x, t->scrn + t->co * y + x + n, (t->co - (x + n)) * sizeof(int));
1295 mmove(t->attr + t->co * y + x, t->attr + t->co * y + x + n, (t->co - (x + n)) * sizeof(int));
1296 msetI(t->scrn + t->co * y + t->co - n, ' ', n);
1297 msetI(t->attr + t->co * y + t->co - n, 0, n);
1300 /* Insert/Delete within line */
1301 /* FIXME: doesn't know about attr */
1303 void magic(SCRN *t, int y, int *cs, int *ca,int *s, int *a, int placex)
1305 struct hentry *htab = t->htab;
1306 int *ofst = t->ofst;
1310 if (!(t->im || t->ic || t->IC) || !(t->dc || t->DC))
1312 mset(htab, 0, 256 * sizeof(struct hentry));
1314 msetI(ofst, 0, t->co);
1316 /* Build hash table */
1317 for (x = 0; x != t->co - 1; ++x) {
1318 t->ary[aryx].next = htab[cs[x] & 255].next;
1319 t->ary[aryx].loc = x;
1320 ++htab[cs[x] & 255].loc;
1321 htab[cs[x] & 255].next = aryx++;
1324 /* Build offset table */
1325 for (x = 0; x < t->co - 1;)
1326 if (htab[s[x] & 255].loc >= 15)
1327 ofst[x++] = t->co - 1;
1336 for (aryy = htab[s[x] & 255].next; aryy; aryy = t->ary[aryy].next) {
1338 int tsfo = t->ary[aryy].loc - x;
1339 int cst = -abs(tsfo);
1342 for (amnt = 0; x + amnt < t->co - 1 && x + tsfo + amnt < t->co - 1; ++amnt) {
1343 if (cs[x + tsfo + amnt] != s[x + amnt])
1345 else if ((s[x + amnt] & 255) != 32 || pre != 32)
1347 pre = s[x + amnt] & 255;
1350 for (back = 0; back + x > 0 && back + tsfo + x > 0; --back) {
1351 if (cs[x + tsfo + back - 1] != s[x + back - 1])
1353 else if ((s[x + back - 1] & 255) != 32 || pre != 32)
1355 pre = s[x + back - 1] & 255;
1365 ofst[x] = t->co - 1;
1367 } else if (best < 2)
1368 for (z = 0; z != maxlen; ++z)
1369 ofst[x + z] = t->co - 1;
1371 for (z = 0; z != maxlen - bestback; ++z)
1372 ofst[x + z + bestback] = t->ary[maxaryy].loc - x;
1376 /* Apply scrolling commands */
1378 for (x = 0; x != t->co - 1; ++x) {
1381 if (q && q != t->co - 1) {
1385 for (z = x; z != t->co - 1 && ofst[z] == q; ++z)
1387 while (s[x] == cs[x] && x < placex)
1389 dodelchr(t, x, y, q);
1390 for (fu = x; fu != t->co - 1; ++fu)
1391 if (ofst[fu] != t->co - 1)
1397 for (z = x; z != t->co - 1 && ofst[z] == q; ++z)
1399 while (s[x + q] == cs[x + q] && x - q < placex)
1401 doinschr(t, x + q, y, s + x + q, a + x + q, -q);
1402 for (fu = x; fu != t->co - 1; ++fu)
1403 if (ofst[fu] != t->co - 1)
1411 static void doupscrl(SCRN *t, int top, int bot, int amnt)
1418 if (top == 0 && bot == t->li && (t->sf || t->SF)) {
1419 setregn(t, 0, t->li);
1420 cpos(t, 0, t->li - 1);
1421 if ((amnt == 1 && t->sf) || !t->SF)
1423 texec(t->cap, t->sf, 1, t->li - 1, 0, 0, 0);
1425 texec(t->cap, t->SF, a, a, 0, 0, 0);
1428 if (bot == t->li && (t->dl || t->DL)) {
1429 setregn(t, 0, t->li);
1431 if ((amnt == 1 && t->dl) || !t->DL)
1433 texec(t->cap, t->dl, 1, top, 0, 0, 0);
1435 texec(t->cap, t->DL, a, a, 0, 0, 0);
1438 if (t->cs && (t->sf || t->SF)) {
1439 setregn(t, top, bot);
1440 cpos(t, 0, bot - 1);
1441 if ((amnt == 1 && t->sf) || !t->SF)
1443 texec(t->cap, t->sf, 1, bot - 1, 0, 0, 0);
1445 texec(t->cap, t->SF, a, a, 0, 0, 0);
1448 if ((t->dl || t->DL) && (t->al || t->AL)) {
1450 if ((amnt == 1 && t->dl) || !t->DL)
1452 texec(t->cap, t->dl, 1, top, 0, 0, 0);
1454 texec(t->cap, t->DL, a, a, 0, 0, 0);
1456 cpos(t, 0, bot - amnt);
1457 if ((amnt == 1 && t->al) || !t->AL)
1459 texec(t->cap, t->al, 1, bot - amnt, 0, 0, 0);
1461 texec(t->cap, t->AL, a, a, 0, 0, 0);
1464 msetI(t->updtab + top, 1, bot - top);
1465 msetI(t->syntab + top, -1, bot - top);
1469 mmove(t->scrn + top * t->co, t->scrn + (top + amnt) * t->co, (bot - top - amnt) * t->co * sizeof(int));
1470 mmove(t->attr + top * t->co, t->attr + (top + amnt) * t->co, (bot - top - amnt) * t->co * sizeof(int));
1472 if (bot == t->li && t->db) {
1473 msetI(t->scrn + (t->li - amnt) * t->co, -1, amnt * t->co);
1474 msetI(t->attr + (t->li - amnt) * t->co, 0, amnt * t->co);
1475 msetI(t->updtab + t->li - amnt, 1, amnt);
1476 msetI(t->syntab + t->li - amnt, -1, amnt);
1478 msetI(t->scrn + (bot - amnt) * t->co, ' ', amnt * t->co);
1479 msetI(t->attr + (bot - amnt) * t->co, 0, amnt * t->co);
1483 static void dodnscrl(SCRN *t, int top, int bot, int amnt)
1490 if (top == 0 && bot == t->li && (t->sr || t->SR)) {
1491 setregn(t, 0, t->li);
1493 if ((amnt == 1 && t->sr) || !t->SR)
1495 texec(t->cap, t->sr, 1, 0, 0, 0, 0);
1497 texec(t->cap, t->SR, a, a, 0, 0, 0);
1500 if (bot == t->li && (t->al || t->AL)) {
1501 setregn(t, 0, t->li);
1503 if ((amnt == 1 && t->al) || !t->AL)
1505 texec(t->cap, t->al, 1, top, 0, 0, 0);
1507 texec(t->cap, t->AL, a, a, 0, 0, 0);
1510 if (t->cs && (t->sr || t->SR)) {
1511 setregn(t, top, bot);
1513 if ((amnt == 1 && t->sr) || !t->SR)
1515 texec(t->cap, t->sr, 1, top, 0, 0, 0);
1517 texec(t->cap, t->SR, a, a, 0, 0, 0);
1520 if ((t->dl || t->DL) && (t->al || t->AL)) {
1521 cpos(t, 0, bot - amnt);
1522 if ((amnt == 1 && t->dl) || !t->DL)
1524 texec(t->cap, t->dl, 1, bot - amnt, 0, 0, 0);
1526 texec(t->cap, t->DL, a, a, 0, 0, 0);
1529 if ((amnt == 1 && t->al) || !t->AL)
1531 texec(t->cap, t->al, 1, top, 0, 0, 0);
1533 texec(t->cap, t->AL, a, a, 0, 0, 0);
1536 msetI(t->updtab + top, 1, bot - top);
1537 msetI(t->syntab + top, -1, bot - top);
1540 mmove(t->scrn + (top + amnt) * t->co, t->scrn + top * t->co, (bot - top - amnt) * t->co * sizeof(int));
1541 mmove(t->attr + (top + amnt) * t->co, t->attr + top * t->co, (bot - top - amnt) * t->co * sizeof(int));
1543 if (!top && t->da) {
1544 msetI(t->scrn, -1, amnt * t->co);
1545 msetI(t->attr, 0, amnt * t->co);
1546 msetI(t->updtab, 1, amnt);
1547 msetI(t->syntab, -1, amnt);
1549 msetI(t->scrn + t->co * top, ' ', amnt * t->co);
1550 msetI(t->attr + t->co * top, 0, amnt * t->co);
1554 void nscroll(SCRN *t)
1558 for (y = 0; y != t->li; ++y) {
1562 if (q && q != t->li) {
1564 for (z = y; z != t->li && t->sary[z] == q; ++z)
1566 doupscrl(t, y, z + q, q);
1569 for (r = y; r != t->li && (t->sary[r] < 0 || t->sary[r] == t->li); ++r)
1574 if (q && q != t->li) {
1575 for (z = p; t->sary[z] = 0, (z && t->sary[z - 1] == q); --z)
1577 dodnscrl(t, z + q, p + 1, -q);
1585 msetI(t->sary, 0, t->li);
1588 void npartial(SCRN *t)
1592 setregn(t, 0, t->li);
1595 void nescape(SCRN *t)
1598 cpos(t, 0, t->li - 1);
1599 eraeol(t, 0, t->li - 1);
1601 texec(t->cap, t->te, 1, 0, 0, 0, 0);
1604 void nreturn(SCRN *t)
1607 texec(t->cap, t->ti, 1, 0, 0, 0, 0);
1608 if (!skiptop && t->cl)
1609 texec(t->cap, t->cl, 1, 0, 0, 0, 0);
1613 void nclose(SCRN *t)
1618 setregn(t, 0, t->li);
1619 cpos(t, 0, t->li - 1);
1621 texec(t->cap, t->te, 1, 0, 0, 0, 0);
1633 void nscrldn(SCRN *t, int top, int bot, int amnt)
1637 if (!amnt || top >= bot || bot > t->li)
1639 if ((amnt < bot - top && bot - top - amnt < amnt / 2) || !t->scroll)
1641 if (amnt < bot - top) {
1642 for (x = bot; x != top + amnt; --x) {
1643 t->sary[x - 1] = (t->sary[x - amnt - 1] == t->li ? t->li : t->sary[x - amnt - 1] - amnt);
1644 t->updtab[x - 1] = t->updtab[x - amnt - 1];
1645 t->syntab[x - 1] = t->syntab[x - amnt - 1];
1647 for (x = top; x != top + amnt; ++x) {
1652 if (amnt > bot - top)
1654 msetI(t->sary + top, t->li, amnt);
1655 if (amnt == bot - top) {
1656 msetI(t->updtab + top, 1, amnt);
1657 msetI(t->syntab + top, -1, amnt);
1661 void nscrlup(SCRN *t, int top, int bot, int amnt)
1665 if (!amnt || top >= bot || bot > t->li)
1667 if ((amnt < bot - top && bot - top - amnt < amnt / 2) || !t->scroll)
1669 if (amnt < bot - top) {
1670 for (x = top + amnt; x != bot; ++x) {
1671 t->sary[x - amnt] = (t->sary[x] == t->li ? t->li : t->sary[x] + amnt);
1672 t->updtab[x - amnt] = t->updtab[x];
1673 t->syntab[x - amnt] = t->syntab[x];
1675 for (x = bot - amnt; x != bot; ++x) {
1680 if (amnt > bot - top)
1682 msetI(t->sary + bot - amnt, t->li, amnt);
1683 if (amnt == bot - top) {
1684 msetI(t->updtab + bot - amnt, 1, amnt);
1685 msetI(t->syntab + bot - amnt, -1, amnt);
1689 extern volatile int dostaupd;
1691 void nredraw(SCRN *t)
1694 msetI(t->scrn, ' ', t->co * skiptop);
1695 msetI(t->attr, 0, t->co * skiptop);
1696 msetI(t->scrn + skiptop * t->co, -1, (t->li - skiptop) * t->co);
1697 msetI(t->attr + skiptop * t->co, 0, (t->li - skiptop) * t->co);
1698 msetI(t->sary, 0, t->li);
1699 msetI(t->updtab + skiptop, -1, t->li - skiptop);
1700 msetI(t->syntab + skiptop, -1, t->li - skiptop);
1709 setregn(t, 0, t->li);
1713 texec(t->cap, t->cl, 1, 0, 0, 0, 0);
1716 msetI(t->scrn, ' ', t->li * t->co);
1717 msetI(t->attr, 0, t->li * t->co);
1720 texec(t->cap, t->cd, 1, 0, 0, 0, 0);
1721 msetI(t->scrn, ' ', t->li * t->co);
1722 msetI(t->attr, 0, t->li * t->co);
1727 /* Convert color/attribute name into internal code */
1729 int meta_color(unsigned char *s)
1731 if(!strcmp((char *)s,"inverse"))
1733 else if(!strcmp((char *)s,"underline"))
1735 else if(!strcmp((char *)s,"bold"))
1737 else if(!strcmp((char *)s,"blink"))
1739 else if(!strcmp((char *)s,"dim"))
1741 else if(!strcmp((char *)s,"white"))
1743 else if(!strcmp((char *)s,"cyan"))
1745 else if(!strcmp((char *)s,"magenta"))
1747 else if(!strcmp((char *)s,"blue"))
1749 else if(!strcmp((char *)s,"yellow"))
1751 else if(!strcmp((char *)s,"green"))
1753 else if(!strcmp((char *)s,"red"))
1755 else if(!strcmp((char *)s,"black"))
1757 else if(!strcmp((char *)s,"bg_white"))
1759 else if(!strcmp((char *)s,"bg_cyan"))
1761 else if(!strcmp((char *)s,"bg_magenta"))
1763 else if(!strcmp((char *)s,"bg_blue"))
1765 else if(!strcmp((char *)s,"bg_yellow"))
1767 else if(!strcmp((char *)s,"bg_green"))
1769 else if(!strcmp((char *)s,"bg_red"))
1771 else if(!strcmp((char *)s,"bg_black"))
1779 * 't' is SCRN to write to.
1780 * 'scrn' is address of field in character buffer
1781 * 'attr' is address of field in attribute buffer
1782 * 'x', 'y' are starting column and line numbers of field
1783 * 'ofst' is first column within string to display
1784 * 's', 'len' is string to generate in field
1785 * 'atr' is screeen attributes (and color) which should be used
1786 * 'width' is column width of field
1787 * 'flg' if set, erases to end of line
1790 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)
1794 int last_col = x + width;
1798 for (col = 0;len != 0 && x < last_col; len--) {
1802 if (fmt) my_atr |= *fmt++;
1803 if (locale_map->type) {
1804 /* UTF-8 mode: decode character and determine its width */
1805 c = utf8_decode(&sm,c);
1807 wid = joe_wcwidth(1,c);
1809 /* Byte mode: character is one column wide */
1814 if (x + wid > last_col) {
1815 /* Character crosses end of field, so fill balance of field with '>' characters instead */
1816 while (x < last_col) {
1817 outatr(utf8_map, t, scrn, attr, x, y, '>', my_atr);
1822 } else /* if (wid >(=) 0) */ {
1823 /* Emit character */
1824 outatr(locale_map, t, scrn, attr, x, y, c, my_atr);
1829 } else if ((col + wid) > ofst) {
1830 /* Wide character crosses left side of field */
1834 outatr(utf8_map, t, scrn, attr, x, y, '<', my_atr);
1845 /* Fill balance of field with spaces */
1846 while (x < last_col) {
1847 outatr(utf8_map, t, scrn, attr, x, y, ' ', 0);
1852 /* Erase to end of line */
1857 /* Width function for above */
1859 int txtwidth(unsigned char *s,int len)
1861 if (locale_map->type) {
1867 int d = utf8_decode(&sm,*s++);
1869 col += joe_wcwidth(1,d);
1877 /* Generate text with formatting escape sequences */
1879 void genfmt(SCRN *t, int x, int y, int ofst, const unsigned char *s, int flg)
1881 int *scrn = t->scrn + y * t->co + x;
1882 int *attr = t->attr + y * t->co + x;
1890 while ((c = *s++) != '\0')
1917 if (col++ >= ofst) {
1918 outatr(locale_map, t, scrn, attr, x, y, (c&0x7F), atr);
1928 if (locale_map->type) {
1929 /* UTF-8 mode: decode character and determine its width */
1930 c = utf8_decode(&sm,c);
1932 wid = joe_wcwidth(1, c);
1935 /* Byte mode: character is one column wide */
1941 outatr(locale_map, t, scrn, attr, x, y, c, atr);
1946 } else if (col+wid>ofst) {
1952 outatr(utf8_map, t, scrn, attr, x, y, '<', atr);
1967 /* Determine column width of string with format codes */
1969 int fmtlen(const unsigned char *s)
1977 while ((c = (*s++))) {
1999 if(locale_map->type) {
2000 c = utf8_decode(&sm,c);
2002 wid = joe_wcwidth(1,c);
2012 /* Return offset within format string which corresponds to a particular
2015 /* FIXME: this is not valid if we land in the middle of a double-wide character */
2017 int fmtpos(unsigned char *s, int goal)
2019 unsigned char *org = s;
2026 while ((c= *s) && col<goal) {
2050 if(locale_map->type) {
2051 c = utf8_decode(&sm,c);
2053 wid = joe_wcwidth(1,c);
2061 return s - org + goal - col;