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, &GT, },
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