home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / elvis184.zip / src / curses.c < prev    next >
C/C++ Source or Header  |  1995-05-26  |  25KB  |  1,147 lines

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