home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 1 / 1708 / curses.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-12-28  |  10.8 KB  |  561 lines

  1. /* curses.c */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    16820 SW Tallac Way
  6.  *    Beaverton, OR 97006
  7.  *    kirkenda@jove.cs.pdx.edu, or ...uunet!tektronix!psueea!jove!kirkenda
  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 UNIXV
  21. # include    <termio.h>
  22. #endif
  23.  
  24. #if BSD || UNIX7 || MINIX
  25. # include    <sgtty.h>
  26. #endif
  27.  
  28. #if TOS
  29. # include    <osbind.h>
  30. #endif
  31.  
  32. #include <signal.h>
  33.  
  34. extern char    *getenv();
  35.  
  36. /* variables, publicly available & used in the macros */
  37. short    ospeed;        /* speed of the tty, eg B2400 */
  38. char    PC;        /* Pad char */
  39. WINDOW    *stdscr;    /* pointer into kbuf[] */
  40. WINDOW    kbuf[KBSIZ];    /* a very large output buffer */
  41. int    LINES;        /* :li#: number of rows */
  42. int    COLS;        /* :co#: number of columns */
  43. int    AM;        /* :am:  boolean: auto margins? */
  44. int    PT;        /* :pt:  boolean: physical tabs? */
  45. char    *VB;        /* :vb=: visible bell */
  46. char    *UP;        /* :up=: move cursor up */
  47. char    *SO;        /* :so=: standout start */
  48. char    *SE;        /* :se=: standout end */
  49. char    *US = "";    /* :us=: underline start */
  50. char    *UE = "";    /* :ue=: underline end */
  51. char    *VB_s = "";    /* :VB=: bold start */
  52. char    *VB_e = "";    /* :Vb=: bold end */
  53. char    *AS;        /* :as=: alternate (italic) start */
  54. char    *AE;        /* :ae=: alternate (italic) end */
  55. char    *CM;        /* :cm=: cursor movement */
  56. char    *CE;        /* :ce=: clear to end of line */
  57. char    *CD;        /* :cd=: clear to end of screen */
  58. char    *AL;        /* :al=: add a line */
  59. char    *DL;        /* :dl=: delete a line */
  60. char    *SR;        /* :sr=: scroll reverse */
  61. char    *KU;        /* :ku=: key sequence sent by up arrow */
  62. char    *KD;        /* :kd=: key sequence sent by down arrow */
  63. char    *KL;        /* :kl=: key sequence sent by left arrow */
  64. char    *KR;        /* :kr=: key sequence sent by right arrow */
  65. char    *HM;        /* :HM=: key sequence sent by the <Home> key */
  66. char    *EN;        /* :EN=: key sequence sent by the <End> key */
  67. char    *PU;        /* :PU=: key sequence sent by the <PgUp> key */
  68. char    *PD;        /* :PD=: key sequence sent by the <PgDn> key */
  69. char    *IM;        /* :im=: insert mode start */
  70. char    *IC = "";    /* :ic=: insert the following character */
  71. char    *EI;        /* :ei=: insert mode end */
  72. char    *DC;        /* :dc=: delete a character */
  73. char    *TI;        /* :ti=: terminal init */    /* GB */
  74. char    *TE;        /* :te=: terminal exit */    /* GB */
  75. #ifndef NO_CURSORSHAPE
  76. char    *CQ = (char *)0;/* :cQ=: normal cursor */
  77. char    *CX = (char *)1;/* :cX=: cursor used for EX command/entry */
  78. char    *CV = (char *)2;/* :cV=: cursor used for VI command mode */
  79. char    *CI = (char *)3;/* :cI=: cursor used for VI input mode */
  80. char    *CR = (char *)4;/* :cR=: cursor used for VI replace mode */
  81. #endif
  82. char    *aend = "";    /* end an attribute -- either UE or VB_e */
  83. char    ERASEKEY;    /* backspace key taken from ioctl structure */
  84.  
  85. #if UNIXV
  86. static struct termio    oldtermio;    /* original tty mode */
  87. static struct termio    newtermio;    /* raw/noecho tty mode */
  88. #endif
  89.  
  90. #if BSD || UNIX7 || MINIX
  91. static struct sgttyb    oldsgttyb;    /* original tty mode */
  92. static struct sgttyb    newsgttyb;    /* raw/nl/noecho tty mode */
  93. static int        oldint;
  94. #endif
  95.  
  96. static char    *capbuf;    /* capability string buffer */
  97.  
  98.  
  99. initscr()
  100. {
  101.     /* make sure TERM variable is set */
  102. #if    MSDOS
  103.     char *val;
  104.     if (! (val = getenv("TERM"))
  105.     || !strcmp(val, "pcbios"))
  106. #else
  107.     if (!getenv("TERM"))
  108. #endif
  109.     {
  110. #if ANY_UNIX || TOS
  111.         write(2, "Environment variable TERM must be set\n", 38);
  112.         exit(1);
  113. #endif
  114. #if MSDOS
  115.         getsize(0);
  116. #endif
  117.     }
  118.     else
  119.     {
  120. #if MSDOS
  121.         *o_pcbios=0;
  122. #endif
  123.         /* start termcap stuff */
  124.         starttcap();
  125.     }
  126.  
  127.     /* create stdscr and curscr */
  128.     stdscr = kbuf;
  129.  
  130.     /* change the terminal mode to raw/noecho */
  131. #if UNIXV
  132.     ioctl(2, TCGETA, &oldtermio);
  133. #endif
  134.  
  135. #if BSD || UNIX7 || MINIX
  136.     ioctl(2, TIOCGETP, &oldsgttyb);
  137. #endif
  138.     resume_curses(TRUE);
  139. }
  140.  
  141.  
  142. endwin()
  143. {
  144.     /* change the terminal mode back the way it was */
  145.     suspend_curses();
  146. }
  147.  
  148. suspend_curses()
  149. {
  150. #if BSD || UNIX7 || MINIX
  151.     struct tchars    tbuf;
  152. #endif
  153. #ifndef NO_CURSORSHAPE
  154.     if (has_CQ)
  155.     {
  156.         do_CQ();
  157.     }
  158. #endif
  159.     if (has_TE)                    /* GB */
  160.     {
  161.         do_TE();
  162.     }
  163.  
  164.     /* change the terminal mode back the way it was */
  165. #if UNIXV
  166.     ioctl(2, TCSETAW, &oldtermio);
  167. #endif
  168. #if BSD || UNIX7 || MINIX
  169.     ioctl(2, TIOCSETP, &oldsgttyb);
  170.  
  171.     ioctl(2, TIOCGETC, &tbuf);
  172.     tbuf.t_intrc = oldint;
  173.     ioctl(2, TIOCSETC, &tbuf);
  174. #endif
  175. }
  176.  
  177. resume_curses(quietly)
  178.     int    quietly;
  179. {    
  180.     /* change the terminal mode to raw/noecho */
  181. #if UNIXV
  182.     ospeed = (oldtermio.c_cflag & CBAUD);
  183.     ERASEKEY = oldtermio.c_cc[VERASE];
  184.     newtermio = oldtermio;
  185.     newtermio.c_iflag &= (IXON|IXOFF|IXANY|ISTRIP|IGNBRK);
  186.     newtermio.c_oflag &= ~OPOST;
  187.     newtermio.c_lflag &= ISIG;
  188.     newtermio.c_cc[VINTR] = ctrl('C'); /* always use ^C for interrupts */
  189.     newtermio.c_cc[VEOF] = 1;    /* minimum # characters to read */
  190.     newtermio.c_cc[VEOL] = 2;    /* allow at least 0.2 seconds */
  191.     ioctl(2, TCSETAW, &newtermio);
  192. #endif
  193. #if BSD || UNIX7 || MINIX
  194.     struct tchars    tbuf;
  195.  
  196.     ospeed = oldsgttyb.sg_ospeed;
  197.     ERASEKEY = oldsgttyb.sg_erase;
  198.     newsgttyb = oldsgttyb;
  199.     newsgttyb.sg_flags |= CBREAK;
  200.     newsgttyb.sg_flags &= ~(CRMOD|ECHO|XTABS);
  201.     ioctl(2, TIOCSETP, &newsgttyb);
  202.  
  203.     ioctl(2, TIOCGETC, &tbuf);
  204.     oldint = tbuf.t_intrc;
  205.     tbuf.t_intrc = ctrl('C');    /* always use ^C for interrupts */
  206.     ioctl(2, TIOCSETC, &tbuf);
  207. #endif
  208.  
  209.     if (has_TI)                    /* GB */
  210.     {
  211.         do_TI();
  212.     }
  213.  
  214.     /* If we're supposed to quit quietly, then we're done */
  215.     if (quietly)
  216.     {
  217.         return;
  218.     }
  219.  
  220.     signal(SIGINT, SIG_IGN);
  221.  
  222.     move(LINES - 1, 0);
  223.     do_SO();
  224.     qaddstr("[Press <RETURN> to continue]");
  225.     do_SE();
  226.     refresh();
  227.     ttyread(kbuf, 20); /* in RAW mode, so <20 is very likely */
  228.     if (kbuf[0] == ':')
  229.     {
  230.         mode = MODE_COLON;
  231.         addch('\n');
  232.         refresh();
  233.     }
  234.     else
  235.     {
  236.         mode = MODE_VI;
  237.         redraw(MARK_UNSET, FALSE);
  238.     }    
  239.     exwrote = FALSE;
  240.  
  241. #if    TURBOC
  242.     signal(SIGINT, (void(*)()) trapint);
  243. #else
  244.     signal(SIGINT, trapint);
  245. #endif
  246. }
  247.  
  248. static lacking(s)
  249.     char    *s;
  250. {
  251.     write(2, "This termcap entry lacks the :", 30);
  252.     write(2, s, 2);
  253.     write(2, "=: capability\n", 14);
  254.     exit(1);
  255. }
  256.  
  257. starttcap()
  258. {
  259.     char    *str;
  260.     static char    cbmem[800];
  261. #define MUSTHAVE(T,s)    if (!(T = tgetstr(s, &capbuf))) lacking(s)
  262. #define MAYHAVE(T,s)    if (str = tgetstr(s, &capbuf)) T = str
  263. #define PAIR(T,U,sT,sU)    T=tgetstr(sT,&capbuf);U=tgetstr(sU,&capbuf);if (!T||!U)T=U=""
  264.  
  265.     /* allocate memory for capbuf */
  266.     capbuf = cbmem;
  267.  
  268.     /* get the termcap entry */
  269.     switch (tgetent(kbuf, getenv("TERM")))
  270.     {
  271.       case -1:
  272.         write(2, "Can't read /etc/termcap\n", 24);
  273.         exit(2);
  274.  
  275.       case 0:
  276.         write(2, "Unrecognized TERM type\n", 23);
  277.         exit(3);
  278.     }
  279.  
  280.     /* get strings */
  281.     MUSTHAVE(UP, "up");
  282.     MAYHAVE(VB, "vb");
  283.     MUSTHAVE(CM, "cm");
  284.     PAIR(SO, SE, "so", "se");
  285.     PAIR(TI, TE, "ti", "te");
  286.     if (tgetnum("ug") <= 0)
  287.     {
  288.         PAIR(US, UE, "us", "ue");
  289.         PAIR(VB_s, VB_e, "VB", "Vb");
  290.  
  291.         /* get italics, or have it default to underline */
  292.         PAIR(AS, AE, "as", "ae");
  293.         if (!*AS)
  294.         {
  295.             AS = US;
  296.             AE = UE;
  297.         }
  298.     }
  299.     MAYHAVE(AL, "al");
  300.     MAYHAVE(DL, "dl");
  301.     MUSTHAVE(CE, "ce");
  302.     MAYHAVE(CD, "cd");
  303.     MAYHAVE(SR, "sr");
  304.     PAIR(IM, EI, "im", "ei");
  305.     MAYHAVE(IC, "ic");
  306.     MAYHAVE(DC, "dc");
  307.  
  308.     /* other termcap stuff */
  309.     AM = tgetflag("am");
  310.     PT = tgetflag("pt");
  311.     getsize(0);
  312.  
  313.     /* Key sequences */
  314.     MAYHAVE(KU, "ku");
  315.     MAYHAVE(KD, "kd");
  316.     MAYHAVE(KL, "kl");
  317.     MAYHAVE(KR, "kr");
  318.     MAYHAVE(PU, "PU");
  319.     MAYHAVE(PD, "PD");
  320.     MAYHAVE(HM, "HM");
  321.     MAYHAVE(EN, "EN");
  322.  
  323. #ifndef NO_CURSORSHAPE
  324.     /* cursor shapes */
  325.     CQ = tgetstr("cQ", &capbuf);
  326.     if (has_CQ)
  327.     {
  328.         CX = tgetstr("cX", &capbuf);
  329.         if (!CX) CX = CQ;
  330.         CV = tgetstr("cV", &capbuf);
  331.         if (!CV) CV = CQ;
  332.         CI = tgetstr("cI", &capbuf);
  333.         if (!CI) CI = CQ;
  334.         CR = tgetstr("cR", &capbuf);
  335.         if (!CR) CR = CQ;
  336.     }
  337. #endif
  338.  
  339. #undef MUSTHAVE
  340. #undef MAYHAVE
  341. #undef PAIR
  342. }
  343.  
  344.  
  345. /* This function gets the window size.  It uses the TIOCGWINSZ ioctl call if
  346.  * your system has it, or tgetnum("li") and tgetnum("co") if it doesn't.
  347.  * This function is called once during initialization, and thereafter it is
  348.  * called whenever the SIGWINCH signal is sent to this process.
  349.  */
  350. getsize(signo)
  351.     int    signo;
  352. {
  353.     int    lines;
  354.     int    cols;
  355. #ifdef TIOCGWINSZ
  356.     struct winsize size;
  357. #endif
  358.  
  359. #ifdef SIGWINCH
  360.     /* reset the signal vector */
  361.     signal(SIGWINCH, getsize);
  362. #endif
  363.  
  364.     /* get the window size, one way or another. */
  365.     lines = cols = 0;
  366. #ifdef TIOCGWINSZ
  367.     if (ioctl(2, TIOCGWINSZ, &size) >= 0)
  368.     {
  369.         lines = size.ws_row;
  370.         cols = size.ws_col;
  371.     }
  372. #endif
  373.     if ((lines == 0 || cols == 0) && signo == 0)
  374.     {
  375.         LINES = CHECKBIOS(v_rows(), tgetnum("li"));
  376.         COLS = CHECKBIOS(v_cols(), tgetnum("co"));
  377.     }
  378.     if (lines >= 2 && cols >= 30)
  379.     {
  380.         LINES = lines;
  381.         COLS = cols;
  382.     }
  383.  
  384.     /* Make sure we got values that we can live with */
  385.     if (LINES < 2 || COLS < 30)
  386.     {
  387.         write(2, "Screen too small\n", 17);
  388.         endwin();
  389.         exit(2);
  390.     }
  391.  
  392.     /* !!! copy the new values into Elvis' options */
  393.     {
  394.         extern char    o_columns[], o_lines[];
  395.  
  396.         *o_columns = COLS;
  397.         *o_lines = LINES;
  398.     }
  399. }
  400.  
  401.  
  402. /* This is a function version of addch() -- it is used by tputs() */
  403. int faddch(ch)
  404.     int    ch;
  405. {
  406.     addch(ch);
  407. }
  408.  
  409. /* These functions are equivelent to the macros of the same names... */
  410.  
  411. void qaddstr(str)
  412.     char    *str;
  413. {
  414.     register char *s_, *d_;
  415.  
  416. #if MSDOS
  417.     if (o_pcbios[0])
  418.     {
  419.         while (*str)
  420.             qaddch(*str++);
  421.         return;
  422.     }
  423. #endif
  424.     for (s_=(str), d_=stdscr; *d_++ = *s_++; )
  425.     {
  426.     }
  427.     stdscr = d_ - 1;
  428. }
  429.  
  430. void attrset(a)
  431.     int    a;
  432. {
  433.     do_aend();
  434.     if (a == A_BOLD)
  435.     {
  436.         do_VB_s();
  437.         aend = VB_e;
  438.     }
  439.     else if (a == A_UNDERLINE)
  440.     {
  441.         do_US();
  442.         aend = UE;
  443.     }
  444.     else if (a == A_ALTCHARSET)
  445.     {
  446.         do_AS();
  447.         aend = AE;
  448.     }
  449.     else
  450.     {
  451.         aend = "";
  452.     }
  453. }
  454.  
  455.  
  456. void insch(ch)
  457.     int    ch;
  458. {
  459.     if (has_IM)
  460.         do_IM();
  461.     do_IC();
  462.     qaddch(ch);
  463.     if (has_EI)
  464.         do_EI();
  465. }
  466.  
  467. #if MSDOS
  468.  
  469. static int alarmtime;
  470.  
  471. /* raw read - #defined to read (0, ...) on non-MSDOS.
  472.  * With MSDOS, am maximum of 1 byte is read.
  473.  * If more bytes should be read, just change the loop.
  474.  * The following code uses the IBM-PC-System-Timer, so probably wont't work
  475.  * on non-compatibles.
  476.  */
  477. /*ARGSUSED*/
  478. ttyread(buf, len)
  479.     char *buf;
  480.     int len;
  481. {
  482.     volatile char far *biostimer;
  483.     char oldtime;
  484.     int nticks = 0;
  485.     int pos = 0;
  486.  
  487.     biostimer = (char far *)0x0040006cl;
  488.     oldtime = *biostimer;
  489.  
  490.     while (!pos && (!alarmtime || nticks<alarmtime))
  491.     {    if (kbhit())
  492.             if ((buf[pos++] = getch()) == 0) /* function key */
  493.                 buf[pos-1] = '#';
  494.         if (oldtime != *biostimer)
  495.         {    nticks++;
  496.             oldtime = *biostimer;
  497.         }
  498.     }
  499.     return pos;
  500. }
  501.  
  502. alarm(time)
  503.     int time;
  504. {
  505.     alarmtime = 2 * time;        /* ticks are 1/18 sec. */
  506. }
  507. #endif
  508.  
  509. #if TOS
  510.  
  511. static int alarmtime;
  512. static long timer;
  513.  
  514. static gettime()
  515. {
  516.     timer = *(long *)(0x4ba);
  517. }
  518.  
  519. /*ARGSUSED*/
  520. ttyread(buf, len)
  521.     char *buf;
  522.     int len;
  523. {
  524.     int    pos=0;
  525.     long    l;
  526.     long    endtime;
  527.  
  528.     Supexec(gettime);
  529.     endtime = timer+alarmtime;
  530.  
  531.     while (!pos && (!alarmtime || timer<endtime))
  532.     {
  533.         if (Bconstat(2))
  534.         {
  535.             l = Bconin(2);
  536.             if ((buf[pos++]=l) == '\0')
  537.             {
  538.                 buf[pos-1]='#';
  539.                 buf[pos++]=l>>16;
  540.             }
  541.         }
  542.         Supexec(gettime);
  543.     }
  544.     return pos;
  545. }
  546.  
  547. alarm(time)
  548.     int time;
  549. {
  550.     alarmtime = 50 * time;        /* ticks are 1/200 sec. */
  551. }
  552.  
  553. ttywrite(buf, len)
  554.     char *buf;
  555.     int len;
  556. {
  557.     while (len--)
  558.         Bconout(2, *buf++);
  559. }
  560. #endif
  561.