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