1 /*	SCCS Id: @(#)termcap.c	3.3	2000/07/10	*/
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed.  See license for details. */
4 
5 #include "hack.h"
6 
7 #if defined (TTY_GRAPHICS) && !defined(NO_TERMS)
8 
9 #include "wintty.h"
10 
11 #include "tcap.h"
12 
13 
14 #ifdef MICROPORT_286_BUG
15 #define Tgetstr(key) (tgetstr(key,tbuf))
16 #else
17 #define Tgetstr(key) (tgetstr(key,&tbufptr))
18 #endif /* MICROPORT_286_BUG **/
19 
20 static char * FDECL(s_atr2str, (int));
21 static char * FDECL(e_atr2str, (int));
22 
23 void FDECL(cmov, (int, int));
24 void FDECL(nocmov, (int, int));
25 #if defined(TEXTCOLOR) && defined(TERMLIB)
26 # ifdef OVLB
27 #  if !defined(UNIX) || !defined(TERMINFO)
28 #   ifndef TOS
29 static void FDECL(analyze_seq, (char *, int *, int *));
30 #   endif
31 #  endif
32 static void NDECL(init_hilite);
33 static void NDECL(kill_hilite);
34 # endif /* OVLB */
35 #endif
36 
37 #ifdef OVLB
38 	/* (see tcap.h) -- nh_CM, nh_ND, nh_CD, nh_HI,nh_HE, nh_US,nh_UE,
39 				ul_hack */
40 struct tc_lcl_data tc_lcl_data = { 0, 0, 0, 0,0, 0,0, FALSE };
41 #endif /* OVLB */
42 
43 STATIC_VAR char *HO, *CL, *CE, *UP, *XD, *BC, *SO, *SE, *TI, *TE;
44 STATIC_VAR char *VS, *VE;
45 STATIC_VAR char *ME;
46 STATIC_VAR char *MR;
47 #if 0
48 STATIC_VAR char *MB, *MH;
49 STATIC_VAR char *MD;     /* may already be in use below */
50 #endif
51 #ifdef TERMLIB
52 # ifdef TEXTCOLOR
53 STATIC_VAR char *MD;
54 # endif
55 STATIC_VAR int SG;
56 #ifdef OVLB
57 STATIC_OVL char PC = '\0';
58 #else /* OVLB */
59 STATIC_DCL char PC;
60 #endif /* OVLB */
61 STATIC_VAR char tbuf[512];
62 #endif
63 
64 #ifdef TEXTCOLOR
65 # ifdef TOS
66 const char *hilites[CLR_MAX];	/* terminal escapes for the various colors */
67 # else
68 char NEARDATA *hilites[CLR_MAX]; /* terminal escapes for the various colors */
69 # endif
70 #endif
71 
72 #ifdef OVLB
73 static char *KS = (char *)0, *KE = (char *)0;	/* keypad sequences */
74 static char nullstr[] = "";
75 #endif /* OVLB */
76 
77 #if defined(ASCIIGRAPH) && !defined(NO_TERMS)
78 extern boolean HE_resets_AS;
79 #endif
80 
81 #ifndef TERMLIB
82 STATIC_VAR char tgotobuf[20];
83 # ifdef TOS
84 #define tgoto(fmt, x, y)	(Sprintf(tgotobuf, fmt, y+' ', x+' '), tgotobuf)
85 # else
86 #define tgoto(fmt, x, y)	(Sprintf(tgotobuf, fmt, y+1, x+1), tgotobuf)
87 # endif
88 #endif /* TERMLIB */
89 
90 #ifdef OVLB
91 
92 void
tty_startup(wid,hgt)93 tty_startup(wid, hgt)
94 int *wid, *hgt;
95 {
96 	register int i;
97 #ifdef TERMLIB
98 	register const char *term;
99 	register char *tptr;
100 	char *tbufptr, *pc;
101 
102 # ifdef VMS
103 	term = verify_termcap();
104 	if (!term)
105 # endif
106 		term = getenv("TERM");
107 
108 # if defined(TOS) && defined(__GNUC__)
109 	if (!term)
110 		term = "builtin";		/* library has a default */
111 # endif
112 	if (!term)
113 #endif
114 #ifndef ANSI_DEFAULT
115 		error("Can't get TERM.");
116 #else
117 # ifdef TOS
118 	{
119 		CO = 80; LI = 25;
120 		TI = VS = VE = TE = nullstr;
121 		HO = "\033H";
122 		CE = "\033K";		/* the VT52 termcap */
123 		UP = "\033A";
124 		nh_CM = "\033Y%c%c";	/* used with function tgoto() */
125 		nh_ND = "\033C";
126 		XD = "\033B";
127 		BC = "\033D";
128 		SO = "\033p";
129 		SE = "\033q";
130 	/* HI and HE will be updated in init_hilite if we're using color */
131 		nh_HI = "\033p";
132 		nh_HE = "\033q";
133 		*wid = CO;
134 		*hgt = LI;
135 		CL = "\033E";		/* last thing set */
136 		return;
137 	}
138 # else /* TOS */
139 	{
140 #  ifdef MICRO
141 		get_scr_size();
142 #   ifdef CLIPPING
143 		if(CO < COLNO || LI < ROWNO+3)
144 			setclipped();
145 #   endif
146 #  endif
147 		HO = "\033[H";
148 /*		nh_CD = "\033[J"; */
149 		CE = "\033[K";		/* the ANSI termcap */
150 #  ifndef TERMLIB
151 		nh_CM = "\033[%d;%dH";
152 #  else
153 		nh_CM = "\033[%i%d;%dH";
154 #  endif
155 		UP = "\033[A";
156 		nh_ND = "\033[C";
157 		XD = "\033[B";
158 #  ifdef MICRO	/* backspaces are non-destructive */
159 		BC = "\b";
160 #  else
161 		BC = "\033[D";
162 #  endif
163 		nh_HI = SO = "\033[1m";
164 		nh_US = "\033[4m";
165 		MR = "\033[7m";
166 		TI = nh_HE = ME = SE = nh_UE = "\033[0m";
167 		/* strictly, SE should be 2, and nh_UE should be 24,
168 		   but we can't trust all ANSI emulators to be
169 		   that complete.  -3. */
170 #  ifndef MICRO
171 		AS = "\016";
172 		AE = "\017";
173 #  endif
174 		TE = VS = VE = nullstr;
175 #  ifdef TEXTCOLOR
176 		for (i = 0; i < CLR_MAX / 2; i++)
177 		    if (i != CLR_BLACK) {
178 			hilites[i|BRIGHT] = (char *) alloc(sizeof("\033[1;3%dm"));
179 			Sprintf(hilites[i|BRIGHT], "\033[1;3%dm", i);
180 			if (i != CLR_GRAY)
181 #   ifdef MICRO
182 			    if (i == CLR_BLUE) hilites[CLR_BLUE] = hilites[CLR_BLUE|BRIGHT];
183 			    else
184 #   endif
185 			    {
186 				hilites[i] = (char *) alloc(sizeof("\033[0;3%dm"));
187 				Sprintf(hilites[i], "\033[0;3%dm", i);
188 			    }
189 		    }
190 #  endif
191 		*wid = CO;
192 		*hgt = LI;
193 		CL = "\033[2J";		/* last thing set */
194 		return;
195 	}
196 # endif /* TOS */
197 #endif /* ANSI_DEFAULT */
198 
199 #ifdef TERMLIB
200 	tptr = (char *) alloc(1024);
201 
202 	tbufptr = tbuf;
203 	if(!strncmp(term, "5620", 4))
204 		flags.null = FALSE;	/* this should be a termcap flag */
205 	if(tgetent(tptr, term) < 1) {
206 		char buf[BUFSZ];
207 		(void) strncpy(buf, term,
208 				(BUFSZ - 1) - (sizeof("Unknown terminal type: .  ")));
209 		buf[BUFSZ-1] = '\0';
210 		error("Unknown terminal type: %s.", term);
211 	}
212 	if ((pc = Tgetstr("pc")) != 0)
213 		PC = *pc;
214 
215 	if(!(BC = Tgetstr("le")))	/* both termcap and terminfo use le */
216 # ifdef TERMINFO
217 	    error("Terminal must backspace.");
218 # else
219 	    if(!(BC = Tgetstr("bc"))) {	/* termcap also uses bc/bs */
220 #  ifndef MINIMAL_TERM
221 		if(!tgetflag("bs"))
222 			error("Terminal must backspace.");
223 #  endif
224 		BC = tbufptr;
225 		tbufptr += 2;
226 		*BC = '\b';
227 	    }
228 # endif
229 
230 # ifdef MINIMAL_TERM
231 	HO = (char *)0;
232 # else
233 	HO = Tgetstr("ho");
234 # endif
235 	/*
236 	 * LI and CO are set in ioctl.c via a TIOCGWINSZ if available.  If
237 	 * the kernel has values for either we should use them rather than
238 	 * the values from TERMCAP ...
239 	 */
240 # ifndef MICRO
241 	if (!CO) CO = tgetnum("co");
242 	if (!LI) LI = tgetnum("li");
243 # else
244 #  if defined(TOS) && defined(__GNUC__)
245 	if (!strcmp(term, "builtin"))
246 		get_scr_size();
247 	else {
248 #  endif
249 		CO = tgetnum("co");
250 		LI = tgetnum("li");
251 		if (!LI || !CO)			/* if we don't override it */
252 			get_scr_size();
253 #  if defined(TOS) && defined(__GNUC__)
254 	}
255 #  endif
256 # endif
257 # ifdef CLIPPING
258 	if(CO < COLNO || LI < ROWNO+3)
259 		setclipped();
260 # endif
261 	nh_ND = Tgetstr("nd");
262 	if(tgetflag("os"))
263 		error("NetHack can't have OS.");
264 	if(tgetflag("ul"))
265 		ul_hack = TRUE;
266 	CE = Tgetstr("ce");
267 	UP = Tgetstr("up");
268 	/* It seems that xd is no longer supported, and we should use
269 	   a linefeed instead; unfortunately this requires resetting
270 	   CRMOD, and many output routines will have to be modified
271 	   slightly. Let's leave that till the next release. */
272 	XD = Tgetstr("xd");
273 /* not:		XD = Tgetstr("do"); */
274 	if(!(nh_CM = Tgetstr("cm"))) {
275 	    if(!UP && !HO)
276 		error("NetHack needs CM or UP or HO.");
277 	    tty_raw_print("Playing NetHack on terminals without CM is suspect.");
278 	    tty_wait_synch();
279 	}
280 	SO = Tgetstr("so");
281 	SE = Tgetstr("se");
282 	nh_US = Tgetstr("us");
283 	nh_UE = Tgetstr("ue");
284 	SG = tgetnum("sg");	/* -1: not fnd; else # of spaces left by so */
285 	if(!SO || !SE || (SG > 0)) SO = SE = nh_US = nh_UE = nullstr;
286 	TI = Tgetstr("ti");
287 	TE = Tgetstr("te");
288 	VS = VE = nullstr;
289 # ifdef TERMINFO
290 	VS = Tgetstr("eA");	/* enable graphics */
291 # endif
292 	KS = Tgetstr("ks");	/* keypad start (special mode) */
293 	KE = Tgetstr("ke");	/* keypad end (ordinary mode [ie, digits]) */
294 	MR = Tgetstr("mr");	/* reverse */
295 # if 0
296 	MB = Tgetstr("mb");	/* blink */
297 	MD = Tgetstr("md");	/* boldface */
298 	MH = Tgetstr("mh");	/* dim */
299 # endif
300 	ME = Tgetstr("me");	/* turn off all attributes */
301 	if (!ME || (SE == nullstr)) ME = SE;	/* default to SE value */
302 
303 	/* Get rid of padding numbers for nh_HI and nh_HE.  Hope they
304 	 * aren't really needed!!!  nh_HI and nh_HE are outputted to the
305 	 * pager as a string - so how can you send it NULs???
306 	 *  -jsb
307 	 */
308 	nh_HI = (char *) alloc((unsigned)(strlen(SO)+1));
309 	nh_HE = (char *) alloc((unsigned)(strlen(ME)+1));
310 	i = 0;
311 	while (digit(SO[i])) i++;
312 	Strcpy(nh_HI, &SO[i]);
313 	i = 0;
314 	while (digit(ME[i])) i++;
315 	Strcpy(nh_HE, &ME[i]);
316 	AS = Tgetstr("as");
317 	AE = Tgetstr("ae");
318 	nh_CD = Tgetstr("cd");
319 # ifdef TEXTCOLOR
320 	MD = Tgetstr("md");
321 # endif
322 # ifdef TEXTCOLOR
323 #  if defined(TOS) && defined(__GNUC__)
324 	if (!strcmp(term, "builtin") || !strcmp(term, "tw52") ||
325 	    !strcmp(term, "st52")) {
326 		init_hilite();
327 	}
328 #  else
329 	init_hilite();
330 #  endif
331 # endif
332 	*wid = CO;
333 	*hgt = LI;
334 	if (!(CL = Tgetstr("cl")))	/* last thing set */
335 		error("NetHack needs CL.");
336 	if ((int)(tbufptr - tbuf) > (int)(sizeof tbuf))
337 		error("TERMCAP entry too big...\n");
338 	free((genericptr_t)tptr);
339 #endif /* TERMLIB */
340 }
341 
342 /* note: at present, this routine is not part of the formal window interface */
343 /* deallocate resources prior to final termination */
344 void
tty_shutdown()345 tty_shutdown()
346 {
347 #if defined(TEXTCOLOR) && defined(TERMLIB)
348 	kill_hilite();
349 #endif
350 	/* we don't attempt to clean up individual termcap variables [yet?] */
351 	return;
352 }
353 
354 void
tty_number_pad(state)355 tty_number_pad(state)
356 int state;
357 {
358 	switch (state) {
359 	    case -1:	/* activate keypad mode (escape sequences) */
360 		    if (KS && *KS) xputs(KS);
361 		    break;
362 	    case  1:	/* activate numeric mode for keypad (digits) */
363 		    if (KE && *KE) xputs(KE);
364 		    break;
365 	    case  0:	/* don't need to do anything--leave terminal as-is */
366 	    default:
367 		    break;
368 	}
369 }
370 
371 #ifdef TERMLIB
372 extern void NDECL((*decgraphics_mode_callback));    /* defined in drawing.c */
373 static void NDECL(tty_decgraphics_termcap_fixup);
374 
375 /*
376    We call this routine whenever DECgraphics mode is enabled, even if it
377    has been previously set, in case the user manages to reset the fonts.
378    The actual termcap fixup only needs to be done once, but we can't
379    call xputs() from the option setting or graphics assigning routines,
380    so this is a convenient hook.
381  */
382 static void
tty_decgraphics_termcap_fixup()383 tty_decgraphics_termcap_fixup()
384 {
385 	static char ctrlN[]   = "\016";
386 	static char ctrlO[]   = "\017";
387 	static char appMode[] = "\033=";
388 	static char numMode[] = "\033>";
389 
390 	/* these values are missing from some termcaps */
391 	if (!AS) AS = ctrlN;	/* ^N (shift-out [graphics font]) */
392 	if (!AE) AE = ctrlO;	/* ^O (shift-in  [regular font])  */
393 	if (!KS) KS = appMode;	/* ESC= (application keypad mode) */
394 	if (!KE) KE = numMode;	/* ESC> (numeric keypad mode)	  */
395 	/*
396 	 * Select the line-drawing character set as the alternate font.
397 	 * Do not select NA ASCII as the primary font since people may
398 	 * reasonably be using the UK character set.
399 	 */
400 	if (iflags.DECgraphics) xputs("\033)0");
401 #ifdef PC9800
402 	init_hilite();
403 #endif
404 
405 #if defined(ASCIIGRAPH) && !defined(NO_TERMS)
406 	/* some termcaps suffer from the bizarre notion that resetting
407 	   video attributes should also reset the chosen character set */
408     {
409 	const char *nh_he = nh_HE, *ae = AE;
410 	int he_limit, ae_length;
411 
412 	if (digit(*ae)) {	/* skip over delay prefix, if any */
413 	    do ++ae; while (digit(*ae));
414 	    if (*ae == '.') { ++ae; if (digit(*ae)) ++ae; }
415 	    if (*ae == '*') ++ae;
416 	}
417 	/* can't use nethack's case-insensitive strstri() here, and some old
418 	   systems don't have strstr(), so use brute force substring search */
419 	ae_length = strlen(ae), he_limit = strlen(nh_he);
420 	while (he_limit >= ae_length) {
421 	    if (strncmp(nh_he, ae, ae_length) == 0) {
422 		HE_resets_AS = TRUE;
423 		break;
424 	    }
425 	    ++nh_he, --he_limit;
426 	}
427     }
428 #endif
429 }
430 #endif	/* TERMLIB */
431 
432 #if defined(ASCIIGRAPH) && defined(PC9800)
433 extern void NDECL((*ibmgraphics_mode_callback));    /* defined in drawing.c */
434 #endif
435 
436 #ifdef PC9800
437 extern void NDECL((*ascgraphics_mode_callback));    /* defined in drawing.c */
438 static void NDECL(tty_ascgraphics_hilite_fixup);
439 
440 static void
tty_ascgraphics_hilite_fixup()441 tty_ascgraphics_hilite_fixup()
442 {
443     register int c;
444 
445     for (c = 0; c < CLR_MAX / 2; c++)
446 	if (c != CLR_BLACK) {
447 	    hilites[c|BRIGHT] = (char *) alloc(sizeof("\033[1;3%dm"));
448 	    Sprintf(hilites[c|BRIGHT], "\033[1;3%dm", c);
449 	    if (c != CLR_GRAY) {
450 		    hilites[c] = (char *) alloc(sizeof("\033[0;3%dm"));
451 		    Sprintf(hilites[c], "\033[0;3%dm", c);
452 	    }
453 	}
454 }
455 #endif /* PC9800 */
456 
457 void
tty_start_screen()458 tty_start_screen()
459 {
460 	xputs(TI);
461 	xputs(VS);
462 #ifdef PC9800
463     if (!iflags.IBMgraphics && !iflags.DECgraphics)
464 	    tty_ascgraphics_hilite_fixup();
465     /* set up callback in case option is not set yet but toggled later */
466     ascgraphics_mode_callback = tty_ascgraphics_hilite_fixup;
467 # ifdef ASCIIGRAPH
468     if (iflags.IBMgraphics) init_hilite();
469     /* set up callback in case option is not set yet but toggled later */
470     ibmgraphics_mode_callback = init_hilite;
471 # endif
472 #endif /* PC9800 */
473 
474 #ifdef TERMLIB
475 	if (iflags.DECgraphics) tty_decgraphics_termcap_fixup();
476 	/* set up callback in case option is not set yet but toggled later */
477 	decgraphics_mode_callback = tty_decgraphics_termcap_fixup;
478 #endif
479 	if (iflags.num_pad) tty_number_pad(1);	/* make keypad send digits */
480 }
481 
482 void
tty_end_screen()483 tty_end_screen()
484 {
485 	clear_screen();
486 	xputs(VE);
487 	xputs(TE);
488 }
489 
490 /* Cursor movements */
491 
492 #endif /* OVLB */
493 
494 #ifdef OVL0
495 /* Note to OVLx tinkerers.  The placement of this overlay controls the location
496    of the function xputc().  This function is not currently in trampoli.[ch]
497    files for what is deemed to be performance reasons.  If this define is moved
498    and or xputc() is taken out of the ROOT overlay, then action must be taken
499    in trampoli.[ch]. */
500 
501 void
nocmov(x,y)502 nocmov(x, y)
503 int x,y;
504 {
505 	if ((int) ttyDisplay->cury > y) {
506 		if(UP) {
507 			while ((int) ttyDisplay->cury > y) {	/* Go up. */
508 				xputs(UP);
509 				ttyDisplay->cury--;
510 			}
511 		} else if(nh_CM) {
512 			cmov(x, y);
513 		} else if(HO) {
514 			home();
515 			tty_curs(BASE_WINDOW, x+1, y);
516 		} /* else impossible("..."); */
517 	} else if ((int) ttyDisplay->cury < y) {
518 		if(XD) {
519 			while((int) ttyDisplay->cury < y) {
520 				xputs(XD);
521 				ttyDisplay->cury++;
522 			}
523 		} else if(nh_CM) {
524 			cmov(x, y);
525 		} else {
526 			while((int) ttyDisplay->cury < y) {
527 				xputc('\n');
528 				ttyDisplay->curx = 0;
529 				ttyDisplay->cury++;
530 			}
531 		}
532 	}
533 	if ((int) ttyDisplay->curx < x) {		/* Go to the right. */
534 		if(!nh_ND) cmov(x, y); else	/* bah */
535 			/* should instead print what is there already */
536 		while ((int) ttyDisplay->curx < x) {
537 			xputs(nh_ND);
538 			ttyDisplay->curx++;
539 		}
540 	} else if ((int) ttyDisplay->curx > x) {
541 		while ((int) ttyDisplay->curx > x) {	/* Go to the left. */
542 			xputs(BC);
543 			ttyDisplay->curx--;
544 		}
545 	}
546 }
547 
548 void
cmov(x,y)549 cmov(x, y)
550 register int x, y;
551 {
552 	xputs(tgoto(nh_CM, x, y));
553 	ttyDisplay->cury = y;
554 	ttyDisplay->curx = x;
555 }
556 
557 /* See note at OVLx ifdef above.   xputc() is a special function. */
558 void
xputc(c)559 xputc(c)
560 #if defined(apollo)
561 int c;
562 #else
563 char c;
564 #endif
565 {
566 	(void) putchar(c);
567 }
568 
569 void
xputs(s)570 xputs(s)
571 const char *s;
572 {
573 # ifndef TERMLIB
574 	(void) fputs(s, stdout);
575 # else
576 #  if defined(NHSTDC) || defined(ULTRIX_PROTO)
577 	tputs(s, 1, (int (*)())xputc);
578 #  else
579 	tputs(s, 1, xputc);
580 #  endif
581 # endif
582 }
583 
584 void
cl_end()585 cl_end()
586 {
587 	if(CE)
588 		xputs(CE);
589 	else {	/* no-CE fix - free after Harold Rynes */
590 		/* this looks terrible, especially on a slow terminal
591 		   but is better than nothing */
592 		register int cx = ttyDisplay->curx+1;
593 
594 		while(cx < CO) {
595 			xputc(' ');
596 			cx++;
597 		}
598 		tty_curs(BASE_WINDOW, (int)ttyDisplay->curx+1,
599 						(int)ttyDisplay->cury);
600 	}
601 }
602 
603 #endif /* OVL0 */
604 #ifdef OVLB
605 
606 void
clear_screen()607 clear_screen()
608 {
609 	/* note: if CL is null, then termcap initialization failed,
610 		so don't attempt screen-oriented I/O during final cleanup.
611 	 */
612 	if (CL) {
613 		xputs(CL);
614 		home();
615 	}
616 }
617 
618 #endif /* OVLB */
619 #ifdef OVL0
620 
621 void
home()622 home()
623 {
624 	if(HO)
625 		xputs(HO);
626 	else if(nh_CM)
627 		xputs(tgoto(nh_CM, 0, 0));
628 	else
629 		tty_curs(BASE_WINDOW, 1, 0);	/* using UP ... */
630 	ttyDisplay->curx = ttyDisplay->cury = 0;
631 }
632 
633 void
standoutbeg()634 standoutbeg()
635 {
636 	if(SO) xputs(SO);
637 }
638 
639 void
standoutend()640 standoutend()
641 {
642 	if(SE) xputs(SE);
643 }
644 
645 #if 0	/* if you need one of these, uncomment it (here and in extern.h) */
646 void
647 revbeg()
648 {
649 	if(MR) xputs(MR);
650 }
651 
652 void
653 boldbeg()
654 {
655 	if(MD) xputs(MD);
656 }
657 
658 void
659 blinkbeg()
660 {
661 	if(MB) xputs(MB);
662 }
663 
664 void
665 dimbeg()
666 /* not in most termcap entries */
667 {
668 	if(MH) xputs(MH);
669 }
670 
671 void
672 m_end()
673 {
674 	if(ME) xputs(ME);
675 }
676 #endif
677 
678 #endif /* OVL0 */
679 #ifdef OVLB
680 
681 void
backsp()682 backsp()
683 {
684 	xputs(BC);
685 }
686 
687 void
tty_nhbell()688 tty_nhbell()
689 {
690 	if (flags.silent) return;
691 	(void) putchar('\007');		/* curx does not change */
692 	(void) fflush(stdout);
693 }
694 
695 #endif /* OVLB */
696 #ifdef OVL0
697 
698 #ifdef ASCIIGRAPH
699 void
graph_on()700 graph_on() {
701 	if (AS) xputs(AS);
702 }
703 
704 void
graph_off()705 graph_off() {
706 	if (AE) xputs(AE);
707 }
708 #endif
709 
710 #endif /* OVL0 */
711 #ifdef OVL1
712 
713 #if !defined(MICRO)
714 # ifdef VMS
715 static const short tmspc10[] = {		/* from termcap */
716 	0, 2000, 1333, 909, 743, 666, 333, 166, 83, 55, 50, 41, 27, 20, 13, 10,
717 	5
718 };
719 # else
720 static const short tmspc10[] = {		/* from termcap */
721 	0, 2000, 1333, 909, 743, 666, 500, 333, 166, 83, 55, 41, 20, 10, 5
722 };
723 # endif
724 #endif
725 
726 /* delay 50 ms */
727 void
tty_delay_output()728 tty_delay_output()
729 {
730 #if defined(MICRO)
731 	register int i;
732 #endif
733 #ifdef TIMED_DELAY
734 	if (flags.nap) {
735 		(void) fflush(stdout);
736 		msleep(50);		/* sleep for 50 milliseconds */
737 		return;
738 	}
739 #endif
740 #if defined(MICRO)
741 	/* simulate the delay with "cursor here" */
742 	for (i = 0; i < 3; i++) {
743 		cmov(ttyDisplay->curx, ttyDisplay->cury);
744 		(void) fflush(stdout);
745 	}
746 #else /* MICRO */
747 	/* BUG: if the padding character is visible, as it is on the 5620
748 	   then this looks terrible. */
749 	if(flags.null)
750 # ifdef TERMINFO
751 		/* cbosgd!cbcephus!pds for SYS V R2 */
752 #  ifdef NHSTDC
753 		tputs("$<50>", 1, (int (*)())xputc);
754 #  else
755 		tputs("$<50>", 1, xputc);
756 #  endif
757 # else
758 #  if defined(NHSTDC) || defined(ULTRIX_PROTO)
759 		tputs("50", 1, (int (*)())xputc);
760 #  else
761 		tputs("50", 1, xputc);
762 #  endif
763 # endif
764 
765 	else if(ospeed > 0 && ospeed < SIZE(tmspc10) && nh_CM) {
766 		/* delay by sending cm(here) an appropriate number of times */
767 		register int cmlen = strlen(tgoto(nh_CM, ttyDisplay->curx,
768 							ttyDisplay->cury));
769 		register int i = 500 + tmspc10[ospeed]/2;
770 
771 		while(i > 0) {
772 			cmov((int)ttyDisplay->curx, (int)ttyDisplay->cury);
773 			i -= cmlen*tmspc10[ospeed];
774 		}
775 	}
776 #endif /* MICRO */
777 }
778 
779 #endif /* OVL1 */
780 #ifdef OVLB
781 
782 void
cl_eos()783 cl_eos()			/* free after Robert Viduya */
784 {				/* must only be called with curx = 1 */
785 
786 	if(nh_CD)
787 		xputs(nh_CD);
788 	else {
789 		register int cy = ttyDisplay->cury+1;
790 		while(cy <= LI-2) {
791 			cl_end();
792 			xputc('\n');
793 			cy++;
794 		}
795 		cl_end();
796 		tty_curs(BASE_WINDOW, (int)ttyDisplay->curx+1,
797 						(int)ttyDisplay->cury);
798 	}
799 }
800 
801 #if defined(TEXTCOLOR) && defined(TERMLIB)
802 # if defined(UNIX) && defined(TERMINFO)
803 /*
804  * Sets up color highlighting, using terminfo(4) escape sequences.
805  *
806  * Having never seen a terminfo system without curses, we assume this
807  * inclusion is safe.  On systems with color terminfo, it should define
808  * the 8 COLOR_FOOs, and avoid us having to guess whether this particular
809  * terminfo uses BGR or RGB for its indexes.
810  *
811  * If we don't get the definitions, then guess.  Original color terminfos
812  * used BGR for the original Sf (setf, Standard foreground) codes, but
813  * there was a near-total lack of user documentation, so some subsequent
814  * terminfos, such as early Linux ncurses and SCO UNIX, used RGB.  Possibly
815  * as a result of the confusion, AF (setaf, ANSI Foreground) codes were
816  * introduced, but this caused yet more confusion.  Later Linux ncurses
817  * have BGR Sf, RGB AF, and RGB COLOR_FOO, which appears to be the SVR4
818  * standard.  We could switch the colors around when using Sf with ncurses,
819  * which would help things on later ncurses and hurt things on early ncurses.
820  * We'll try just preferring AF and hoping it always agrees with COLOR_FOO,
821  * and falling back to Sf if AF isn't defined.
822  *
823  * In any case, treat black specially so we don't try to display black
824  * characters on the assumed black background.
825  */
826 
827 	/* `curses' is aptly named; various versions don't like these
828 	    macros used elsewhere within nethack; fortunately they're
829 	    not needed beyond this point, so we don't need to worry
830 	    about reconstructing them after the header file inclusion. */
831 #undef delay_output
832 #undef TRUE
833 #undef FALSE
834 #define m_move curses_m_move	/* Some curses.h decl m_move(), not used here */
835 
836 #include <curses.h>
837 
838 #ifndef LINUX
839 extern char *tparm();
840 #endif
841 
842 #  ifdef COLOR_BLACK	/* trust include file */
843 #undef COLOR_BLACK
844 #  else
845 #   ifndef _M_UNIX	/* guess BGR */
846 #define COLOR_BLUE    1
847 #define COLOR_GREEN   2
848 #define COLOR_CYAN    3
849 #define COLOR_RED     4
850 #define COLOR_MAGENTA 5
851 #define COLOR_YELLOW  6
852 #define COLOR_WHITE   7
853 #   else		/* guess RGB */
854 #define COLOR_RED     1
855 #define COLOR_GREEN   2
856 #define COLOR_YELLOW  3
857 #define COLOR_BLUE    4
858 #define COLOR_MAGENTA 5
859 #define COLOR_CYAN    6
860 #define COLOR_WHITE   7
861 #   endif
862 #  endif
863 #define COLOR_BLACK COLOR_BLUE
864 
865 const int ti_map[8] = {
866 	COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_YELLOW,
867 	COLOR_BLUE, COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE };
868 
869 static void
init_hilite()870 init_hilite()
871 {
872 	register int c;
873 	char *setf, *scratch;
874 
875 	for (c = 0; c < SIZE(hilites); c++)
876 		hilites[c] = nh_HI;
877 	hilites[CLR_GRAY] = hilites[NO_COLOR] = (char *)0;
878 
879 	if (tgetnum("Co") < 8
880 	    || ((setf = tgetstr("AF", (char **)0)) == (char *)0
881 		 && (setf = tgetstr("Sf", (char **)0)) == (char *)0))
882 		return;
883 
884 	for (c = 0; c < CLR_MAX / 2; c++) {
885 	    scratch = tparm(setf, ti_map[c]);
886 	    if (c != CLR_GRAY) {
887 		hilites[c] = (char *) alloc(strlen(scratch) + 1);
888 		Strcpy(hilites[c], scratch);
889 	    }
890 	    if (c != CLR_BLACK) {
891 		hilites[c|BRIGHT] = (char*) alloc(strlen(scratch)+strlen(MD)+1);
892 		Strcpy(hilites[c|BRIGHT], MD);
893 		Strcat(hilites[c|BRIGHT], scratch);
894 	    }
895 
896 	}
897 }
898 
899 # else /* UNIX && TERMINFO */
900 
901 #  ifndef TOS
902 /* find the foreground and background colors set by nh_HI or nh_HE */
903 static void
analyze_seq(str,fg,bg)904 analyze_seq (str, fg, bg)
905 char *str;
906 int *fg, *bg;
907 {
908 	register int c, code;
909 	int len;
910 
911 #   ifdef MICRO
912 	*fg = CLR_GRAY; *bg = CLR_BLACK;
913 #   else
914 	*fg = *bg = NO_COLOR;
915 #   endif
916 
917 	c = (str[0] == '\233') ? 1 : 2;	 /* index of char beyond esc prefix */
918 	len = strlen(str) - 1;		 /* length excluding attrib suffix */
919 	if ((c != 1 && (str[0] != '\033' || str[1] != '[')) ||
920 	    (len - c) < 1 || str[len] != 'm')
921 		return;
922 
923 	while (c < len) {
924 	    if ((code = atoi(&str[c])) == 0) { /* reset */
925 		/* this also catches errors */
926 #   ifdef MICRO
927 		*fg = CLR_GRAY; *bg = CLR_BLACK;
928 #   else
929 		*fg = *bg = NO_COLOR;
930 #   endif
931 	    } else if (code == 1) { /* bold */
932 		*fg |= BRIGHT;
933 #   if 0
934 	/* I doubt we'll ever resort to using blinking characters,
935 	   unless we want a pulsing glow for something.  But, in case
936 	   we do... - 3. */
937 	    } else if (code == 5) { /* blinking */
938 		*fg |= BLINK;
939 	    } else if (code == 25) { /* stop blinking */
940 		*fg &= ~BLINK;
941 #   endif
942 	    } else if (code == 7 || code == 27) { /* reverse */
943 		code = *fg & ~BRIGHT;
944 		*fg = *bg | (*fg & BRIGHT);
945 		*bg = code;
946 	    } else if (code >= 30 && code <= 37) { /* hi_foreground RGB */
947 		*fg = code - 30;
948 	    } else if (code >= 40 && code <= 47) { /* hi_background RGB */
949 		*bg = code - 40;
950 	    }
951 	    while (digit(str[++c]));
952 	    c++;
953 	}
954 }
955 #  endif
956 
957 /*
958  * Sets up highlighting sequences, using ANSI escape sequences (highlight code
959  * found in print.c).  The nh_HI and nh_HE sequences (usually from SO) are
960  * scanned to find foreground and background colors.
961  */
962 
963 static void
init_hilite()964 init_hilite()
965 {
966 	register int c;
967 #  ifdef TOS
968 	extern unsigned long tos_numcolors;	/* in tos.c */
969 	static char NOCOL[] = "\033b0", COLHE[] = "\033q\033b0";
970 
971 	if (tos_numcolors <= 2) {
972 		return;
973 	}
974 /* Under TOS, the "bright" and "dim" colors are reversed. Moreover,
975  * on the Falcon the dim colors are *really* dim; so we make most
976  * of the colors the bright versions, with a few exceptions where
977  * the dim ones look OK.
978  */
979 	hilites[0] = NOCOL;
980 	for (c = 1; c < SIZE(hilites); c++) {
981 		char *foo;
982 		foo = (char *) alloc(sizeof("\033b0"));
983 		if (tos_numcolors > 4)
984 			Sprintf(foo, "\033b%c", (c&~BRIGHT)+'0');
985 		else
986 			Strcpy(foo, "\033b0");
987 		hilites[c] = foo;
988 	}
989 
990 	if (tos_numcolors == 4) {
991 		TI = "\033b0\033c3\033E\033e";
992 		TE = "\033b3\033c0\033J";
993 		nh_HE = COLHE;
994 		hilites[CLR_GREEN] = hilites[CLR_GREEN|BRIGHT] = "\033b2";
995 		hilites[CLR_RED] = hilites[CLR_RED|BRIGHT] = "\033b1";
996 	} else {
997 		sprintf(hilites[CLR_BROWN], "\033b%c", (CLR_BROWN^BRIGHT)+'0');
998 		sprintf(hilites[CLR_GREEN], "\033b%c", (CLR_GREEN^BRIGHT)+'0');
999 
1000 		TI = "\033b0\033c\017\033E\033e";
1001 		TE = "\033b\017\033c0\033J";
1002 		nh_HE = COLHE;
1003 		hilites[CLR_WHITE] = hilites[CLR_BLACK] = NOCOL;
1004 		hilites[NO_COLOR] = hilites[CLR_GRAY];
1005 	}
1006 
1007 #  else /* TOS */
1008 
1009 	int backg, foreg, hi_backg, hi_foreg;
1010 
1011 	for (c = 0; c < SIZE(hilites); c++)
1012 	    hilites[c] = nh_HI;
1013 	hilites[CLR_GRAY] = hilites[NO_COLOR] = (char *)0;
1014 
1015 	analyze_seq(nh_HI, &hi_foreg, &hi_backg);
1016 	analyze_seq(nh_HE, &foreg, &backg);
1017 
1018 	for (c = 0; c < SIZE(hilites); c++)
1019 	    /* avoid invisibility */
1020 	    if ((backg & ~BRIGHT) != c) {
1021 #   ifdef MICRO
1022 		if (c == CLR_BLUE) continue;
1023 #   endif
1024 		if (c == foreg)
1025 		    hilites[c] = (char *)0;
1026 		else if (c != hi_foreg || backg != hi_backg) {
1027 		    hilites[c] = (char *) alloc(sizeof("\033[%d;3%d;4%dm"));
1028 		    Sprintf(hilites[c], "\033[%d", !!(c & BRIGHT));
1029 		    if ((c | BRIGHT) != (foreg | BRIGHT))
1030 			Sprintf(eos(hilites[c]), ";3%d", c & ~BRIGHT);
1031 		    if (backg != CLR_BLACK)
1032 			Sprintf(eos(hilites[c]), ";4%d", backg & ~BRIGHT);
1033 		    Strcat(hilites[c], "m");
1034 		}
1035 	    }
1036 
1037 #   ifdef MICRO
1038 	/* brighten low-visibility colors */
1039 	hilites[CLR_BLUE] = hilites[CLR_BLUE|BRIGHT];
1040 #   endif
1041 #  endif /* TOS */
1042 }
1043 # endif /* UNIX */
1044 
1045 static void
kill_hilite()1046 kill_hilite()
1047 {
1048 # ifndef TOS
1049 	register int c;
1050 
1051 	for (c = 0; c < CLR_MAX / 2; c++) {
1052 	    if (hilites[c|BRIGHT] == hilites[c])  hilites[c|BRIGHT] = 0;
1053 	    if (hilites[c] && (hilites[c] != nh_HI))
1054 		free((genericptr_t) hilites[c]),  hilites[c] = 0;
1055 	    if (hilites[c|BRIGHT] && (hilites[c|BRIGHT] != nh_HI))
1056 		free((genericptr_t) hilites[c|BRIGHT]),  hilites[c|BRIGHT] = 0;
1057 	}
1058 # endif
1059 	return;
1060 }
1061 #endif /* TEXTCOLOR */
1062 
1063 
1064 static char nulstr[] = "";
1065 
1066 static char *
s_atr2str(n)1067 s_atr2str(n)
1068 int n;
1069 {
1070     switch (n) {
1071 	    case ATR_ULINE:
1072 		    if(nh_US) return nh_US;
1073 	    case ATR_BOLD:
1074 	    case ATR_BLINK:
1075 		    return nh_HI;
1076 	    case ATR_INVERSE:
1077 		    return MR;
1078     }
1079     return nulstr;
1080 }
1081 
1082 static char *
e_atr2str(n)1083 e_atr2str(n)
1084 int n;
1085 {
1086     switch (n) {
1087 	    case ATR_ULINE:
1088 		    if(nh_UE) return nh_UE;
1089 	    case ATR_BOLD:
1090 	    case ATR_BLINK:
1091 		    return nh_HE;
1092 	    case ATR_INVERSE:
1093 		    return ME;
1094     }
1095     return nulstr;
1096 }
1097 
1098 
1099 void
term_start_attr(attr)1100 term_start_attr(attr)
1101 int attr;
1102 {
1103 	if (attr) {
1104 		xputs(s_atr2str(attr));
1105 	}
1106 }
1107 
1108 
1109 void
term_end_attr(attr)1110 term_end_attr(attr)
1111 int attr;
1112 {
1113 	if(attr) {
1114 		xputs(e_atr2str(attr));
1115 	}
1116 }
1117 
1118 
1119 void
term_start_raw_bold()1120 term_start_raw_bold()
1121 {
1122 	xputs(nh_HI);
1123 }
1124 
1125 
1126 void
term_end_raw_bold()1127 term_end_raw_bold()
1128 {
1129 	xputs(nh_HE);
1130 }
1131 
1132 
1133 #ifdef TEXTCOLOR
1134 
1135 void
term_end_color()1136 term_end_color()
1137 {
1138 	xputs(nh_HE);
1139 }
1140 
1141 
1142 void
term_start_color(color)1143 term_start_color(color)
1144 int color;
1145 {
1146 	xputs(hilites[color]);
1147 }
1148 
1149 
1150 int
has_color(color)1151 has_color(color)
1152 int color;
1153 {
1154 	return hilites[color] != (char *)0;
1155 }
1156 
1157 #endif /* TEXTCOLOR */
1158 
1159 #endif /* OVLB */
1160 
1161 #endif /* TTY_GRAPHICS */
1162 
1163 /*termcap.c*/
1164