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