OSDN Git Service

milden exp curve
[nethackexpress/trunk.git] / win / tty / termcap.c
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
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 #if defined(TERMLIB) && defined(TEXTCOLOR)
1076                     if (MD) return MD;
1077 #endif
1078                     return nh_HI;
1079             case ATR_INVERSE:
1080                     return MR;
1081     }
1082     return nulstr;
1083 }
1084
1085 static char *
1086 e_atr2str(n)
1087 int n;
1088 {
1089     switch (n) {
1090             case ATR_ULINE:
1091                     if(nh_UE) return nh_UE;
1092             case ATR_BOLD:
1093             case ATR_BLINK:
1094                     return nh_HE;
1095             case ATR_INVERSE:
1096                     return ME;
1097     }
1098     return nulstr;
1099 }
1100
1101
1102 void
1103 term_start_attr(attr)
1104 int attr;
1105 {
1106         if (attr) {
1107                 xputs(s_atr2str(attr));
1108         }
1109 }
1110
1111
1112 void
1113 term_end_attr(attr)
1114 int attr;
1115 {
1116         if(attr) {
1117                 xputs(e_atr2str(attr));
1118         }
1119 }
1120
1121
1122 void
1123 term_start_raw_bold()
1124 {
1125         xputs(nh_HI);
1126 }
1127
1128
1129 void
1130 term_end_raw_bold()
1131 {
1132         xputs(nh_HE);
1133 }
1134
1135
1136 #ifdef TEXTCOLOR
1137
1138 void
1139 term_end_color()
1140 {
1141         xputs(nh_HE);
1142 }
1143
1144
1145 void
1146 term_start_color(color)
1147 int color;
1148 {
1149         xputs(hilites[color]);
1150 }
1151
1152
1153 int
1154 has_color(color)
1155 int color;
1156 {
1157 #ifdef X11_GRAPHICS
1158         /* XXX has_color() should be added to windowprocs */
1159         if (windowprocs.name != NULL &&
1160             !strcmpi(windowprocs.name, "X11")) return TRUE;
1161 #endif
1162 #ifdef GEM_GRAPHICS
1163         /* XXX has_color() should be added to windowprocs */
1164         if (windowprocs.name != NULL &&
1165             !strcmpi(windowprocs.name, "Gem")) return TRUE;
1166 #endif
1167 #ifdef QT_GRAPHICS
1168         /* XXX has_color() should be added to windowprocs */
1169         if (windowprocs.name != NULL &&
1170             !strcmpi(windowprocs.name, "Qt")) return TRUE;
1171 #endif
1172 #ifdef AMII_GRAPHICS
1173         /* hilites[] not used */
1174         return iflags.use_color;
1175 #endif
1176         return hilites[color] != (char *)0;
1177 }
1178
1179 #endif /* TEXTCOLOR */
1180
1181 #endif /* OVLB */
1182
1183 #endif /* TTY_GRAPHICS */
1184
1185 /*termcap.c*/