1 /*
2 * Visual screen packadge.
3 * -----------------------
4 *
5 * int VInit ()
6 * - initialise packadge. Returns 1 if ok else 0.
7 *
8 * VOpen ()
9 * - enters video mode.
10 *
11 * VClose ()
12 * - closes video mode.
13 *
14 * VSetPalette (n, nb, nr, nrb, b, bb, br, brb, d, db, dr, drb)
15 * - set screen palette. Sets normal, normal background,
16 * normal reverse, normal reverse background, bold,
17 * bold background, bold reverse, bold reverse background,
18 * dim, dim background, dim reverse, dim reverse background.
19 * Default are 10, 0, 0, 10, 15, 0, 15, 12, 7, 0, 0, 6.
20 *
21 * VRedraw ()
22 * - redraws screen.
23 *
24 * VSync ()
25 * - refresh screen.
26 *
27 * VFlush ()
28 * - flush terminal output buffer. Called just before
29 * getting input from terminal.
30 *
31 * VBeep ()
32 * - bell.
33 *
34 * VSyncLine (wy)
35 * - refresh line number wy.
36 *
37 * VDelLine (n)
38 * - delete line.
39 *
40 * VInsLine (n)
41 * - insert line.
42 *
43 * VDelChar ()
44 * - delete char at current position, shift line left.
45 *
46 * VInsChar ()
47 * - insert space at current position.
48 *
49 * VMove (y, x)
50 * - set current position.
51 *
52 * VClearLine ()
53 * - erase to end of line.
54 *
55 * VClear ()
56 * - clear screen.
57 *
58 * VPutChar (c)
59 * - put character to screen. Special characters are:
60 * '\1' - set dim
61 * '\2' - set normal
62 * '\3' - set bold
63 * '\16' - set reverse
64 * '\17' - unset reverse
65 * '\t' - next tab stop
66 * '\r' - return
67 * '\n' - new line
68 * '\b' - back space
69 *
70 * VPutString (str)
71 * - print string to screen.
72 *
73 * int VStandOut ()
74 * - set reverse attribute. Returns 1 if terminal
75 * has reverse, else 0.
76 *
77 * VStandEnd ()
78 * - unset reverse attribute.
79 *
80 * VSetNormal ()
81 * - set normal attribute.
82 *
83 * VSetPrev ()
84 * - set attribute before last change.
85 *
86 * VSetDim ()
87 * - set dim attribute.
88 *
89 * VSetBold ()
90 * - set bold attribute.
91 *
92 * CURSOR VGetCursor ()
93 * - get current cursor position.
94 *
95 * VSetCursor (c)
96 * - set stored cursor position.
97 *
98 * BOX *VGetBox (y, x, ny, nx)
99 * - get rectangular area of screen, called "box".
100 * (y, x) specifies upper left corner, ny, nx -
101 * vertical and horisontal sizes.
102 *
103 * VUngetBox (box)
104 * - restore saved box.
105 *
106 * VPrintBox (box)
107 * - print saved box with current attribute.
108 *
109 * VFreeBox (box)
110 * - free box structure.
111 *
112 * VExpandString (s, d)
113 * - expand string "s", which contains
114 * attribute switching escapes '\1, '\2', '\3', '\16', '\17'.
115 * Store expanded string in "d".
116 */
117 /* #define DEBUG */
118
119 #include <setjmp.h>
120 #include <signal.h>
121 #include <stdio.h>
122 #include <stdlib.h>
123 #include <stdarg.h>
124 #include <string.h>
125 #if HAVE_UNISTD_H
126 # include <unistd.h>
127 #endif
128 #if HAVE_FCNTL_H
129 # include <fcntl.h>
130 #endif
131 #if HAVE_SYS_IOCTL_H
132 # include <sys/ioctl.h>
133 #endif
134 #include "deco.h"
135 #include "scr.h"
136 #include "env.h"
137
138 #define STANDOUT 0400
139 #define BOLD 01000
140 #define DIM 02000
141 #define GRAPH 04000
142 #define NOCHANGE -1
143 #define OUTBUFSZ 256
144
145 #define qputch(c) (outptr>=outbuf+OUTBUFSZ?VFlush(),*outptr++=(c):(*outptr++=(c)))
146
147 WINDOW VScreen;
148 int BlackWhite = 0;
149 int ColorMode = 1;
150 int GraphMode = 1;
151 extern int TtyUpperCase;
152
153 static WINDOW curscr;
154 static scrool, rscrool;
155 static beepflag;
156 static prevattr;
157
158 static short ctab [16], btab [16];
159 static char *colorbuf, *colorp;
160 static char outbuf [OUTBUFSZ], *outptr = outbuf;
161
162 static char *BS, *BR, *DS, *DR, *NS, *NR;
163 static char *GS, *GE, *G1, *G2, *GT, *AC, *AS, *AE;
164 static char *CS, *SF, *SR, *EA;
165
166 static char *KS, *KE;
167
168 static char *CL, *CM, *SE, *SO, *TE, *TI, *VE, *VS,
169 *AL, *DL, *IS, *IF, *FS, *MD, *MH, *ME, *MR,
170 *CF, *CB, *AF, *AB, *Sf, *Sb, *MF, *MB, *OP;
171 static NF, NB;
172 static char MS, C2;
173
174 static char Cy;
175 static char *Cs, *Ce, *Ct;
176
177 char VCyrInputTable ['~' - ' ' + 1];
178 static char VCyrOutputTable [64];
179 static cyroutput;
180
181 int LINES; /* number of lines on screen */
182 int COLS; /* number of columns */
183
184 struct CapTab outtab [] = {
185 { "ms", CAPFLG, 0, &MS, 0, 0, },
186 { "C2", CAPFLG, 0, &C2, 0, 0, },
187 { "CY", CAPFLG, 0, &Cy, 0, 0, },
188 { "li", CAPNUM, 0, 0, &LINES, 0, },
189 { "co", CAPNUM, 0, 0, &COLS, 0, },
190 { "Nf", CAPNUM, 0, 0, &NF, 0, },
191 { "Nb", CAPNUM, 0, 0, &NB, 0, },
192 { "cl", CAPSTR, 0, 0, 0, &CL, },
193 { "cm", CAPSTR, 0, 0, 0, &CM, },
194 { "se", CAPSTR, 0, 0, 0, &SE, },
195 { "so", CAPSTR, 0, 0, 0, &SO, },
196 { "Cf", CAPSTR, 0, 0, 0, &CF, },
197 { "Cb", CAPSTR, 0, 0, 0, &CB, },
198 { "AF", CAPSTR, 0, 0, 0, &AF, },
199 { "AB", CAPSTR, 0, 0, 0, &AB, },
200 { "Sf", CAPSTR, 0, 0, 0, &Sf, },
201 { "Sb", CAPSTR, 0, 0, 0, &Sb, },
202 { "Mf", CAPSTR, 0, 0, 0, &MF, },
203 { "Mb", CAPSTR, 0, 0, 0, &MB, },
204 { "md", CAPSTR, 0, 0, 0, &MD, },
205 { "mh", CAPSTR, 0, 0, 0, &MH, },
206 { "mr", CAPSTR, 0, 0, 0, &MR, },
207 { "me", CAPSTR, 0, 0, 0, &ME, },
208 { "te", CAPSTR, 0, 0, 0, &TE, },
209 { "ti", CAPSTR, 0, 0, 0, &TI, },
210 { "vs", CAPSTR, 0, 0, 0, &VS, },
211 { "ve", CAPSTR, 0, 0, 0, &VE, },
212 { "ks", CAPSTR, 0, 0, 0, &KS, },
213 { "ke", CAPSTR, 0, 0, 0, &KE, },
214 { "al", CAPSTR, 0, 0, 0, &AL, },
215 { "dl", CAPSTR, 0, 0, 0, &DL, },
216 { "is", CAPSTR, 0, 0, 0, &IS, },
217 { "if", CAPSTR, 0, 0, 0, &IF, },
218 { "fs", CAPSTR, 0, 0, 0, &FS, },
219 { "eA", CAPSTR, 0, 0, 0, &EA, },
220 { "gs", CAPSTR, 0, 0, 0, &GS, },
221 { "ge", CAPSTR, 0, 0, 0, &GE, },
222 { "as", CAPSTR, 0, 0, 0, &AS, },
223 { "ae", CAPSTR, 0, 0, 0, &AE, },
224 { "g1", CAPSTR, 0, 0, 0, &G1, },
225 { "g2", CAPSTR, 0, 0, 0, &G2, },
226 { "gt", CAPSTR, 0, 0, 0, >, },
227 { "ac", CAPSTR, 0, 0, 0, &AC, },
228 { "cs", CAPSTR, 0, 0, 0, &CS, },
229 { "sf", CAPSTR, 0, 0, 0, &SF, },
230 { "sr", CAPSTR, 0, 0, 0, &SR, },
231 { "Cs", CAPSTR, 0, 0, 0, &Cs, },
232 { "Ce", CAPSTR, 0, 0, 0, &Ce, },
233 { "Ct", CAPSTR, 0, 0, 0, &Ct, },
234 { "op", CAPSTR, 0, 0, 0, &OP, },
235 { { 0, 0, }, 0, 0, 0, 0, 0, },
236 };
237
238 static char *skipdelay ();
239
240 static char linedraw [11] = {
241 '-', /* 0 horisontal line */
242 '|', /* 1 vertical line */
243 '+', /* 2 lower left corner */
244 '-', /* 3 lower center */
245 '+', /* 4 lower right corner */
246 '|', /* 5 left center */
247 '+', /* 6 center cross */
248 '|', /* 7 right center */
249 '+', /* 8 upper left corner */
250 '-', /* 9 upper center */
251 '+', /* 10 upper right corner */
252 };
253
254 static void putch (int c);
255 static void cyr (int on);
256 static void tputs (char *cp);
257 static void pokechr (int y, int x, int c);
258 static void setattr (int c);
259 static void initgraph (void);
260 static void resetattr (int c);
261 static void initcolor (void);
262 static void initbold (void);
263 static void delwin (WINDOW *win);
264 static int newwin (WINDOW *win);
265 static int makenew (WINDOW *win);
266 static void makech (int y);
267 static void makerch (int y);
268 static void domvcur (int y, int x);
269 static void doscrool (void);
270 static void sclln (int y1, int y2, int n);
271 static void screrase ();
272
VInit()273 int VInit ()
274 {
275 register char *p;
276 int i;
277
278 CapGet (outtab);
279
280 p = EnvGet ("LINES");
281 if (p && *p)
282 LINES = strtol (p, 0, 0);
283 p = EnvGet ("COLUMNS");
284 if (p && *p)
285 COLS = strtol (p, 0, 0);
286 #ifdef TIOCGWINSZ
287 {
288 static struct winsize ws;
289 if (ioctl (0,TIOCGWINSZ, &ws) >= 0) {
290 if (ws.ws_row > 0)
291 LINES = ws.ws_row;
292 if (ws.ws_col > 0)
293 COLS = ws.ws_col;
294 }
295 }
296 #endif
297 if (LINES <= 6 || COLS <= 30)
298 return (0);
299 if (! CM)
300 return (0);
301
302 if (AF || Sf) {
303 CF = AF;
304 if (! CF)
305 CF = Sf;
306 CB = AB;
307 if (! CB)
308 CB = Sb;
309 C2 = 0;
310 NF = 16;
311 NB = 8;
312 MF = "042615378CAE9DBF";
313 MB = "04261537";
314 } else if (! NF) {
315 p = EnvGet ("TERM");
316 if (p && *p) {
317 if (strncmp (p, "cons", 4) == 0 ||
318 strncmp (p, "linux", 5) == 0 ||
319 strncmp (p, "ibmpc3", 6) == 0 ||
320 strncmp (p, "pc3", 3) == 0) {
321 /* BSD/OS, Linux */
322 C2 = 1;
323 NF = 16;
324 NB = 8;
325 MF = "042615378CAE9DBF";
326 MB = "04261537";
327 CF = "\33[%p1%{8}%/%d;3%p1%{8}%m%d;4%p2%dm";
328 }
329 }
330 }
331 if (! SO && ! SE) {
332 SO = "\33[7m";
333 SE = "\33[m";
334 }
335
336 scrool = AL && DL;
337 if (! (rscrool = SF && SR))
338 SF = SR = 0;
339 if (NF && ColorMode)
340 initcolor ();
341 else if (ME)
342 initbold ();
343 if ((G1 || G2 || GT || AC) && GraphMode)
344 initgraph ();
345
346 for (i=' '; i<='~'; ++i)
347 VCyrInputTable [i-' '] = i;
348 for (i=0300; i<=0377; ++i)
349 VCyrOutputTable [i-0300] = i;
350
351 if (! Cs || ! Ce)
352 Cs = Ce = 0;
353 if (Cy && Ct) {
354 int fd = open (Ct, 0);
355 if (fd >= 0) {
356 read (fd, VCyrOutputTable, sizeof (VCyrOutputTable));
357 read (fd, VCyrInputTable, sizeof (VCyrInputTable));
358 close (fd);
359 }
360 }
361
362 if (curscr.y)
363 delwin (&curscr);
364 if (VScreen.y)
365 delwin (&VScreen);
366 if (! newwin (&curscr) || ! newwin (&VScreen)) {
367 VClose ();
368 return (0);
369 }
370 curscr.clear = 1;
371 resetattr (0);
372 if (Cy)
373 cyr (0);
374 return (1);
375 }
376
VOpen()377 void VOpen ()
378 {
379 TtySet ();
380 if (IS)
381 tputs (IS);
382 if (TI)
383 tputs (TI);
384 if (VS)
385 tputs (VS);
386 if (KS)
387 tputs (KS);
388 if (EA)
389 tputs (EA);
390 }
391
VReopen()392 void VReopen ()
393 {
394 TtySet ();
395 if (VS)
396 tputs (VS);
397 if (KS)
398 tputs (KS);
399 if (ME)
400 tputs (ME);
401 }
402
VClose()403 void VClose ()
404 {
405 if (curscr.y)
406 setattr (0);
407 if (Cy)
408 cyr (0);
409 if (FS)
410 tputs (FS);
411 if (VE)
412 tputs (VE);
413 if (TE)
414 tputs (TE);
415 if (KE)
416 tputs (KE);
417 if (OP)
418 tputs (OP);
419 VFlush ();
420 TtyReset ();
421 }
422
VRestore()423 void VRestore ()
424 {
425 if (Cy)
426 cyr (0);
427 if (VE)
428 tputs (VE);
429 if (KE)
430 tputs (KE);
431 if (OP)
432 tputs (OP);
433 VFlush ();
434 TtyReset ();
435 }
436
delwin(WINDOW * win)437 static void delwin (WINDOW *win)
438 {
439 register i;
440
441 for (i=0; i < LINES && win->y[i]; i++)
442 free (win->y[i]);
443 free (win->y);
444 free (win->firstch);
445 free (win->lastch);
446 free (win->lnum);
447 win->y = 0;
448 }
449
newwin(WINDOW * win)450 static int newwin (WINDOW *win)
451 {
452 register short *sp;
453 register i;
454
455 if (! makenew (win))
456 return (0);
457 for (i=0; i<LINES; i++) {
458 win->y[i] = (short*) malloc ((int) (COLS * sizeof (short)));
459 if (! win->y[i]) {
460 register j;
461
462 for (j=0; j<i; j++)
463 free (win->y[i]);
464 free (win->y);
465 free (win->firstch);
466 free (win->lastch);
467 free (win->lnum);
468 win->y = 0;
469 return (0);
470 }
471 for (sp=win->y[i]; sp < win->y[i]+COLS;)
472 *sp++ = ' ';
473 }
474 return (1);
475 }
476
makenew(WINDOW * win)477 static int makenew (WINDOW *win)
478 {
479 register i;
480
481 if (! (win->y = (short**) malloc ((int) (LINES * sizeof (short *)))))
482 return (0);
483 if (! (win->firstch = (short*) malloc ((int) (LINES * sizeof (short)))))
484 goto b;
485 if (! (win->lastch = (short*) malloc ((int) (LINES * sizeof (short)))))
486 goto c;
487 if (! (win->lnum = (short*) malloc ((int) (LINES * sizeof (short))))) {
488 free (win->lastch);
489 c: free (win->firstch);
490 b: free (win->y);
491 return (0);
492 }
493 win->cury = win->curx = 0;
494 win->clear = 1;
495 win->flgs = 0;
496 for (i=0; i<LINES; i++) {
497 win->firstch[i] = win->lastch[i] = NOCHANGE;
498 win->lnum[i] = i;
499 }
500 return (1);
501 }
502
VRedraw()503 void VRedraw ()
504 {
505 register short wy;
506 register y, x;
507
508 tputs (CL);
509 y = curscr.cury;
510 x = curscr.curx;
511 curscr.cury = 0;
512 curscr.curx = 0;
513 for (wy=0; wy<LINES; wy++)
514 makerch (wy);
515 domvcur (y, x);
516 setattr (VScreen.flgs);
517 VFlush ();
518 }
519
makerch(int y)520 static void makerch (int y)
521 {
522 register short *new;
523 register short x;
524
525 new = &curscr.y [y] [0];
526 for (x=0; x<COLS; ++new, ++x) {
527 if (*new == ' ')
528 continue;
529 if (x >= COLS-1 && y >= LINES-1)
530 return;
531 domvcur (y, x);
532 setattr (*new);
533 putch (*new);
534 curscr.curx = x + 1;
535 }
536 }
537
VSyncLine(int wy)538 void VSyncLine (int wy)
539 {
540 if (VScreen.firstch[wy] != NOCHANGE) {
541 makech (wy);
542 VScreen.firstch[wy] = NOCHANGE;
543 }
544 }
545
VSync()546 void VSync ()
547 {
548 register short wy;
549
550 if (VScreen.clear || curscr.clear) {
551 setattr (0);
552 tputs (CL);
553 VScreen.clear = 0;
554 curscr.clear = 0;
555 curscr.cury = 0;
556 curscr.curx = 0;
557 for (wy=0; wy<LINES; wy++) {
558 register short *sp, *end;
559
560 end = &curscr.y[wy][COLS];
561 for (sp=curscr.y[wy]; sp<end; sp++)
562 *sp = ' ';
563 }
564 for (wy=0; wy<LINES; wy++) {
565 VScreen.firstch[wy] = 0;
566 VScreen.lastch[wy] = COLS-1;
567 VScreen.lnum[wy] = wy;
568 }
569 } else if (rscrool || scrool)
570 doscrool ();
571 for (wy=0; wy<LINES; wy++) {
572 VSyncLine (wy);
573 VScreen.lnum[wy] = wy;
574 }
575 domvcur (VScreen.cury, VScreen.curx);
576 curscr.cury = VScreen.cury;
577 curscr.curx = VScreen.curx;
578 if (beepflag) {
579 qputch ('\007');
580 beepflag = 0;
581 }
582 setattr (VScreen.flgs);
583 VFlush ();
584 }
585
makech(int y)586 static void makech (int y)
587 {
588 register short *new, *old;
589 register short x, lastch;
590
591 x = VScreen.firstch[y];
592 lastch = VScreen.lastch[y];
593 old = &curscr.y [y] [x];
594 new = &VScreen.y [y] [x];
595 for (; x<=lastch; ++new, ++old, ++x) {
596 if (*new == *old)
597 continue;
598 if (x >= COLS-1 && y >= LINES-1)
599 return;
600 domvcur (y, x);
601 setattr (*new);
602 putch (*old = *new);
603 curscr.curx = x + 1;
604 }
605 }
606
doscrool()607 static void doscrool ()
608 {
609 register line, n, topline, botline;
610 int mustreset = 0;
611
612 for (line=0; line<LINES; ++line) {
613 /* find next range to scrool */
614
615 /* skip fresh lines */
616 while (line < LINES && VScreen.lnum [line] < 0)
617 ++line;
618
619 /* last line reached - no range to scrool */
620 if (line >= LINES)
621 break;
622
623 /* top line found */
624 topline = line;
625
626 /* skip range of old lines */
627 while (line < LINES-1 && VScreen.lnum [line] + 1 == VScreen.lnum [line+1])
628 ++line;
629
630 /* bottom line found */
631 botline = line;
632
633 /* compute number of scrools, >0 - forward */
634 n = topline - VScreen.lnum [topline];
635
636 if (n == 0)
637 continue;
638 else if (n > 0)
639 topline = VScreen.lnum [topline];
640 else if (n < 0)
641 botline = VScreen.lnum [botline];
642
643 /* do scrool */
644
645 if (rscrool && !scrool && !CS) {
646 /* cannot scrool small regions if no scrool region */
647 if (2 * (botline - topline) < LINES-2) {
648 for (line=topline; line<=botline; ++line) {
649 VScreen.firstch [line] = 0;
650 VScreen.lastch [line] = COLS-1;
651 }
652 return;
653 }
654 if (topline > 0) {
655 for (line=0; line<topline; ++line) {
656 VScreen.firstch [line] = 0;
657 VScreen.lastch [line] = COLS-1;
658 }
659 topline = 0;
660 }
661 if (botline < LINES-1) {
662 for (line=botline+1; line<LINES; ++line) {
663 VScreen.firstch [line] = 0;
664 VScreen.lastch [line] = COLS-1;
665 }
666 botline = LINES-1;
667 }
668 }
669
670 /* update curscr */
671 sclln (topline, botline, n);
672
673 /* set scrool region */
674 if (CS) {
675 tputs (CapGoto (CS, botline, topline));
676 mustreset = 1;
677 }
678
679 /* do scrool n lines forward or backward */
680 if (n > 0) {
681 if (CS || !scrool) {
682 tputs (CapGoto (CM, 0, CS ? topline : 0));
683 while (--n >= 0)
684 tputs (SR);
685 } else {
686 while (--n >= 0) {
687 tputs (CapGoto (CM, 0, botline));
688 tputs (DL);
689 tputs (CapGoto (CM, 0, topline));
690 tputs (AL);
691 }
692 }
693 } else {
694 if (CS || !scrool) {
695 tputs (CapGoto (CM, 0, CS ? botline : LINES-1));
696 while (++n <= 0)
697 tputs (SF);
698 } else {
699 while (++n <= 0) {
700 tputs (CapGoto (CM, 0, topline));
701 tputs (DL);
702 tputs (CapGoto (CM, 0, botline));
703 tputs (AL);
704 }
705 }
706 }
707 }
708 if (mustreset)
709 /* unset scrool region */
710 tputs (CapGoto (CS, LINES-1, 0));
711 }
712
sclln(int y1,int y2,int n)713 static void sclln (int y1, int y2, int n)
714 {
715 register short *end, *temp;
716 register y;
717
718 if (n > 0) {
719 for (y=y2-n+1; y<=y2; ++y) {
720 temp = curscr.y [y];
721 for (end = &temp[COLS]; temp<end; *--end = ' ');
722 }
723 while (--n >= 0) {
724 temp = curscr.y [y2];
725 for (y=y2; y>y1; --y)
726 curscr.y [y] = curscr.y [y-1];
727 curscr.y [y1] = temp;
728 }
729 } else {
730 for (y=y1; y<y1-n; ++y) {
731 temp = curscr.y [y];
732 for (end = &temp[COLS]; temp<end; *--end = ' ');
733 }
734 while (++n <= 0) {
735 temp = curscr.y [y1];
736 for (y=y1; y<y2; ++y)
737 curscr.y [y] = curscr.y [y+1];
738 curscr.y [y2] = temp;
739 }
740 }
741 }
742
VDelLine(int n)743 void VDelLine (int n)
744 {
745 register short *temp;
746 register y;
747 register short *end;
748
749 if (n<0 || n>=LINES)
750 return;
751 temp = VScreen.y [n];
752 for (y=n; y < LINES-1; y++) {
753 VScreen.y [y] = VScreen.y [y+1];
754 VScreen.lnum [y] = VScreen.lnum [y+1];
755 if (scrool || rscrool) {
756 VScreen.firstch [y] = VScreen.firstch [y+1];
757 VScreen.lastch [y] = VScreen.lastch [y+1];
758 } else {
759 VScreen.firstch [y] = 0;
760 VScreen.lastch [y] = COLS-1;
761 }
762 }
763 VScreen.y [LINES-1] = temp;
764 VScreen.lnum [LINES-1] = -1;
765 VScreen.firstch [LINES-1] = 0;
766 VScreen.lastch [LINES-1] = COLS-1;
767 for (end = &temp[COLS]; temp<end; *temp++ = ' ');
768 }
769
VInsLine(int n)770 void VInsLine (int n)
771 {
772 register short *temp;
773 register y;
774 register short *end;
775
776 if (n<0 || n>=LINES)
777 return;
778 temp = VScreen.y [LINES-1];
779 for (y=LINES-1; y>n; --y) {
780 VScreen.y [y] = VScreen.y [y-1];
781 VScreen.lnum [y] = VScreen.lnum [y-1];
782 if (scrool || rscrool) {
783 VScreen.firstch [y] = VScreen.firstch [y-1];
784 VScreen.lastch [y] = VScreen.lastch [y-1];
785 } else {
786 VScreen.firstch [y] = 0;
787 VScreen.lastch [y] = COLS-1;
788 }
789 }
790 VScreen.lnum [n] = -1;
791 VScreen.y [n] = temp;
792 VScreen.firstch [n] = 0;
793 VScreen.lastch [n] = COLS-1;
794 for (end = &temp[COLS]; temp<end; *temp++ = ' ');
795 }
796
domvcur(int y,int x)797 static void domvcur (int y, int x)
798 {
799 if (curscr.curx==x && curscr.cury==y)
800 return;
801 if (curscr.cury==y && x-curscr.curx > 0 && x-curscr.curx < 7) {
802 register short i;
803
804 while (curscr.curx < x) {
805 i = curscr.y [curscr.cury] [curscr.curx];
806 if ((i & ~0377) == curscr.flgs)
807 putch ((int) i);
808 else break;
809 ++curscr.curx;
810 }
811 if (curscr.curx == x)
812 return;
813 }
814 if (!MS && curscr.flgs)
815 setattr (0);
816 tputs (CapGoto (CM, x, y));
817 curscr.curx = x;
818 curscr.cury = y;
819 }
820
VMove(int y,int x)821 void VMove (int y, int x)
822 {
823 if (x>=0 && x<COLS)
824 VScreen.curx = x;
825 if (y>=0 && y<LINES)
826 VScreen.cury = y;
827 }
828
VClearLine()829 void VClearLine ()
830 {
831 register short *sp, *end;
832 register y, x;
833 register short *maxx;
834 register minx;
835
836 y = VScreen.cury;
837 x = VScreen.curx;
838 end = &VScreen.y[y][COLS];
839 minx = NOCHANGE;
840 maxx = &VScreen.y[y][x];
841 for (sp=maxx; sp<end; sp++)
842 if (*sp != ' ') {
843 maxx = sp;
844 if (minx == NOCHANGE)
845 minx = sp - VScreen.y[y];
846 *sp = ' ';
847 }
848 if (minx != NOCHANGE) {
849 if (VScreen.firstch[y] > minx || VScreen.firstch[y] == NOCHANGE)
850 VScreen.firstch[y] = minx;
851 if (VScreen.lastch[y] < maxx - VScreen.y[y])
852 VScreen.lastch[y] = maxx - VScreen.y[y];
853 }
854 }
855
VClear()856 void VClear ()
857 {
858 screrase ();
859 VScreen.clear = 1;
860 }
861
screrase()862 static void screrase ()
863 {
864 register y;
865 register short *sp, *end, *maxx;
866 register minx;
867
868 for (y=0; y<LINES; y++) {
869 minx = NOCHANGE;
870 maxx = 0;
871 end = &VScreen.y[y][COLS];
872 for (sp=VScreen.y[y]; sp<end; sp++)
873 if (*sp != ' ') {
874 maxx = sp;
875 if (minx == NOCHANGE)
876 minx = sp - VScreen.y[y];
877 *sp = ' ';
878 }
879 if (minx != NOCHANGE) {
880 if (VScreen.firstch[y] > minx
881 || VScreen.firstch[y] == NOCHANGE)
882 VScreen.firstch[y] = minx;
883 if (VScreen.lastch[y] < maxx - VScreen.y[y])
884 VScreen.lastch[y] = maxx - VScreen.y[y];
885 }
886 VScreen.lnum[y] = y;
887 }
888 VScreen.curx = VScreen.cury = 0;
889 }
890
VPutString(char * str)891 void VPutString (char *str)
892 {
893 while (*str)
894 VPutChar (*str++);
895 }
896
makecolor(int c,int b)897 static char *makecolor (int c, int b)
898 {
899 register char *p = colorp;
900
901 if (C2) {
902 strcpy (colorp, CapGoto (CF, b, c));
903 while (*colorp++);
904 } else {
905 #if 1
906 if (c > 8) {
907 strcpy (colorp, "\33[1m");
908 while (*colorp++);
909 } else {
910 strcpy (colorp, "\33[0m");
911 while (*colorp++);
912 }
913 #endif
914 strcpy (--colorp, CapGoto (CF, 0, c % 8));
915 while (*colorp++);
916 strcpy (--colorp, CapGoto (CB, 0, b));
917 while (*colorp++);
918 }
919 return (p);
920 }
921
initcolor()922 static void initcolor ()
923 {
924 register i;
925
926 if (NF<=0 || NB<=0 || !CF || (!CB && !C2))
927 return;
928 if (NF > 16)
929 NF = 16;
930 if (NB > 16)
931 NB = 16;
932 if (! MF)
933 MF = "0123456789ABCDEF";
934 if (! MB)
935 MB = "0123456789ABCDEF";
936 for (i=0; i<16; ++i)
937 ctab [i] = btab [i] = -1;
938 for (i=0; i<16 && i<NF; ++i)
939 if (! MF [i])
940 break;
941 else if (MF[i]>='0' && MF[i]<='9')
942 ctab [MF [i] - '0'] = i;
943 else if (MF[i]>='A' && MF[i]<='F')
944 ctab [MF [i] - 'A' + 10] = i;
945 for (i=0; i<16 && i<NB; ++i)
946 if (! MB [i])
947 break;
948 else if (MB[i]>='0' && MB[i]<='9')
949 btab [MB [i] - '0'] = i;
950 else if (MF[i]>='A' && MF[i]<='F')
951 btab [MB [i] - 'A' + 10] = i;
952 for (i=1; i<8; ++i) {
953 if (ctab[i] >= 0 && ctab[i+8] < 0)
954 ctab [i+8] = ctab [i];
955 if (ctab[i+8] >= 0 && ctab[i] < 0)
956 ctab [i] = ctab [i+8];
957 if (btab[i] >= 0 && btab[i+8] < 0)
958 btab [i+8] = btab [i];
959 if (btab[i+8] >= 0 && btab[i] < 0)
960 btab [i] = btab [i+8];
961 }
962 VSetPalette (7, 0, 0, 7, 15, 0, 15, 12, 3, 0, 0, 6);
963 }
964
VSetPalette(int n,int nb,int nr,int nrb,int b,int bb,int br,int brb,int d,int db,int dr,int drb)965 void VSetPalette (int n, int nb, int nr, int nrb, int b, int bb,
966 int br, int brb, int d, int db, int dr, int drb)
967 {
968 if (! NF || ctab[n]<0 || ctab[nr]<0 || btab[nb]<0 || btab[nrb]<0)
969 return;
970 NS = NR = BS = BR = DS = DR = 0;
971 if (colorp)
972 free (colorbuf);
973 colorp = colorbuf = malloc (256);
974 NS = makecolor (ctab [n], btab [nb]); /* NORMAL - bright green on black */
975 NR = makecolor (ctab [nr], btab [nrb]); /* REVERSE NORMAL - black on bright green */
976 if (ctab[b]<0 || ctab[br]<0 || btab[bb]<0 || btab[brb]<0)
977 return;
978 BS = makecolor (ctab [b], btab [bb]); /* BOLD - bright white on black */
979 BR = makecolor (ctab [br], btab [brb]); /* REVERSE BOLD - bright white on bright red */
980 if (ctab[d]<0 || ctab[dr]<0 || btab[db]<0 || btab[drb]<0)
981 return;
982 DS = makecolor (ctab [d], btab [db]); /* DIM - white on black */
983 DR = makecolor (ctab [dr], btab [drb]); /* REVERSE DIM - bright yellow on brown */
984 }
985
initbold()986 static void initbold ()
987 {
988 if (ME)
989 NS = skipdelay (ME);
990 if (MD)
991 BS = skipdelay (MD);
992 if (MH)
993 DS = skipdelay (MH);
994 if (SO)
995 SO = skipdelay (SO);
996 else if (MR)
997 SO = skipdelay (MR);
998 }
999
initgraph()1000 static void initgraph ()
1001 {
1002 register i;
1003 register char *g = 0;
1004
1005 if (G1)
1006 g = G1;
1007 else if (G2)
1008 g = G2;
1009 else if (GT) {
1010 GT [1] = GT [0];
1011 g = GT+1;
1012 }
1013 if (g)
1014 for (i=0; i<11 && *g; ++i, ++g)
1015 linedraw [i] = *g;
1016 else if (AC) {
1017 GS = AS;
1018 GE = AE;
1019 for (; AC[0] && AC[1]; AC+=2)
1020 switch (AC[0]) {
1021 case 'l': linedraw [8] = AC[1]; break;
1022 case 'q': linedraw [0] = AC[1]; break;
1023 case 'k': linedraw [10] = AC[1]; break;
1024 case 'x': linedraw [1] = AC[1]; break;
1025 case 'j': linedraw [4] = AC[1]; break;
1026 case 'm': linedraw [2] = AC[1]; break;
1027 case 'w': linedraw [9] = AC[1]; break;
1028 case 'u': linedraw [7] = AC[1]; break;
1029 case 'v': linedraw [3] = AC[1]; break;
1030 case 't': linedraw [5] = AC[1]; break;
1031 case 'n': linedraw [6] = AC[1]; break;
1032 }
1033 }
1034 }
1035
1036 #define RESETATTR(a,b,c,f)\
1037 if (a)\
1038 tputs (b);\
1039 else {\
1040 tputs (c);\
1041 tputs (f);\
1042 }\
1043 break
1044
resetattr(int c)1045 static void resetattr (int c)
1046 {
1047 c &= DIM | BOLD | STANDOUT | GRAPH;
1048 switch (c & (DIM | BOLD | STANDOUT)) {
1049 case 0: RESETATTR (NR,NS,NS,SE);
1050 case STANDOUT: RESETATTR (NR,NR,NS,SO);
1051 case DIM: RESETATTR (DR,DS,DS,SE);
1052 case DIM|STANDOUT: RESETATTR (DR,DR,DS,SO);
1053 case BOLD: RESETATTR (BR,BS,BS,SE);
1054 case BOLD|STANDOUT: RESETATTR (BR,BR,BS,SO);
1055 }
1056 curscr.flgs = c;
1057 }
1058
1059 #define SETATTR(a,b,c)\
1060 if (a)\
1061 tputs (b);\
1062 else {\
1063 if (curscr.flgs & STANDOUT) {\
1064 tputs (SE);\
1065 tputs (b);\
1066 } else if ((curscr.flgs & (DIM|BOLD)) != (c))\
1067 tputs (b);\
1068 }\
1069 break
1070
1071 #define SETREVA(a,b,c)\
1072 if (a)\
1073 tputs (a);\
1074 else {\
1075 if ((curscr.flgs & (DIM|BOLD)) != (c))\
1076 tputs (b);\
1077 if (! (curscr.flgs & STANDOUT))\
1078 tputs (SO);\
1079 }\
1080 break
1081
setattr(int c)1082 static void setattr (int c)
1083 {
1084 c &= DIM | BOLD | STANDOUT | GRAPH;
1085 if ((c & GRAPH) != (curscr.flgs & GRAPH))
1086 if (c & GRAPH) {
1087 tputs (GS);
1088 resetattr (c);
1089 return;
1090 } else
1091 tputs (GE);
1092 if ((c & (DIM | BOLD | STANDOUT)) != (curscr.flgs & (DIM | BOLD | STANDOUT)))
1093 switch (c & (DIM | BOLD | STANDOUT)) {
1094 case 0: SETATTR (NR,NS,0);
1095 case STANDOUT: SETREVA (NR,NS,0);
1096 case DIM: SETATTR (DR,DS,DIM);
1097 case DIM|STANDOUT: SETREVA (DR,DS,DIM);
1098 case BOLD: SETATTR (BR,BS,BOLD);
1099 case BOLD|STANDOUT: SETREVA (BR,BS,BOLD);
1100 }
1101 curscr.flgs = c;
1102 }
1103
VStandOut()1104 int VStandOut ()
1105 {
1106 if (!SO && !NR)
1107 return (0);
1108 VScreen.flgs |= STANDOUT;
1109 return (1);
1110 }
1111
VStandEnd()1112 void VStandEnd ()
1113 {
1114 VScreen.flgs &= ~STANDOUT;
1115 }
1116
VSetNormal()1117 void VSetNormal ()
1118 {
1119 prevattr = VScreen.flgs;
1120 VScreen.flgs &= ~(BOLD | DIM);
1121 }
1122
VSetPrev()1123 void VSetPrev ()
1124 {
1125 VScreen.flgs &= ~(BOLD | DIM);
1126 VScreen.flgs |= prevattr & (BOLD | DIM);
1127 }
1128
VSetDim()1129 int VSetDim ()
1130 {
1131 prevattr = VScreen.flgs & (BOLD | DIM);
1132 VScreen.flgs &= ~(BOLD | DIM);
1133 if (!DS)
1134 return (0);
1135 if (BlackWhite)
1136 return (0);
1137 VScreen.flgs |= DIM;
1138 return (1);
1139 }
1140
VSetBold()1141 int VSetBold ()
1142 {
1143 prevattr = VScreen.flgs & (BOLD | DIM);
1144 VScreen.flgs &= ~(BOLD | DIM);
1145 if (!BS)
1146 return (0);
1147 if (BlackWhite)
1148 return (0);
1149 VScreen.flgs |= BOLD;
1150 return (1);
1151 }
1152
VPutChar(int c)1153 void VPutChar (int c)
1154 {
1155 register x, y;
1156
1157 x = VScreen.curx;
1158 y = VScreen.cury;
1159 switch (c &= 0377) {
1160 case '\16':
1161 VStandOut ();
1162 return;
1163 case '\17':
1164 VStandEnd ();
1165 return;
1166 case '\1':
1167 VSetDim ();
1168 return;
1169 case '\2':
1170 VSetNormal ();
1171 return;
1172 case '\3':
1173 VSetBold ();
1174 return;
1175 case '\t':
1176 x += (8 - (x & 07));
1177 break;
1178 default:
1179 pokechr (y, x++, c | VScreen.flgs);
1180 break;
1181 case '\n':
1182 ++y;
1183 case '\r':
1184 x = 0;
1185 break;
1186 case '\b':
1187 if (x == 0)
1188 return;
1189 --x;
1190 break;
1191 }
1192 if (x >= COLS) {
1193 x = 0;
1194 if (++y >= LINES)
1195 y = 0;
1196 }
1197 VScreen.curx = x;
1198 VScreen.cury = y;
1199 }
1200
pokechr(int y,int x,int c)1201 static void pokechr (int y, int x, int c)
1202 {
1203 if (VScreen.y[y][x] == c)
1204 return;
1205 if (VScreen.firstch[y] == NOCHANGE)
1206 VScreen.firstch[y] = VScreen.lastch[y] = x;
1207 else if (x < VScreen.firstch[y])
1208 VScreen.firstch[y] = x;
1209 else if (x > VScreen.lastch[y])
1210 VScreen.lastch[y] = x;
1211 VScreen.y[y][x] = c;
1212 }
1213
skipdelay(char * cp)1214 static char *skipdelay (char *cp)
1215 {
1216 while (*cp>='0' && *cp<='9')
1217 ++cp;
1218 if (*cp == '.') {
1219 ++cp;
1220 while (*cp>='0' && *cp<='9')
1221 ++cp;
1222 }
1223 if (*cp == '*')
1224 ++cp;
1225 return (cp);
1226 }
1227
tputs(char * cp)1228 static void tputs (char *cp)
1229 {
1230 register c;
1231
1232 if (! cp)
1233 return;
1234 cp = skipdelay (cp);
1235 while ((c = *cp++))
1236 qputch (c);
1237 }
1238
cyr(int on)1239 static void cyr (int on)
1240 {
1241 if (on) {
1242 if (! cyroutput) {
1243 tputs (Cs);
1244 cyroutput = 1;
1245 }
1246 } else {
1247 if (cyroutput) {
1248 tputs (Ce);
1249 cyroutput = 0;
1250 }
1251 }
1252 }
1253
putch(int c)1254 static void putch (int c)
1255 {
1256 c &= 0377;
1257 if (TtyUpperCase) {
1258 if (c>='a' && c<='z')
1259 c += 'A' - 'a';
1260 else if (c>=0300 && c<=0336)
1261 c += 040;
1262 else if (c == 0337)
1263 c = '\'';
1264 }
1265 if (Cy) {
1266 if (c>=0300 && c<=0377) {
1267 cyr (1);
1268 c = VCyrOutputTable [c - 0300];
1269 } else if (c>' ' && c<='~')
1270 cyr (0);
1271 }
1272 qputch (c);
1273 }
1274
VFlush()1275 void VFlush ()
1276 {
1277 if (outptr > outbuf)
1278 write (1, outbuf, (unsigned) (outptr-outbuf));
1279 outptr = outbuf;
1280 }
1281
VBeep()1282 void VBeep ()
1283 {
1284 beepflag = 1;
1285 }
1286
VGetCursor()1287 CURSOR VGetCursor ()
1288 {
1289 return ((CURSOR) ((long) VScreen.cury<<16 | VScreen.curx));
1290 }
1291
VSetCursor(CURSOR c)1292 void VSetCursor (CURSOR c)
1293 {
1294 VMove ((int) (c >> 16), (int) c & 0xffff);
1295 }
1296
VGetBox(int y,int x,int ny,int nx)1297 BOX *VGetBox (int y, int x, int ny, int nx)
1298 {
1299 register xx, yy;
1300 register short *p, *q;
1301 BOX *box;
1302
1303 box = (BOX*) malloc ((int) (sizeof (BOX)));
1304 box->y = y;
1305 box->x = x;
1306 box->ny = ny;
1307 box->nx = nx;
1308 box->mem = (short*) malloc ((int) (ny * nx * sizeof (short)));
1309
1310 for (yy=0; yy<ny; ++yy) {
1311 p = & VScreen.y [yy+y] [x];
1312 q = & box->mem [yy*nx];
1313 for (xx=0; xx<nx; ++xx)
1314 *q++ = *p++;
1315 }
1316 return (box);
1317 }
1318
VUngetBox(BOX * box)1319 void VUngetBox (BOX *box)
1320 {
1321 register xx, yy;
1322 register short *q;
1323
1324 for (yy=0; yy<box->ny; ++yy) {
1325 q = & box->mem [yy * box->nx];
1326 for (xx=0; xx<box->nx; ++xx, ++q)
1327 pokechr (box->y+yy, box->x+xx, *q);
1328 }
1329 }
1330
VPrintBox(BOX * box)1331 void VPrintBox (BOX *box)
1332 {
1333 register xx, yy;
1334 register short *q;
1335
1336 for (yy=0; yy<box->ny; ++yy) {
1337 q = & box->mem [yy * box->nx];
1338 for (xx=0; xx<box->nx; ++xx)
1339 pokechr (box->y+yy, box->x+xx,
1340 (*q++ & 0377) | VScreen.flgs);
1341 }
1342 }
1343
VFreeBox(BOX * box)1344 void VFreeBox (BOX *box)
1345 {
1346 free (box->mem);
1347 free (box);
1348 }
1349
VClearBox(int r,int c,int nr,int nc)1350 void VClearBox (int r, int c, int nr, int nc)
1351 {
1352 register i;
1353
1354 for (; --nr>=0; ++r)
1355 for (i=nc; --i>=0;)
1356 pokechr (r, c+i, ' ');
1357 }
1358
VFillBox(int r,int c,int nr,int nc,int sym)1359 void VFillBox (int r, int c, int nr, int nc, int sym)
1360 {
1361 register i;
1362
1363 for (; --nr>=0; ++r)
1364 for (i=nc; --i>=0;)
1365 pokechr (r, c+i, sym | VScreen.flgs);
1366 }
1367
VHorLine(int r,int c,int nc)1368 void VHorLine (int r, int c, int nc)
1369 {
1370 register sym;
1371
1372 sym = (linedraw [0] & 0377) | GRAPH | VScreen.flgs;
1373 while (--nc >= 0)
1374 pokechr (r, c++, sym);
1375 }
1376
VVertLine(int c,int r,int nr)1377 void VVertLine (int c, int r, int nr)
1378 {
1379 register sym;
1380
1381 sym = (linedraw [1] & 0377) | GRAPH | VScreen.flgs;
1382 while (--nr >= 0)
1383 pokechr (r++, c, sym);
1384 }
1385
VCorner(int r,int c,int n)1386 void VCorner (int r, int c, int n)
1387 {
1388 static short map [9] = { 8, 9, 10, 5, 6, 7, 2, 3, 4 };
1389
1390 switch (n) {
1391 case 1: case 2: case 3: case 4:
1392 case 5: case 6: case 7: case 8:
1393 case 9:
1394 n = (linedraw [map [n-1]] & 0377) | GRAPH;
1395 break;
1396 default:
1397 n = '?';
1398 break;
1399 }
1400 pokechr (r, c, n | VScreen.flgs);
1401 }
1402
VDrawBox(int r,int c,int nr,int nc)1403 void VDrawBox (int r, int c, int nr, int nc)
1404 {
1405 VHorLine (r, c+1, nc-2);
1406 VHorLine (r+nr-1, c+1, nc-2);
1407 VVertLine (c, r+1, nr-2);
1408 VVertLine (c+nc-1, r+1, nr-2);
1409 VCorner (r, c, 1) ;
1410 VCorner (r, c+nc-1, 3);
1411 VCorner (r+nr-1, c, 7) ;
1412 VCorner (r+nr-1, c+nc-1, 9);
1413 }
1414
1415 #define ADDSTR(a)\
1416 if (a) {\
1417 strcpy (d, skipdelay (a));\
1418 while (*d) ++d;\
1419 }
1420
1421 #define ADDREVERSE(a,b)\
1422 if (reverse == (a))\
1423 continue;\
1424 ADDSTR (b)\
1425 reverse = (a);
1426
1427 #define ADDCOLOR(a,b,c)\
1428 if (bright == (a))\
1429 continue;\
1430 ADDSTR (reverse ? (b) : (c))\
1431 bright = (a);
1432
VExpandString(char * s,char * d)1433 void VExpandString (char *s, char *d)
1434 {
1435 /* expand string s to d substituting \1, \2, \3, \16, \17 */
1436 register c;
1437 int bright; /* 1=bold, 0=normal, 2=dim */
1438 int reverse;
1439
1440 bright = 0;
1441 reverse = 0;
1442 while ((c = *s++))
1443 switch (c) {
1444 case '\17': ADDREVERSE (0, SE); break;
1445 case '\16': ADDREVERSE (1, SO); break;
1446 case '\1': ADDCOLOR (2, DR, DS); break;
1447 case '\2': ADDCOLOR (0, NR, NS); break;
1448 case '\3': ADDCOLOR (1, BR, BS); break;
1449 default: *d++ = c; break;
1450 }
1451 *d = 0;
1452 }
1453
VPrint(char * fmt,...)1454 void VPrint (char *fmt, ...)
1455 {
1456 char buf [512];
1457 va_list ap;
1458
1459 va_start (ap, fmt);
1460 vsprintf (buf, fmt, ap);
1461 va_end (ap);
1462 VPutString (buf);
1463 }
1464
1465
1466 #ifdef notdef
tstp()1467 static void tstp ()
1468 {
1469 tputs (CapGoto (CM, 0, LINES-1));
1470 VRestore ();
1471 kill (0, SIGSTOP);
1472 VReopen ();
1473 VRedraw ();
1474 }
1475 #endif
1476
1477 #ifdef DOC
1478 #include <stdio.h>
1479
_prscreen(void)1480 void _prscreen (void)
1481 {
1482 static char filename [] = "screenX",fname[128];
1483 static count = 0;
1484 register FILE *fd;
1485 register short y, x, c, a, m;
1486 char *toname;
1487
1488 filename [6] = 'A' + count;
1489 toname = EnvGet ("DECOSCREEN");
1490 if (! toname)
1491 toname = ".";
1492 strcpy (fname, toname);
1493 strcat (fname, "/");
1494 strcat (fname, filename);
1495 fd = fopen (fname, "w");
1496 if (! fd)
1497 return;
1498 ++count;
1499 a = 0;
1500 m = BOLD | DIM;
1501 for (y=0; y<LINES; ++y) {
1502 for (x=0; x<COLS; ++x) {
1503 c = curscr.y [y] [x];
1504 if ((a & GRAPH) != (c & GRAPH))
1505 putc (c & GRAPH ? cntrl ('[') : cntrl ('\\'), fd);
1506 if ((a & STANDOUT) != (c & STANDOUT))
1507 putc (c & STANDOUT ? cntrl ('n') : cntrl ('o'), fd);
1508 if ((a & m) != (c & m))
1509 switch (c & m) {
1510 case BOLD: putc (3, fd); break;
1511 case DIM: putc (1, fd); break;
1512 case 0: putc (2, fd); break;
1513 }
1514 putc (c & GRAPH ? _graphsym (c) : c, fd);
1515 a = c;
1516 }
1517 putc ('\n', fd);
1518 }
1519 fclose (fd);
1520 }
1521
_graphsym(int c)1522 static int _graphsym (int c)
1523 {
1524 register i;
1525
1526 c &= 0xff;
1527 for (i=0; i<11; ++i)
1528 if (c == linedraw [i])
1529 switch (i) {
1530 case 0: /* horisontal line */
1531 return ('-');
1532 case 1: /* vertical line */
1533 return ('|');
1534 case 2: /* lower left corner */
1535 case 3: /* lower center */
1536 case 4: /* lower right corner */
1537 case 5: /* left center */
1538 case 6: /* center cross */
1539 case 7: /* right center */
1540 case 8: /* upper left corner */
1541 case 9: /* upper center */
1542 case 10: /* upper right corner */
1543 return ('0' + i - 1);
1544 }
1545 return ('?');
1546 }
1547 #endif
1548