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 boolean colorflag = FALSE; /* colors are initialized */
95 int ttycolors[CLR_MAX];
96
97 void
init_ttycolor()98 init_ttycolor()
99 {
100 if (!colorflag) {
101 ttycolors[CLR_RED] = CLR_RED;
102 ttycolors[CLR_GREEN] = CLR_GREEN;
103 ttycolors[CLR_BROWN] = CLR_BROWN;
104 ttycolors[CLR_BLUE] = CLR_BLUE;
105 ttycolors[CLR_MAGENTA] = CLR_MAGENTA;
106 ttycolors[CLR_CYAN] = CLR_CYAN;
107 ttycolors[CLR_GRAY] = CLR_GRAY;
108 if (iflags.wc2_newcolors) {
109 ttycolors[CLR_BLACK] = CLR_BLACK;
110 defsyms[S_corr].color = CLR_BLACK;
111 defsyms[S_dnstair].color= CLR_WHITE;
112 defsyms[S_upstair].color= CLR_WHITE;
113 } else {
114 ttycolors[CLR_BLACK] = CLR_BLUE;
115 }
116 ttycolors[CLR_ORANGE] = CLR_ORANGE;
117 ttycolors[CLR_BRIGHT_GREEN] = CLR_BRIGHT_GREEN;
118 ttycolors[CLR_YELLOW] = CLR_YELLOW;
119 ttycolors[CLR_BRIGHT_BLUE] = CLR_BRIGHT_BLUE;
120 ttycolors[CLR_BRIGHT_MAGENTA] = CLR_BRIGHT_MAGENTA;
121 ttycolors[CLR_BRIGHT_CYAN] = CLR_BRIGHT_CYAN;
122 ttycolors[CLR_WHITE] = CLR_WHITE;
123 }
124 }
125
126 static int FDECL(convert_uchars,(char *, uchar *, int));
127
128 #ifdef VIDEOSHADES
129 /*
130 * OPTIONS=videocolors:1-2-3-4-5-6-7-8-9-10-11-12-13-14-15
131 * Left to right assignments for:
132 * red green brown blue magenta cyan gray black
133 * orange br.green yellow br.blue br.mag br.cyan white
134 */
assign_videocolors(char * colorvals)135 int assign_videocolors(char *colorvals)
136 {
137 int i,icolor;
138 uchar *tmpcolor;
139
140 init_ttycolor();
141
142 i = strlen(colorvals);
143 tmpcolor = (uchar *)alloc(i);
144 if (convert_uchars(colorvals,tmpcolor,i) < 0) return FALSE;
145
146 icolor = CLR_RED;
147 for( i = 0; tmpcolor[i] != 0; ++i) {
148 if (icolor <= CLR_WHITE)
149 ttycolors[icolor++] = tmpcolor[i];
150 }
151
152 colorflag = TRUE;
153 free((genericptr_t)tmpcolor);
154 return 1;
155 }
156 #endif
157
158 static int
convert_uchars(bufp,list,size)159 convert_uchars(bufp,list,size)
160 char *bufp; /* current pointer */
161 uchar *list; /* return list */
162 int size;
163 {
164 unsigned int num = 0;
165 int count = 0;
166
167 list[count] = 0;
168
169 while (1) {
170 switch(*bufp) {
171 case ' ': case '\0':
172 case '\t': case '-':
173 case '\n':
174 if (num) {
175 list[count++] = num;
176 list[count] = 0;
177 num = 0;
178 }
179 if ((count==size) || !*bufp) return count;
180 bufp++;
181 break;
182 case '#':
183 if (num) {
184 list[count++] = num;
185 list[count] = 0;
186 }
187 return count;
188 case '0': case '1': case '2': case '3':
189 case '4': case '5': case '6': case '7':
190 case '8': case '9':
191 num = num*10 + (*bufp-'0');
192 if (num > 15) return -1;
193 bufp++;
194 break;
195 default: return -1;
196 }
197 }
198 /*NOTREACHED*/
199 }
200 #endif /* !MSDOS */
201
202 #ifdef OVLB
203
204 void
tty_startup(wid,hgt)205 tty_startup(wid, hgt)
206 int *wid, *hgt;
207 {
208 register int i;
209 #ifdef TERMLIB
210 register const char *term;
211 register char *tptr;
212 char *tbufptr, *pc;
213 #endif
214
215 #ifdef TEXTCOLOR
216 # ifndef MSDOS
217 init_ttycolor();
218 # endif
219 #endif
220
221 #ifdef TERMLIB
222
223 # ifdef VMS
224 term = verify_termcap();
225 if (!term)
226 # endif
227 term = getenv("TERM");
228
229 # if defined(TOS) && defined(__GNUC__)
230 if (!term)
231 term = "builtin"; /* library has a default */
232 # endif
233 if (!term)
234 #endif
235 #ifndef ANSI_DEFAULT
236 error("Can't get TERM.");
237 #else
238 # ifdef TOS
239 {
240 CO = 80; LI = 25;
241 TI = VS = VE = TE = nullstr;
242 HO = "\033H";
243 CE = "\033K"; /* the VT52 termcap */
244 UP = "\033A";
245 nh_CM = "\033Y%c%c"; /* used with function tgoto() */
246 nh_ND = "\033C";
247 XD = "\033B";
248 BC = "\033D";
249 SO = "\033p";
250 SE = "\033q";
251 /* HI and HE will be updated in init_hilite if we're using color */
252 nh_HI = "\033p";
253 nh_HE = "\033q";
254 *wid = CO;
255 *hgt = LI;
256 CL = "\033E"; /* last thing set */
257 return;
258 }
259 # else /* TOS */
260 {
261 # ifdef MICRO
262 get_scr_size();
263 # ifdef CLIPPING
264 if(CO < COLNO || LI < ROWNO+3)
265 setclipped();
266 # endif
267 # endif
268 HO = "\033[H";
269 /* nh_CD = "\033[J"; */
270 CE = "\033[K"; /* the ANSI termcap */
271 # ifndef TERMLIB
272 nh_CM = "\033[%d;%dH";
273 # else
274 nh_CM = "\033[%i%d;%dH";
275 # endif
276 UP = "\033[A";
277 nh_ND = "\033[C";
278 XD = "\033[B";
279 # ifdef MICRO /* backspaces are non-destructive */
280 BC = "\b";
281 # else
282 BC = "\033[D";
283 # endif
284 nh_HI = SO = "\033[1m";
285 nh_US = "\033[4m";
286 MR = "\033[7m";
287 TI = nh_HE = ME = SE = nh_UE = "\033[0m";
288 /* strictly, SE should be 2, and nh_UE should be 24,
289 but we can't trust all ANSI emulators to be
290 that complete. -3. */
291 # ifndef MICRO
292 AS = "\016";
293 AE = "\017";
294 # endif
295 TE = VS = VE = nullstr;
296 # ifdef TEXTCOLOR
297 for (i = 0; i < CLR_MAX / 2; i++)
298 if (i != CLR_BLACK) {
299 hilites[i|BRIGHT] = (char *) alloc(sizeof("\033[1;3%dm"));
300 Sprintf(hilites[i|BRIGHT], "\033[1;3%dm", i);
301 if (iflags.wc2_newcolors || (i != CLR_GRAY))
302 # ifdef MICRO
303 if (i == CLR_BLUE) hilites[CLR_BLUE] = hilites[CLR_BLUE|BRIGHT];
304 else
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("UnNetHack 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("UnNetHack needs CM or UP or HO.");
398 tty_raw_print("Playing UnNetHack 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("UnNetHack 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 if (iflags.wc2_newcolors || (c != CLR_GRAY)) {
571 hilites[c] = (char *) alloc(sizeof("\033[0;3%dm"));
572 Sprintf(hilites[c], "\033[0;3%dm", c);
573 }
574 }
575 }
576 #endif /* PC9800 */
577
578 void
tty_start_screen()579 tty_start_screen()
580 {
581 xputs(TI);
582 xputs(VS);
583 #ifdef PC9800
584 if (!iflags.IBMgraphics && !iflags.DECgraphics)
585 tty_ascgraphics_hilite_fixup();
586 /* set up callback in case option is not set yet but toggled later */
587 ascgraphics_mode_callback = tty_ascgraphics_hilite_fixup;
588 # ifdef ASCIIGRAPH
589 if (iflags.IBMgraphics) init_hilite();
590 /* set up callback in case option is not set yet but toggled later */
591 ibmgraphics_mode_callback = init_hilite;
592 # endif
593 #endif /* PC9800 */
594
595 #ifdef TERMLIB
596 if (iflags.DECgraphics) tty_decgraphics_termcap_fixup();
597 /* set up callback in case option is not set yet but toggled later */
598 decgraphics_mode_callback = tty_decgraphics_termcap_fixup;
599 #endif
600 if (iflags.num_pad) tty_number_pad(1); /* make keypad send digits */
601 }
602
603 void
tty_end_screen()604 tty_end_screen()
605 {
606 clear_screen();
607 xputs(VE);
608 xputs(TE);
609 }
610
611 /* Cursor movements */
612
613 #endif /* OVLB */
614
615 #ifdef OVL0
616 /* Note to OVLx tinkerers. The placement of this overlay controls the location
617 of the function xputc(). This function is not currently in trampoli.[ch]
618 files for what is deemed to be performance reasons. If this define is moved
619 and or xputc() is taken out of the ROOT overlay, then action must be taken
620 in trampoli.[ch]. */
621
622 void
nocmov(x,y)623 nocmov(x, y)
624 int x,y;
625 {
626 if ((int) ttyDisplay->cury > y) {
627 if(UP) {
628 while ((int) ttyDisplay->cury > y) { /* Go up. */
629 xputs(UP);
630 ttyDisplay->cury--;
631 }
632 } else if(nh_CM) {
633 cmov(x, y);
634 } else if(HO) {
635 home();
636 tty_curs(BASE_WINDOW, x+1, y);
637 } /* else impossible("..."); */
638 } else if ((int) ttyDisplay->cury < y) {
639 if(XD) {
640 while((int) ttyDisplay->cury < y) {
641 xputs(XD);
642 ttyDisplay->cury++;
643 }
644 } else if(nh_CM) {
645 cmov(x, y);
646 } else {
647 while((int) ttyDisplay->cury < y) {
648 xputc('\n');
649 ttyDisplay->curx = 0;
650 ttyDisplay->cury++;
651 }
652 }
653 }
654 if ((int) ttyDisplay->curx < x) { /* Go to the right. */
655 if(!nh_ND) cmov(x, y); else /* bah */
656 /* should instead print what is there already */
657 while ((int) ttyDisplay->curx < x) {
658 xputs(nh_ND);
659 ttyDisplay->curx++;
660 }
661 } else if ((int) ttyDisplay->curx > x) {
662 while ((int) ttyDisplay->curx > x) { /* Go to the left. */
663 xputs(BC);
664 ttyDisplay->curx--;
665 }
666 }
667 }
668
669 void
cmov(x,y)670 cmov(x, y)
671 register int x, y;
672 {
673 xputs(tgoto(nh_CM, x, y));
674 ttyDisplay->cury = y;
675 ttyDisplay->curx = x;
676 }
677
678 /* See note at OVLx ifdef above. xputc() is a special function. */
679 void
xputc(c)680 xputc(c)
681 #if defined(apollo)
682 int c;
683 #else
684 char c;
685 #endif
686 {
687 (void) putchar(c);
688 }
689
690 void
xputs(s)691 xputs(s)
692 const char *s;
693 {
694 # ifndef TERMLIB
695 (void) fputs(s, stdout);
696 # else
697 # if defined(NHSTDC) || defined(ULTRIX_PROTO)
698 tputs(s, 1, (int (*)())xputc);
699 # else
700 tputs(s, 1, xputc);
701 # endif
702 # endif
703 }
704
705 void
cl_end()706 cl_end()
707 {
708 if(CE)
709 xputs(CE);
710 else { /* no-CE fix - free after Harold Rynes */
711 /* this looks terrible, especially on a slow terminal
712 but is better than nothing */
713 register int cx = ttyDisplay->curx+1;
714
715 while(cx < CO) {
716 xputc(' ');
717 cx++;
718 }
719 tty_curs(BASE_WINDOW, (int)ttyDisplay->curx+1,
720 (int)ttyDisplay->cury);
721 }
722 }
723
724 #endif /* OVL0 */
725 #ifdef OVLB
726
727 void
clear_screen()728 clear_screen()
729 {
730 /* note: if CL is null, then termcap initialization failed,
731 so don't attempt screen-oriented I/O during final cleanup.
732 */
733 if (CL) {
734 xputs(CL);
735 home();
736 }
737 }
738
739 #endif /* OVLB */
740 #ifdef OVL0
741
742 void
home()743 home()
744 {
745 if(HO)
746 xputs(HO);
747 else if(nh_CM)
748 xputs(tgoto(nh_CM, 0, 0));
749 else
750 tty_curs(BASE_WINDOW, 1, 0); /* using UP ... */
751 ttyDisplay->curx = ttyDisplay->cury = 0;
752 }
753
754 void
standoutbeg()755 standoutbeg()
756 {
757 if(SO) xputs(SO);
758 }
759
760 void
standoutend()761 standoutend()
762 {
763 if(SE) xputs(SE);
764 }
765
766 #if 0 /* if you need one of these, uncomment it (here and in extern.h) */
767 void
768 revbeg()
769 {
770 if(MR) xputs(MR);
771 }
772
773 void
774 boldbeg()
775 {
776 if(MD) xputs(MD);
777 }
778
779 void
780 blinkbeg()
781 {
782 if(MB) xputs(MB);
783 }
784
785 void
786 dimbeg()
787 /* not in most termcap entries */
788 {
789 if(MH) xputs(MH);
790 }
791
792 void
793 m_end()
794 {
795 if(ME) xputs(ME);
796 }
797 #endif
798
799 #endif /* OVL0 */
800 #ifdef OVLB
801
802 void
backsp()803 backsp()
804 {
805 xputs(BC);
806 }
807
808 void
tty_nhbell()809 tty_nhbell()
810 {
811 if (flags.silent) return;
812 (void) putchar('\007'); /* curx does not change */
813 (void) fflush(stdout);
814 }
815
816 #endif /* OVLB */
817 #ifdef OVL0
818
819 #ifdef ASCIIGRAPH
820 void
graph_on()821 graph_on() {
822 if (AS) xputs(AS);
823 }
824
825 void
graph_off()826 graph_off() {
827 if (AE) xputs(AE);
828 }
829 #endif
830
831 #endif /* OVL0 */
832 #ifdef OVL1
833
834 #if !defined(MICRO)
835 # ifdef VMS
836 static const short tmspc10[] = { /* from termcap */
837 0, 2000, 1333, 909, 743, 666, 333, 166, 83, 55, 50, 41, 27, 20, 13, 10,
838 5
839 };
840 # else
841 static const short tmspc10[] = { /* from termcap */
842 0, 2000, 1333, 909, 743, 666, 500, 333, 166, 83, 55, 41, 20, 10, 5
843 };
844 # endif
845 #endif
846
847 /* delay 50 ms */
848 void
tty_delay_output()849 tty_delay_output()
850 {
851 #if defined(MICRO)
852 register int i;
853 #endif
854 #ifdef TIMED_DELAY
855 if (flags.nap) {
856 (void) fflush(stdout);
857 msleep(50); /* sleep for 50 milliseconds */
858 return;
859 }
860 #endif
861 #if defined(MICRO)
862 /* simulate the delay with "cursor here" */
863 for (i = 0; i < 3; i++) {
864 cmov(ttyDisplay->curx, ttyDisplay->cury);
865 (void) fflush(stdout);
866 }
867 #else /* MICRO */
868 /* BUG: if the padding character is visible, as it is on the 5620
869 then this looks terrible. */
870 if(flags.null)
871 # ifdef TERMINFO
872 /* cbosgd!cbcephus!pds for SYS V R2 */
873 # ifdef NHSTDC
874 tputs("$<50>", 1, (int (*)())xputc);
875 # else
876 tputs("$<50>", 1, xputc);
877 # endif
878 # else
879 # if defined(NHSTDC) || defined(ULTRIX_PROTO)
880 tputs("50", 1, (int (*)())xputc);
881 # else
882 tputs("50", 1, xputc);
883 # endif
884 # endif
885
886 else if(ospeed > 0 && ospeed < SIZE(tmspc10) && nh_CM) {
887 /* delay by sending cm(here) an appropriate number of times */
888 register int cmlen = strlen(tgoto(nh_CM, ttyDisplay->curx,
889 ttyDisplay->cury));
890 register int i = 500 + tmspc10[ospeed]/2;
891
892 while(i > 0) {
893 cmov((int)ttyDisplay->curx, (int)ttyDisplay->cury);
894 i -= cmlen*tmspc10[ospeed];
895 }
896 }
897 #endif /* MICRO */
898 }
899
900 #endif /* OVL1 */
901 #ifdef OVLB
902
903 void
cl_eos()904 cl_eos() /* free after Robert Viduya */
905 { /* must only be called with curx = 1 */
906
907 if(nh_CD)
908 xputs(nh_CD);
909 else {
910 register int cy = ttyDisplay->cury+1;
911 while(cy <= LI-2) {
912 cl_end();
913 xputc('\n');
914 cy++;
915 }
916 cl_end();
917 tty_curs(BASE_WINDOW, (int)ttyDisplay->curx+1,
918 (int)ttyDisplay->cury);
919 }
920 }
921
922 #if defined(TEXTCOLOR) && defined(TERMLIB)
923 # if defined(UNIX) && defined(TERMINFO)
924 /*
925 * Sets up color highlighting, using terminfo(4) escape sequences.
926 *
927 * Having never seen a terminfo system without curses, we assume this
928 * inclusion is safe. On systems with color terminfo, it should define
929 * the 8 COLOR_FOOs, and avoid us having to guess whether this particular
930 * terminfo uses BGR or RGB for its indexes.
931 *
932 * If we don't get the definitions, then guess. Original color terminfos
933 * used BGR for the original Sf (setf, Standard foreground) codes, but
934 * there was a near-total lack of user documentation, so some subsequent
935 * terminfos, such as early Linux ncurses and SCO UNIX, used RGB. Possibly
936 * as a result of the confusion, AF (setaf, ANSI Foreground) codes were
937 * introduced, but this caused yet more confusion. Later Linux ncurses
938 * have BGR Sf, RGB AF, and RGB COLOR_FOO, which appears to be the SVR4
939 * standard. We could switch the colors around when using Sf with ncurses,
940 * which would help things on later ncurses and hurt things on early ncurses.
941 * We'll try just preferring AF and hoping it always agrees with COLOR_FOO,
942 * and falling back to Sf if AF isn't defined.
943 *
944 * In any case, treat black specially so we don't try to display black
945 * characters on the assumed black background.
946 */
947
948 /* `curses' is aptly named; various versions don't like these
949 macros used elsewhere within nethack; fortunately they're
950 not needed beyond this point, so we don't need to worry
951 about reconstructing them after the header file inclusion. */
952 #undef delay_output
953 #undef TRUE
954 #undef FALSE
955 #define m_move curses_m_move /* Some curses.h decl m_move(), not used here */
956
957 #include <curses.h>
958
959 #ifndef HAVE_TPARM
960 extern char *tparm();
961 #endif
962
963 # ifdef COLOR_BLACK /* trust include file */
964 #ifndef VIDEOSHADES
965 #undef COLOR_BLACK
966 #endif
967 # else
968 # ifndef _M_UNIX /* guess BGR */
969 #ifdef VIDEOSHADES
970 #define COLOR_BLACK 0
971 #endif
972 #define COLOR_BLUE 1
973 #define COLOR_GREEN 2
974 #define COLOR_CYAN 3
975 #define COLOR_RED 4
976 #define COLOR_MAGENTA 5
977 #define COLOR_YELLOW 6
978 #define COLOR_WHITE 7
979 # else /* guess RGB */
980 #define COLOR_RED 1
981 #define COLOR_GREEN 2
982 #define COLOR_YELLOW 3
983 #define COLOR_BLUE 4
984 #define COLOR_MAGENTA 5
985 #define COLOR_CYAN 6
986 #define COLOR_WHITE 7
987 # endif
988 # endif
989 #ifndef VIDEOSHADES
990 #define COLOR_BLACK COLOR_BLUE
991 #endif
992
993 const int ti_map[8] = {
994 COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_YELLOW,
995 COLOR_BLUE, COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE };
996
997 static void
init_hilite()998 init_hilite()
999 {
1000 register int c;
1001 char *setf, *scratch;
1002
1003 for (c = 0; c < SIZE(hilites); c++)
1004 hilites[c] = nh_HI;
1005 hilites[CLR_GRAY] = hilites[NO_COLOR] = (char *)0;
1006
1007 if (tgetnum("Co") < 8
1008 || ((setf = tgetstr("AF", (char **)0)) == (char *)0
1009 && (setf = tgetstr("Sf", (char **)0)) == (char *)0))
1010 return;
1011
1012 for (c = 0; c < CLR_MAX / 2; c++) {
1013 scratch = tparm(setf, ti_map[c]);
1014 if (iflags.wc2_newcolors || (c != CLR_GRAY)) {
1015 hilites[c] = (char *) alloc(strlen(scratch) + 1);
1016 Strcpy(hilites[c], scratch);
1017 }
1018 if (c != CLR_BLACK) {
1019 hilites[c|BRIGHT] = (char*) alloc(strlen(scratch)+strlen(MD)+1);
1020 Strcpy(hilites[c|BRIGHT], MD);
1021 Strcat(hilites[c|BRIGHT], scratch);
1022 }
1023
1024 }
1025 if (!iflags.wc2_newcolors)
1026 hilites[CLR_BLACK] = hilites[CLR_BLUE];
1027 }
1028
1029 # else /* UNIX && TERMINFO */
1030
1031 # ifndef TOS
1032 /* find the foreground and background colors set by nh_HI or nh_HE */
1033 static void
analyze_seq(str,fg,bg)1034 analyze_seq (str, fg, bg)
1035 char *str;
1036 int *fg, *bg;
1037 {
1038 register int c, code;
1039 int len;
1040
1041 # ifdef MICRO
1042 *fg = CLR_GRAY; *bg = CLR_BLACK;
1043 # else
1044 *fg = *bg = NO_COLOR;
1045 # endif
1046
1047 c = (str[0] == '\233') ? 1 : 2; /* index of char beyond esc prefix */
1048 len = strlen(str) - 1; /* length excluding attrib suffix */
1049 if ((c != 1 && (str[0] != '\033' || str[1] != '[')) ||
1050 (len - c) < 1 || str[len] != 'm')
1051 return;
1052
1053 while (c < len) {
1054 if ((code = atoi(&str[c])) == 0) { /* reset */
1055 /* this also catches errors */
1056 # ifdef MICRO
1057 *fg = CLR_GRAY; *bg = CLR_BLACK;
1058 # else
1059 *fg = *bg = NO_COLOR;
1060 # endif
1061 } else if (code == 1) { /* bold */
1062 *fg |= BRIGHT;
1063 # if 0
1064 /* I doubt we'll ever resort to using blinking characters,
1065 unless we want a pulsing glow for something. But, in case
1066 we do... - 3. */
1067 } else if (code == 5) { /* blinking */
1068 *fg |= BLINK;
1069 } else if (code == 25) { /* stop blinking */
1070 *fg &= ~BLINK;
1071 # endif
1072 } else if (code == 7 || code == 27) { /* reverse */
1073 code = *fg & ~BRIGHT;
1074 *fg = *bg | (*fg & BRIGHT);
1075 *bg = code;
1076 } else if (code >= 30 && code <= 37) { /* hi_foreground RGB */
1077 *fg = code - 30;
1078 } else if (code >= 40 && code <= 47) { /* hi_background RGB */
1079 *bg = code - 40;
1080 }
1081 while (digit(str[++c]));
1082 c++;
1083 }
1084 }
1085 # endif
1086
1087 /*
1088 * Sets up highlighting sequences, using ANSI escape sequences (highlight code
1089 * found in print.c). The nh_HI and nh_HE sequences (usually from SO) are
1090 * scanned to find foreground and background colors.
1091 */
1092
1093 static void
init_hilite()1094 init_hilite()
1095 {
1096 register int c;
1097 # ifdef TOS
1098 extern unsigned long tos_numcolors; /* in tos.c */
1099 static char NOCOL[] = "\033b0", COLHE[] = "\033q\033b0";
1100
1101 if (tos_numcolors <= 2) {
1102 return;
1103 }
1104 /* Under TOS, the "bright" and "dim" colors are reversed. Moreover,
1105 * on the Falcon the dim colors are *really* dim; so we make most
1106 * of the colors the bright versions, with a few exceptions where
1107 * the dim ones look OK.
1108 */
1109 hilites[0] = NOCOL;
1110 for (c = 1; c < SIZE(hilites); c++) {
1111 char *foo;
1112 foo = (char *) alloc(sizeof("\033b0"));
1113 if (tos_numcolors > 4)
1114 Sprintf(foo, "\033b%c", (c&~BRIGHT)+'0');
1115 else
1116 Strcpy(foo, "\033b0");
1117 hilites[c] = foo;
1118 }
1119
1120 if (tos_numcolors == 4) {
1121 TI = "\033b0\033c3\033E\033e";
1122 TE = "\033b3\033c0\033J";
1123 nh_HE = COLHE;
1124 hilites[CLR_GREEN] = hilites[CLR_GREEN|BRIGHT] = "\033b2";
1125 hilites[CLR_RED] = hilites[CLR_RED|BRIGHT] = "\033b1";
1126 } else {
1127 sprintf(hilites[CLR_BROWN], "\033b%c", (CLR_BROWN^BRIGHT)+'0');
1128 sprintf(hilites[CLR_GREEN], "\033b%c", (CLR_GREEN^BRIGHT)+'0');
1129
1130 TI = "\033b0\033c\017\033E\033e";
1131 TE = "\033b\017\033c0\033J";
1132 nh_HE = COLHE;
1133 hilites[CLR_WHITE] = hilites[CLR_BLACK] = NOCOL;
1134 hilites[NO_COLOR] = hilites[CLR_GRAY];
1135 }
1136
1137 # else /* TOS */
1138
1139 int backg, foreg, hi_backg, hi_foreg;
1140
1141 for (c = 0; c < SIZE(hilites); c++)
1142 hilites[c] = nh_HI;
1143 hilites[CLR_GRAY] = hilites[NO_COLOR] = (char *)0;
1144
1145 analyze_seq(nh_HI, &hi_foreg, &hi_backg);
1146 analyze_seq(nh_HE, &foreg, &backg);
1147
1148 for (c = 0; c < SIZE(hilites); c++)
1149 /* avoid invisibility */
1150 if ((backg & ~BRIGHT) != c) {
1151 # ifdef MICRO
1152 if (c == CLR_BLUE) continue;
1153 # endif
1154 if (c == foreg)
1155 hilites[c] = (char *)0;
1156 else if (c != hi_foreg || backg != hi_backg) {
1157 hilites[c] = (char *) alloc(sizeof("\033[%d;3%d;4%dm"));
1158 Sprintf(hilites[c], "\033[%d", !!(c & BRIGHT));
1159 if ((c | BRIGHT) != (foreg | BRIGHT))
1160 Sprintf(eos(hilites[c]), ";3%d", c & ~BRIGHT);
1161 if (backg != CLR_BLACK)
1162 Sprintf(eos(hilites[c]), ";4%d", backg & ~BRIGHT);
1163 Strcat(hilites[c], "m");
1164 }
1165 }
1166
1167 # ifdef MICRO
1168 /* brighten low-visibility colors */
1169 hilites[CLR_BLUE] = hilites[CLR_BLUE|BRIGHT];
1170 # endif
1171 # endif /* TOS */
1172 }
1173 # endif /* UNIX */
1174
1175 static void
kill_hilite()1176 kill_hilite()
1177 {
1178 # ifndef TOS
1179 register int c;
1180
1181 for (c = 0; c < CLR_MAX / 2; c++) {
1182 if ((!iflags.wc2_newcolors) &&
1183 (c == CLR_BLUE || c == CLR_GRAY)) continue;
1184
1185 if (hilites[c|BRIGHT] == hilites[c]) hilites[c|BRIGHT] = 0;
1186 if (hilites[c] && (hilites[c] != nh_HI))
1187 free((genericptr_t) hilites[c]), hilites[c] = 0;
1188 if (hilites[c|BRIGHT] && (hilites[c|BRIGHT] != nh_HI))
1189 free((genericptr_t) hilites[c|BRIGHT]), hilites[c|BRIGHT] = 0;
1190 }
1191 # endif
1192 return;
1193 }
1194 #endif /* TEXTCOLOR */
1195
1196
1197 static char nulstr[] = "";
1198
1199 static char *
s_atr2str(n)1200 s_atr2str(n)
1201 int n;
1202 {
1203 switch (n) {
1204 case ATR_ULINE:
1205 if(nh_US) return nh_US;
1206 case ATR_BOLD:
1207 case ATR_BLINK:
1208 #if defined(TERMLIB) && defined(TEXTCOLOR)
1209 if (MD) return MD;
1210 #endif
1211 return nh_HI;
1212 case ATR_INVERSE:
1213 return MR;
1214 }
1215 return nulstr;
1216 }
1217
1218 static char *
e_atr2str(n)1219 e_atr2str(n)
1220 int n;
1221 {
1222 switch (n) {
1223 case ATR_ULINE:
1224 if(nh_UE) return nh_UE;
1225 case ATR_BOLD:
1226 case ATR_BLINK:
1227 return nh_HE;
1228 case ATR_INVERSE:
1229 return ME;
1230 }
1231 return nulstr;
1232 }
1233
1234
1235 void
term_start_attr(attr)1236 term_start_attr(attr)
1237 int attr;
1238 {
1239 if (attr) {
1240 xputs(s_atr2str(attr));
1241 }
1242 }
1243
1244
1245 void
term_end_attr(attr)1246 term_end_attr(attr)
1247 int attr;
1248 {
1249 if(attr) {
1250 xputs(e_atr2str(attr));
1251 }
1252 }
1253
1254
1255 void
term_start_raw_bold()1256 term_start_raw_bold()
1257 {
1258 xputs(nh_HI);
1259 }
1260
1261
1262 void
term_end_raw_bold()1263 term_end_raw_bold()
1264 {
1265 xputs(nh_HE);
1266 }
1267
1268
1269 #ifdef TEXTCOLOR
1270
1271 void
term_end_color()1272 term_end_color()
1273 {
1274 xputs(nh_HE);
1275 }
1276
1277
1278 void
term_start_color(color)1279 term_start_color(color)
1280 int color;
1281 {
1282 if (iflags.wc2_newcolors)
1283 xputs(hilites[ttycolors[color]]);
1284 else
1285 xputs(hilites[color]);
1286 }
1287
1288
1289 int
has_color(color)1290 has_color(color)
1291 int color;
1292 {
1293 #ifdef X11_GRAPHICS
1294 /* XXX has_color() should be added to windowprocs */
1295 if (windowprocs.name != NULL &&
1296 !strcmpi(windowprocs.name, "X11")) return TRUE;
1297 #endif
1298 #ifdef GEM_GRAPHICS
1299 /* XXX has_color() should be added to windowprocs */
1300 if (windowprocs.name != NULL &&
1301 !strcmpi(windowprocs.name, "Gem")) return TRUE;
1302 #endif
1303 #ifdef QT_GRAPHICS
1304 /* XXX has_color() should be added to windowprocs */
1305 if (windowprocs.name != NULL &&
1306 !strcmpi(windowprocs.name, "Qt")) return TRUE;
1307 #endif
1308 #ifdef AMII_GRAPHICS
1309 /* hilites[] not used */
1310 return iflags.use_color;
1311 #endif
1312 #ifdef CURSES_GRAPHICS
1313 /* XXX has_color() should be added to windowprocs */
1314 /* iflags.wc_color is set to false and the option disabled if the
1315 terminal cannot display color */
1316 if (windowprocs.name != NULL &&
1317 !strcmpi(windowprocs.name, "curses")) return iflags.wc_color;
1318 #endif
1319 return hilites[color] != (char *)0;
1320 }
1321
1322 #endif /* TEXTCOLOR */
1323
1324 #endif /* OVLB */
1325
1326 #endif /* TTY_GRAPHICS */
1327
1328 /*termcap.c*/
1329