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