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