home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 365_01 / curses.c < prev    next >
C/C++ Source or Header  |  1992-04-06  |  23KB  |  1,025 lines

  1. /* curses.c */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    14407 SW Teal Blvd. #C
  6.  *    Beaverton, OR 97005
  7.  *    kirkenda@cs.pdx.edu
  8.  */
  9.  
  10.  
  11. /* This file contains the functions & variables needed for a tiny subset of
  12.  * curses.  The principle advantage of this version of curses is its
  13.  * extreme speed.  Disadvantages are potentially larger code, few supported
  14.  * functions, limited compatibility with full curses, and only stdscr.
  15.  */
  16.  
  17. #include "config.h"
  18. #include "vi.h"
  19.  
  20. #if ANY_UNIX
  21. # if UNIXV
  22. #  ifdef TERMIOS
  23. #   include    <termios.h>
  24. #  else
  25. #   include    <termio.h>
  26. #  endif
  27. #  ifdef S5WINSIZE
  28. #   include    <sys/stream.h>    /* winsize struct defined in one of these? */
  29. #   include    <sys/ptem.h>
  30. #  else
  31. #   undef    TIOCGWINSZ    /* we can't handle it correctly yet */
  32. #  endif
  33. # else
  34. #  include    <sgtty.h>
  35. # endif
  36. #endif
  37.  
  38. #if TOS
  39. # include    <osbind.h>
  40. #endif
  41.  
  42. #if OSK
  43. # include    <sgstat.h>
  44. #endif
  45.  
  46. #if VMS
  47. extern int VMS_read_raw;  /* Set in initscr() */
  48. #endif
  49.  
  50.  
  51. extern char    *getenv();
  52. static void     starttcap();
  53.  
  54. /* variables, publicly available & used in the macros */
  55. char    *termtype;    /* name of terminal entry */
  56. short    ospeed;        /* speed of the tty, eg B2400 */
  57. #if OSK
  58. char    PC_;    /* Pad char */
  59. char    *BC;    /* backspace character string */
  60. #else
  61. char    PC;        /* Pad char */
  62. #endif
  63. WINDOW    *stdscr;    /* pointer into kbuf[] */
  64. WINDOW    kbuf[KBSIZ];    /* a very large output buffer */
  65. int    LINES;        /* :li#: number of rows */
  66. int    COLS;        /* :co#: number of columns */
  67. int    AM;        /* :am:  boolean: auto margins? */
  68. int    PT;        /* :pt:  boolean: physical tabs? */
  69. char    *VB;        /* :vb=: visible bell */
  70. char    *UP;        /* :up=: move cursor up */
  71. char    *SO = "";    /* :so=: standout start */
  72. char    *SE = "";    /* :se=: standout end */
  73. char    *US = "";    /* :us=: underline start */
  74. char    *UE = "";    /* :ue=: underline end */
  75. char    *MD = "";    /* :md=: bold start */
  76. char    *ME = "";    /* :me=: bold end */
  77. char    *AS = "";    /* :as=: alternate (italic) start */
  78. char    *AE = "";    /* :ae=: alternate (italic) end */
  79. #ifndef NO_VISIBLE
  80. char    *MV;        /* :mv=: "visible" selection start */
  81. #endif
  82. char    *CM;        /* :cm=: cursor movement */
  83. char    *CE;        /* :ce=: clear to end of line */
  84. char    *CD;        /* :cd=: clear to end of screen */
  85. char    *AL;        /* :al=: add a line */
  86. char    *DL;        /* :dl=: delete a line */
  87. #if OSK
  88. char    *SR_;        /* :sr=: scroll reverse */
  89. #else
  90. char    *SR;        /* :sr=: scroll reverse */
  91. #endif
  92. char    *KS = "";    /* :ks=: init string for cursor */
  93. char    *KE = "";    /* :ke=: restore string for cursor */
  94. char    *KU;        /* :ku=: key sequence sent by up arrow */
  95. char    *KD;        /* :kd=: key sequence sent by down arrow */
  96. char    *KL;        /* :kl=: key sequence sent by left arrow */
  97. char    *KR;        /* :kr=: key sequence sent by right arrow */
  98. char    *HM;        /* :HM=: key sequence sent by the <Home> key */
  99. char    *EN;        /* :EN=: key sequence sent by the <End> key */
  100. char    *PU;        /* :PU=: key sequence sent by the <PgUp> key */
  101. char    *PD;        /* :PD=: key sequence sent by the <PgDn> key */
  102. char    *KI;        /* :kI=: key sequence sent by the <Insert> key */
  103. #ifndef NO_FKEY
  104. char    *FKEY[NFKEYS];    /* :k0=: ... :k9=: sequences sent by function keys */
  105. #endif
  106. char    *IM = "";    /* :im=: insert mode start */
  107. char    *IC = "";    /* :ic=: insert the following character */
  108. char    *EI = "";    /* :ei=: insert mode end */
  109. char    *DC;        /* :dc=: delete a character */
  110. char    *TI = "";    /* :ti=: terminal init */    /* GB */
  111. char    *TE = "";    /* :te=: terminal exit */    /* GB */
  112. #ifndef NO_CURSORSHAPE
  113. #if 1
  114. char    *CQ = (char *)0;/* :cQ=: normal cursor */
  115. char    *CX = (char *)1;/* :cX=: cursor used for EX command/entry */
  116. char    *CV = (char *)2;/* :cV=: cursor used for VI command mode */
  117. char    *CI = (char *)3;/* :cI=: cursor used for VI input mode */
  118. char    *CR = (char *)4;/* :cR=: cursor used for VI replace mode */
  119. #else
  120. char    *CQ = "";    /* :cQ=: normal cursor */
  121. char    *CX = "";    /* :cX=: cursor used for EX command/entry */
  122. char    *CV = "";    /* :cV=: cursor used for VI command mode */
  123. char    *CI = "";    /* :cI=: cursor used for VI input mode */
  124. char    *CR = "";    /* :cR=: cursor used for VI replace mode */
  125. #endif
  126. #endif
  127. char    *aend = "";    /* end an attribute -- either UE or ME */
  128. char    ERASEKEY;    /* backspace key taken from ioctl structure */
  129. #ifndef NO_COLOR
  130. char    normalcolor[16];
  131. char    SOcolor[16];
  132. char    SEcolor[16];
  133. char    UScolor[16];
  134. char    UEcolor[16];
  135. char    MDcolor[16];
  136. char    MEcolor[16];
  137. char    AScolor[16];
  138. char    AEcolor[16];
  139. # ifndef NO_POPUP
  140. char    POPUPcolor[16];
  141. # endif
  142. # ifndef NO_VISIBLE
  143. char    VISIBLEcolor[16];
  144. # endif
  145. #endif
  146.  
  147. #if ANY_UNIX
  148. # if UNIXV
  149. #  ifdef TERMIOS
  150. static struct termios    oldtermio;    /* original tty mode */
  151. static struct termios    newtermio;    /* cbreak/noecho tty mode */
  152. #  else
  153. static struct termio    oldtermio;    /* original tty mode */
  154. static struct termio    newtermio;    /* cbreak/noecho tty mode */
  155. #  endif
  156. # else
  157. static struct sgttyb    oldsgttyb;    /* original tty mode */
  158. static struct sgttyb    newsgttyb;    /* cbreak/nl/noecho tty mode */
  159. static int        oldint;        /* ^C or DEL, the "intr" character */
  160. #  ifdef TIOCSLTC
  161. static int        oldswitch;    /* ^Z, the "suspend" character */
  162. static int        olddswitch;    /* ^Y, the "delayed suspend" char */
  163. static int        oldquote;    /* ^V, the "quote next char" char */
  164. #  endif
  165. # endif
  166. #endif
  167.  
  168. #if OSK
  169. static struct sgbuf    oldsgttyb;    /* orginal tty mode */
  170. static struct sgbuf    newsgttyb;    /* noecho tty mode */
  171. #endif
  172.  
  173. static char    *capbuf;    /* capability string buffer */
  174.  
  175.  
  176. /* Initialize the Curses package. */
  177. void initscr()
  178. {
  179.     /* make sure TERM variable is set */
  180.     termtype = getenv("TERM");
  181.  
  182. #if VMS
  183.     /* VMS getenv() handles TERM as a environment setting.  Foreign 
  184.      * terminal support can be implemented by setting the ELVIS_TERM
  185.      * logical or symbol to match a tinytcap entry.
  186.      */
  187.     if (!strcmp(termtype,"unknown"))
  188.         termtype = getenv("ELVIS_TERM");
  189. #endif
  190. #if MSDOS
  191.     /* For MS-DOS, if TERM is unset we can default to "pcbios", or
  192.      * maybe "rainbow".
  193.      */
  194.     if (!termtype)
  195.     {
  196. #ifdef RAINBOW
  197.         if (*(unsigned char far*)(0xffff000eL) == 6   /* Rainbow 100a */
  198.          || *(unsigned char far*)(0xffff000eL) == 148)/* Rainbow 100b */
  199.         {
  200.             termtype = "rainbow";
  201.         }
  202.         else
  203. #endif
  204.             termtype = "pcbios";
  205.     }
  206.     if (!strcmp(termtype, "pcbios"))
  207. #else
  208.     if (!termtype)
  209. #endif
  210.     {
  211. #if ANY_UNIX
  212.         write(2, "Environment variable TERM must be set\n", (unsigned)38);
  213.         exit(1);
  214. #endif
  215. #if OSK
  216.         writeln(2, "Environment variable TERM must be set\n", (unsigned)38);
  217.         exit(1);
  218. #endif
  219. #if AMIGA
  220.         termtype = TERMTYPE;
  221.         starttcap(termtype);
  222. #endif
  223. #if MSDOS
  224.         starttcap("pcbios");
  225. #endif
  226. #if TOS
  227.         termtype = "vt52";
  228.         starttcap(termtype);
  229. #endif
  230. #if VMS
  231.         write(2, "UNKNOWN terminal: define ELVIS_TERM\n", (unsigned)36);
  232.         exit(1);
  233. #endif
  234.     }
  235.     else
  236.     {
  237. #if MSDOS
  238.         *o_pcbios = 0;
  239. #endif
  240.         /* start termcap stuff */
  241.         starttcap(termtype);
  242.     }
  243.  
  244.     /* create stdscr and curscr */
  245.     stdscr = kbuf;
  246.  
  247.     /* change the terminal mode to cbreak/noecho */
  248. #if ANY_UNIX
  249. # if UNIXV
  250. #  ifdef TERMIOS
  251.     tcgetattr(2, &oldtermio);
  252. #  else
  253.     ioctl(2, TCGETA, &oldtermio);
  254. #  endif
  255. # else
  256.     ioctl(2, TIOCGETP, &oldsgttyb);
  257. # endif
  258. #endif
  259.  
  260. #if OSK
  261.     _gs_opt(0, &oldsgttyb);
  262. #endif
  263.  
  264. #if VMS
  265.     VMS_read_raw = 1;   /* cbreak/noecho */
  266.     vms_open_tty();
  267. #endif
  268.     resume_curses(TRUE);
  269. }
  270.  
  271. /* Shut down the Curses package. */
  272. void endwin()
  273. {
  274.     /* change the terminal mode back the way it was */
  275.     suspend_curses();
  276. #if AMIGA
  277.     amiclosewin();
  278. #endif
  279. }
  280.  
  281.  
  282. static int curses_active = FALSE;
  283.  
  284. /* Send any required termination strings.  Turn off "raw" mode. */
  285. void suspend_curses()
  286. {
  287. #if ANY_UNIX && !UNIXV
  288.     struct tchars    tbuf;
  289. # ifdef TIOCSLTC
  290.     struct ltchars    ltbuf;
  291. # endif
  292. #endif
  293. #ifndef NO_CURSORSHAPE
  294.     if (has_CQ)
  295.     {
  296.         do_CQ();
  297.     }
  298. #endif
  299.     if (has_TE)                    /* GB */
  300.     {
  301.         do_TE();
  302.     }
  303.     if (has_KE)
  304.     {
  305.         do_KE();
  306.     }
  307. #ifndef NO_COLOR
  308.     quitcolor();
  309. #endif
  310.     refresh();
  311.  
  312.     /* change the terminal mode back the way it was */
  313. #if ANY_UNIX
  314. # if UNIXV
  315. #  if TERMIOS
  316.     tcsetattr(2, TCSADRAIN, &oldtermio);
  317. #  else
  318.     ioctl(2, TCSETAW, &oldtermio);
  319. #  endif
  320. # else
  321.     ioctl(2, TIOCSETP, &oldsgttyb);
  322.  
  323.     ioctl(2, TIOCGETC, (struct sgttyb *) &tbuf);
  324.     tbuf.t_intrc = oldint;
  325.     ioctl(2, TIOCSETC, (struct sgttyb *) &tbuf);
  326.  
  327. #  ifdef TIOCSLTC
  328.     ioctl(2, TIOCGLTC, <buf);
  329.     ltbuf.t_suspc = oldswitch;
  330.     ltbuf.t_dsuspc = olddswitch;
  331.     ltbuf.t_lnextc = oldquote;
  332.     ioctl(2, TIOCSLTC, <buf);
  333. #  endif
  334. # endif
  335. #endif
  336. #if OSK
  337.     _ss_opt(0, &oldsgttyb);
  338. #endif
  339. #if AMIGA
  340.     ttyshutdown();
  341. #endif
  342. #if MSDOS
  343.     raw_set_stdio(FALSE);
  344. #endif
  345.  
  346. #if VMS
  347.     VMS_read_raw = 0;
  348. #endif
  349.     curses_active = FALSE;
  350. }
  351.  
  352.  
  353. /* put the terminal in RAW mode.  If "quietly" is FALSE, then ask the user
  354.  * to hit a key, and wait for keystroke before returning.
  355.  */
  356. void resume_curses(quietly)
  357.     int    quietly;
  358. {
  359.     if (!curses_active)
  360.     {
  361.         /* change the terminal mode to cbreak/noecho */
  362. #if ANY_UNIX
  363. # if UNIXV
  364.         ospeed = (oldtermio.c_cflag & CBAUD);
  365.         ERASEKEY = oldtermio.c_cc[VERASE];
  366.         newtermio = oldtermio;
  367.         newtermio.c_iflag &= (IXON|IXOFF|IXANY|ISTRIP|IGNBRK);
  368.         newtermio.c_oflag &= ~OPOST;
  369.         newtermio.c_lflag &= ISIG;
  370.         newtermio.c_cc[VINTR] = ctrl('C'); /* always use ^C for interrupts */
  371.         newtermio.c_cc[VMIN] = 1;
  372.         newtermio.c_cc[VTIME] = 0;
  373. #  ifdef VSWTCH
  374.         newtermio.c_cc[VSWTCH] = 0;
  375. #  endif
  376. #  ifdef VSUSP
  377.         newtermio.c_cc[VSUSP] = 0;
  378. #  endif
  379. #  ifdef TERMIOS
  380.         tcsetattr(2, TCSADRAIN, &newtermio);
  381. #  else
  382.         ioctl(2, TCSETAW, &newtermio);
  383. #  endif
  384. # else /* BSD or V7 or Coherent or Minix */
  385.         struct tchars    tbuf;
  386. #  ifdef TIOCSLTC
  387.         struct ltchars    ltbuf;
  388. #  endif
  389.  
  390.         ospeed = oldsgttyb.sg_ospeed;
  391.         ERASEKEY = oldsgttyb.sg_erase;
  392.         newsgttyb = oldsgttyb;
  393.         newsgttyb.sg_flags |= CBREAK;
  394.         newsgttyb.sg_flags &= ~(CRMOD|ECHO|XTABS);
  395.         ioctl(2, TIOCSETP, &newsgttyb);
  396.  
  397.         ioctl(2, TIOCGETC, (struct sgttyb *) &tbuf);
  398.         oldint = tbuf.t_intrc;
  399.         tbuf.t_intrc = ctrl('C');    /* always use ^C for interrupts */
  400.         ioctl(2, TIOCSETC, (struct sgttyb *) &tbuf);
  401.  
  402. #  ifdef TIOCSLTC
  403.         ioctl(2, TIOCGLTC, <buf);
  404.         oldswitch = ltbuf.t_suspc;
  405.         ltbuf.t_suspc = 0;        /* disable ^Z for elvis */
  406.         olddswitch = ltbuf.t_dsuspc;
  407.         ltbuf.t_dsuspc = 0;        /* disable ^Y for elvis */
  408.         oldquote = ltbuf.t_lnextc;
  409.         ltbuf.t_lnextc = 0;        /* disable ^V for elvis */
  410.         ioctl(2, TIOCSLTC, <buf);
  411. #  endif
  412.  
  413. # endif
  414. #endif
  415. #if OSK
  416.         newsgttyb = oldsgttyb;
  417.         newsgttyb.sg_echo = 0;
  418.         newsgttyb.sg_eofch = 0;
  419.         newsgttyb.sg_kbach = 0;
  420.         newsgttyb.sg_kbich = ctrl('C');
  421.         _ss_opt(0, &newsgttyb);
  422.         ospeed = oldsgttyb.sg_baud;
  423.         ERASEKEY = oldsgttyb.sg_bspch;
  424. #endif
  425. #if AMIGA
  426.         /* turn on window resize and RAW */
  427.         ttysetup();
  428. #endif
  429. #if MSDOS
  430.         raw_set_stdio(TRUE);
  431. #endif
  432.  
  433. #if VMS
  434.         VMS_read_raw = 1;
  435.         { int c;
  436.             read(0,&c,0);   /* Flush the tty buffer. */
  437.         }
  438.         ERASEKEY = '\177';  /* Accept <DEL> as <^H> for VMS */
  439. #endif
  440.  
  441.         if (has_TI)                    /* GB */
  442.         {
  443.             do_TI();
  444.         }
  445.         if (has_KS)
  446.         {
  447.             do_KS();
  448.         }
  449.  
  450.         curses_active = TRUE;
  451.     }
  452.  
  453.     /* If we're supposed to quit quietly, then we're done */
  454.     if (quietly)
  455.     {
  456.         return;
  457.     }
  458.  
  459.     signal(SIGINT, SIG_IGN);
  460.  
  461.     move(LINES - 1, 0);
  462.     do_SO();
  463. #if VMS
  464.     qaddstr("\n[Press <RETURN> to continue]");
  465. #else
  466.     qaddstr("[Press <RETURN> to continue]");
  467. #endif
  468.     do_SE();
  469.     refresh();
  470.     ttyread(kbuf, 20, 0); /* in RAW mode, so <20 is very likely */
  471.     if (kbuf[0] == ':')
  472.     {
  473.         mode = MODE_COLON;
  474.         addch('\n');
  475.         refresh();
  476.     }
  477.     else
  478.     {
  479.         mode = MODE_VI;
  480.         redraw(MARK_UNSET, FALSE);
  481.     }    
  482.     exwrote = FALSE;
  483.  
  484. #if TURBOC || __GNUC__
  485.     signal(SIGINT, (void(*)()) trapint);
  486. #else
  487.     signal(SIGINT, trapint);
  488. #endif
  489. }
  490.  
  491. /* This function fetches an optional string from termcap */
  492. static void mayhave(T, s)
  493.     char    **T;    /* where to store the returned pointer */
  494.     char    *s;    /* name of the capability */
  495. {
  496.     char    *val;
  497.  
  498.     val = tgetstr(s, &capbuf);
  499.     if (val)
  500.     {
  501.         *T = val;
  502.     }
  503. }
  504.  
  505.  
  506. /* This function fetches a required string from termcap */
  507. static void musthave(T, s)
  508.     char    **T;    /* where to store the returned pointer */
  509.     char    *s;    /* name of the capability */
  510. {
  511.     mayhave(T, s);
  512.     if (!*T)
  513.     {
  514.         write(2, "This termcap entry lacks the :", (unsigned)30);
  515.         write(2, s, (unsigned)2);
  516.         write(2, "=: capability\n", (unsigned)14);
  517. #if OSK
  518.         write(2, "\l", 1);
  519. #endif
  520.         exit(1);
  521.     }
  522. }
  523.  
  524.  
  525. /* This function fetches a pair of strings from termcap.  If one of them is
  526.  * missing, then the other one is ignored.
  527.  */
  528. static void pair(T, U, sT, sU)
  529.     char    **T;    /* where to store the first pointer */
  530.     char    **U;    /* where to store the second pointer */
  531.     char    *sT;    /* name of the first capability */
  532.     char    *sU;    /* name of the second capability */
  533. {
  534.     mayhave(T, sT);
  535.     mayhave(U, sU);
  536.     if (!**T || !**U)
  537.     {
  538.         *T = *U = "";
  539.     }
  540. }
  541.  
  542.  
  543.  
  544. /* Read everything from termcap */
  545. static void starttcap(term)
  546.     char    *term;
  547. {
  548.     static char    cbmem[800];
  549.  
  550.     /* allocate memory for capbuf */
  551.     capbuf = cbmem;
  552.  
  553.     /* get the termcap entry */
  554.     switch (tgetent(kbuf, term))
  555.     {
  556.       case -1:
  557.         write(2, "Can't read /etc/termcap\n", (unsigned)24);
  558. #if OSK
  559.         write(2, "\l", 1);
  560. #endif
  561.         exit(2);
  562.  
  563.       case 0:
  564.         write(2, "Unrecognized TERM type\n", (unsigned)23);
  565. #if OSK
  566.         write(2, "\l", 1);
  567. #endif
  568.         exit(3);
  569.     }
  570.  
  571.     /* get strings */
  572.     musthave(&UP, "up");
  573.     mayhave(&VB, "vb");
  574.     musthave(&CM, "cm");
  575.     pair(&SO, &SE, "so", "se");
  576.     mayhave(&TI, "ti");
  577.     mayhave(&TE, "te");
  578.     if (tgetnum("ug") <= 0)
  579.     {
  580.         pair(&US, &UE, "us", "ue");
  581.         pair(&MD, &ME, "md", "me");
  582.  
  583.         /* get italics, or have it default to underline */
  584.         pair(&AS, &AE, "as", "ae");
  585.         if (!*AS)
  586.         {
  587.             AS = US;
  588.             AE = UE;
  589.         }
  590.     }
  591. #ifndef NO_VISIBLE
  592.     MV = SO; /* by default */
  593.     mayhave(&MV, "mv");
  594. #endif
  595.     mayhave(&AL, "al");
  596.     mayhave(&DL, "dl");
  597.     musthave(&CE, "ce");
  598.     mayhave(&CD, "cd");
  599. #if OSK
  600.     mayhave(&SR_, "sr");
  601. #else    
  602.     mayhave(&SR, "sr");
  603. #endif
  604.     pair(&IM, &EI, "im", "ei");
  605.     mayhave(&IC, "ic");
  606.     mayhave(&DC, "dc");
  607.  
  608.     /* other termcap stuff */
  609.     AM = (tgetflag("am") && !tgetflag("xn"));
  610.     PT = tgetflag("pt");
  611. #if AMIGA
  612.     amiopenwin(termtype);    /* Must run this before ttysetup(); */
  613.     ttysetup();    /* Must run this before getsize(0); */
  614. #endif
  615.     getsize(0);
  616.  
  617.     /* Key sequences */
  618.     pair(&KS, &KE, "ks", "ke");
  619.     mayhave(&KU, "ku");        /* up */
  620.     mayhave(&KD, "kd");        /* down */
  621.     mayhave(&KL, "kl");        /* left */
  622.     mayhave(&KR, "kr");        /* right */
  623.     mayhave(&PU, "kP");        /* PgUp */
  624.     mayhave(&PD, "kN");        /* PgDn */
  625.     mayhave(&HM, "kh");        /* Home */
  626.     mayhave(&EN, "kH");        /* End */
  627.     mayhave(&KI, "kI");        /* Insert */
  628. #ifndef CRUNCH
  629.     if (!PU) mayhave(&PU, "K2");    /* "3x3 pad" names for PgUp, etc. */
  630.     if (!PD) mayhave(&PD, "K5");
  631.     if (!HM) mayhave(&HM, "K1");
  632.     if (!EN) mayhave(&EN, "K4");
  633.  
  634.     mayhave(&PU, "PU");        /* old XENIX names for PgUp, etc. */
  635.     mayhave(&PD, "PD");        /* (overrides others, if used.) */
  636.     mayhave(&HM, "HM");
  637.     mayhave(&EN, "EN");
  638. #endif
  639. #ifndef NO_FKEY
  640.     mayhave(&FKEY[0], "k0");        /* function key codes */
  641.     mayhave(&FKEY[1], "k1");
  642.     mayhave(&FKEY[2], "k2");
  643.     mayhave(&FKEY[3], "k3");
  644.     mayhave(&FKEY[4], "k4");
  645.     mayhave(&FKEY[5], "k5");
  646.     mayhave(&FKEY[6], "k6");
  647.     mayhave(&FKEY[7], "k7");
  648.     mayhave(&FKEY[8], "k8");
  649.     mayhave(&FKEY[9], "k9");
  650. # ifndef NO_SHIFT_FKEY
  651.     mayhave(&FKEY[10], "s0");        /* shift function key codes */
  652.     mayhave(&FKEY[11], "s1");
  653.     mayhave(&FKEY[12], "s2");
  654.     mayhave(&FKEY[13], "s3");
  655.     mayhave(&FKEY[14], "s4");
  656.     mayhave(&FKEY[15], "s5");
  657.     mayhave(&FKEY[16], "s6");
  658.     mayhave(&FKEY[17], "s7");
  659.     mayhave(&FKEY[18], "s8");
  660.     mayhave(&FKEY[19], "s9");
  661. #  ifndef NO_CTRL_FKEY
  662.     mayhave(&FKEY[20], "c0");        /* control function key codes */
  663.     mayhave(&FKEY[21], "c1");
  664.     mayhave(&FKEY[22], "c2");
  665.     mayhave(&FKEY[23], "c3");
  666.     mayhave(&FKEY[24], "c4");
  667.     mayhave(&FKEY[25], "c5");
  668.     mayhave(&FKEY[26], "c6");
  669.     mayhave(&FKEY[27], "c7");
  670.     mayhave(&FKEY[28], "c8");
  671.     mayhave(&FKEY[29], "c9");
  672. #   ifndef NO_ALT_FKEY
  673.     mayhave(&FKEY[30], "a0");        /* alt function key codes */
  674.     mayhave(&FKEY[31], "a1");
  675.     mayhave(&FKEY[32], "a2");
  676.     mayhave(&FKEY[33], "a3");
  677.     mayhave(&FKEY[34], "a4");
  678.     mayhave(&FKEY[35], "a5");
  679.     mayhave(&FKEY[36], "a6");
  680.     mayhave(&FKEY[37], "a7");
  681.     mayhave(&FKEY[38], "a8");
  682.     mayhave(&FKEY[39], "a9");
  683. #   endif
  684. #  endif
  685. # endif
  686. #endif
  687.  
  688. #ifndef NO_CURSORSHAPE
  689.     /* cursor shapes */
  690.     CQ = tgetstr("cQ", &capbuf);
  691.     if (has_CQ)
  692.     {
  693.         CX = tgetstr("cX", &capbuf);
  694.         if (!CX) CX = CQ;
  695.         CV = tgetstr("cV", &capbuf);
  696.         if (!CV) CV = CQ;
  697.         CI = tgetstr("cI", &capbuf);
  698.         if (!CI) CI = CQ;
  699.         CR = tgetstr("cR", &capbuf);
  700.         if (!CR) CR = CQ;
  701.     }
  702. # ifndef CRUNCH
  703.     else
  704.     {
  705.         CQ = CV = "";
  706.         pair(&CQ, &CV, "ve", "vs");
  707.         CX = CI = CR = CQ;
  708.     }
  709. # endif /* !CRUNCH */
  710. #endif /* !NO_CURSORSHAPE */
  711.  
  712. #ifndef NO_COLOR
  713.     strcpy(SOcolor, SO);
  714.     strcpy(SEcolor, SE);
  715.     strcpy(AScolor, AS);
  716.     strcpy(AEcolor, AE);
  717.     strcpy(MDcolor, MD);
  718.     strcpy(MEcolor, ME);
  719.     strcpy(UScolor, US);
  720.     strcpy(UEcolor, UE);
  721. # ifndef NO_POPUP
  722.     strcpy(POPUPcolor, SO);
  723. # endif
  724. # ifndef NO_VISIBLE
  725.     strcpy(VISIBLEcolor, MV);
  726. # endif
  727. #endif
  728.  
  729. }
  730.  
  731.  
  732. /* This function gets the window size.  It uses the TIOCGWINSZ ioctl call if
  733.  * your system has it, or tgetnum("li") and tgetnum("co") if it doesn't.
  734.  * This function is called once during initialization, and thereafter it is
  735.  * called whenever the SIGWINCH signal is sent to this process.
  736.  */
  737. int getsize(signo)
  738.     int    signo;
  739. {
  740.     int    lines;
  741.     int    cols;
  742. #ifdef TIOCGWINSZ
  743.     struct winsize size;
  744. #endif
  745.  
  746. #ifdef SIGWINCH
  747.     /* reset the signal vector */
  748.     signal(SIGWINCH, getsize);
  749. #endif
  750.  
  751.     /* get the window size, one way or another. */
  752.     lines = cols = 0;
  753. #ifdef TIOCGWINSZ
  754.     if (ioctl(2, TIOCGWINSZ, &size) >= 0)
  755.     {
  756.         lines = size.ws_row;
  757.         cols = size.ws_col;
  758.     }
  759. #endif
  760. #if AMIGA
  761.     /* Amiga gets window size by asking the console.device */
  762.     if (!strcmp(TERMTYPE, termtype))
  763.     {
  764.         auto long len;
  765.         auto char buf[30];
  766.         
  767.         Write(Output(), "\2330 q", 4); /* Ask the console.device */
  768.         len = Read(Input(), buf, 29);
  769.         buf[len] = '\000';
  770.         sscanf(&buf[5], "%d;%d", &lines, &cols);
  771.     }
  772. #endif
  773.     if ((lines == 0 || cols == 0) && signo == 0)
  774.     {
  775.         LINES = tgetnum("li");
  776.         COLS = tgetnum("co");
  777.     }
  778. #if MSDOS
  779. # ifdef RAINBOW
  780.     if (!strcmp(termtype, "rainbow"))
  781.     {
  782.         /* Determine whether Rainbow is in 80-column or 132-column mode */
  783.         cols = *(unsigned char far *)0xee000f57L;
  784.     }
  785.     else
  786. # endif
  787.     {
  788.         lines = v_rows();
  789.         cols = v_cols();
  790.     }
  791. #endif
  792.     if (lines >= 2 && cols >= 30)
  793.     {
  794.         LINES = lines;
  795.         COLS = cols;
  796.     }
  797.  
  798.     /* Make sure we got values that we can live with */
  799.     if (LINES < 2 || COLS < 30)
  800.     {
  801.         write(2, "Screen too small\n", (unsigned)17);
  802. #if OSK
  803.         write(2, "\l", 1);
  804. #endif
  805.         endwin();
  806.         exit(2);
  807.     }
  808.  
  809. #if AMIGA
  810.     if (*o_lines != LINES || *o_columns != COLS)
  811.     {
  812.         *o_lines = LINES;
  813.         *o_columns = COLS;
  814.     }
  815. #endif
  816.  
  817.     return 0;
  818. }
  819.  
  820.  
  821. /* This is a function version of addch() -- it is used by tputs() */
  822. int faddch(ch)
  823.     int    ch;
  824. {
  825.     addch(ch);
  826.  
  827.     return 0;
  828. }
  829.  
  830. /* This function quickly adds a string to the output queue.  It does *NOT*
  831.  * convert \n into <CR><LF>.
  832.  */
  833. void qaddstr(str)
  834.     char    *str;
  835. {
  836.     REG char *s_, *d_;
  837.  
  838. #if MSDOS
  839.     if (o_pcbios[0])
  840.     {
  841.         while (*str)
  842.             qaddch(*str++);
  843.         return;
  844.     }
  845. #endif
  846.     for (s_=(str), d_=stdscr; *d_++ = *s_++; )
  847.     {
  848.     }
  849.     stdscr = d_ - 1;
  850. }
  851.  
  852. /* Output the ESC sequence needed to go into any video mode, if supported */
  853. void attrset(a)
  854.     int    a;
  855. {
  856.     do_aend();
  857.     if (a == A_BOLD)
  858.     {
  859.         do_MD();
  860.         aend = ME;
  861.     }
  862.     else if (a == A_UNDERLINE)
  863.     {
  864.         do_US();
  865.         aend = UE;
  866.     }
  867.     else if (a == A_ALTCHARSET)
  868.     {
  869.         do_AS();
  870.         aend = AE;
  871.     }
  872.     else
  873.     {
  874.         aend = "";
  875.     }
  876. }
  877.  
  878.  
  879. /* Insert a single character into the display */
  880. void insch(ch)
  881.     int    ch;
  882. {
  883.     if (has_IM)
  884.         do_IM();
  885.     do_IC();
  886.     qaddch(ch);
  887.     if (has_EI)
  888.         do_EI();
  889. }
  890.  
  891. void wrefresh()
  892. {
  893.     if (stdscr != kbuf)
  894.     {
  895.         VOIDBIOS(;,ttywrite(kbuf, (unsigned)(stdscr - kbuf)));
  896.         stdscr = kbuf;
  897.     }
  898. }
  899.  
  900. void wqrefresh()
  901. {
  902.     if (stdscr - kbuf > 2000)
  903.     {
  904.         VOIDBIOS(stdscr = kbuf,
  905.         {
  906.             ttywrite(kbuf, (unsigned)(stdscr - kbuf)); 
  907.             stdscr = kbuf;
  908.         });
  909.     }
  910. }
  911.  
  912. #ifndef NO_COLOR
  913. /* This function is called during termination.  It resets color modes */
  914. int ansiquit()
  915. {
  916.     /* if ANSI color terminal, then reset the colors */
  917.     if (!strcmp(UP, "\033[A"))
  918.     {
  919.         tputs("\033[37;40m\033[m", 1, faddch);
  920.         clrtoeol();
  921.         return 1;
  922.     }
  923.     return 0;
  924. }
  925.  
  926. /* This sets the color strings that work for ANSI terminals.  If the TERMCAP
  927.  * doesn't look like an ANSI terminal, then it returns FALSE.  If the colors
  928.  * aren't understood, it also returns FALSE.  If all goes well, it returns TRUE
  929.  */
  930. int ansicolor(cmode, attrbyte)
  931.     int    cmode;        /* mode to set, e.g. A_NORMAL */
  932.     int    attrbyte;    /* IBM PC attribute byte */
  933. {
  934.     char    temp[16];    /* hold the new mode string */
  935.  
  936.     /* if not ANSI-ish, then fail */
  937.     if (strcmp(UP, "\033[A") && strcmp(UP, "\033OA"))
  938.     {
  939.         msg("Don't know how to set colors for this terminal");
  940.         return 0;
  941.     }
  942.  
  943.     /* construct the color string */
  944.     sprintf(temp, "\033[m\033[3%c;4%c%s%sm",
  945.         "04261537"[attrbyte & 0x07],
  946.         "04261537"[(attrbyte >> 4) & 0x07],
  947.         (attrbyte & 0x08) ? ";1" : "",
  948.         (attrbyte & 0x80) ? ";5" : "");
  949.  
  950.     /* stick it in the right place */
  951.     switch (cmode)
  952.     {
  953.       case A_NORMAL:
  954.         if (!strcmp(MEcolor, normalcolor))
  955.             strcpy(MEcolor, temp);
  956.         if (!strcmp(UEcolor, normalcolor))
  957.             strcpy(UEcolor, temp);
  958.         if (!strcmp(AEcolor, normalcolor))
  959.             strcpy(AEcolor, temp);
  960.         if (!strcmp(SEcolor, normalcolor))
  961.             strcpy(SEcolor, temp);
  962.  
  963.         strcpy(normalcolor, temp);
  964.         tputs(normalcolor, 1, faddch);
  965.         break;
  966.  
  967.       case A_BOLD:
  968.         strcpy(MDcolor, temp);
  969.         strcpy(MEcolor, normalcolor);
  970.         break;
  971.  
  972.       case A_UNDERLINE:
  973.         strcpy(UScolor, temp);
  974.         strcpy(UEcolor, normalcolor);
  975.         break;
  976.  
  977.       case A_ALTCHARSET:
  978.         strcpy(AScolor, temp);
  979.         strcpy(AEcolor, normalcolor);
  980.         break;
  981.  
  982.       case A_STANDOUT:
  983.         strcpy(SOcolor, temp);
  984.         strcpy(SEcolor, normalcolor);
  985.         break;
  986.  
  987. #ifndef NO_POPUP
  988.       case A_POPUP:
  989.         strcpy(POPUPcolor, temp);
  990.         break;
  991. #endif
  992.  
  993. #ifndef NO_VISIBLE
  994.       case A_VISIBLE:
  995.         strcpy(VISIBLEcolor, temp);
  996.         break;
  997. #endif
  998.     }
  999.  
  1000.     return 1;
  1001. }
  1002.  
  1003.  
  1004. /* This function outputs the ESC sequence needed to switch the screen back
  1005.  * to "normal" mode.  On color terminals which haven't had their color set
  1006.  * yet, this is one of the termcap strings; for color terminals that really
  1007.  * have had colors defined, we just the "normal color" escape sequence.
  1008.  */
  1009. endcolor()
  1010. {
  1011.     if (aend == ME)
  1012.         tputs(MEcolor, 1, faddch);
  1013.     else if (aend == UE)
  1014.         tputs(UEcolor, 1, faddch);
  1015.     else if (aend == AE)
  1016.         tputs(AEcolor, 1, faddch);
  1017.     else if (aend == SE)
  1018.         tputs(SEcolor, 1, faddch);
  1019.     aend = "";
  1020.     return 0;
  1021. }
  1022.  
  1023.  
  1024. #endif /* !NO_COLOR */
  1025.