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