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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
634 | standoutbeg()
635 | {
636 | if(SO) xputs(SO);
637 | }
638 |
639 | void
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
682 | backsp()
683 | {
684 | xputs(BC);
685 | }
686 |
687 | void
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
700 | graph_on() {
701 | if (AS) xputs(AS);
702 | }
703 |
704 | void
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
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
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
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
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
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
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 *
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 *
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
1100 | term_start_attr(attr)
1101 | int attr;
1102 | {
1103 | if (attr) {
1104 | xputs(s_atr2str(attr));
1105 | }
1106 | }
1107 |
1108 |
1109 | void
1110 | term_end_attr(attr)
1111 | int attr;
1112 | {
1113 | if(attr) {
1114 | xputs(e_atr2str(attr));
1115 | }
1116 | }
1117 |
1118 |
1119 | void
1120 | term_start_raw_bold()
1121 | {
1122 | xputs(nh_HI);
1123 | }
1124 |
1125 |
1126 | void
1127 | term_end_raw_bold()
1128 | {
1129 | xputs(nh_HE);
1130 | }
1131 |
1132 |
1133 | #ifdef TEXTCOLOR
1134 |
1135 | void
1136 | term_end_color()
1137 | {
1138 | xputs(nh_HE);
1139 | }
1140 |
1141 |
1142 | void
1143 | term_start_color(color)
1144 | int color;
1145 | {
1146 | xputs(hilites[color]);
1147 | }
1148 |
1149 |
1150 | int
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*/