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