home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / APPS / elvis_1.4.tar.Z / elvis_1.4.tar / curses.c < prev    next >
C/C++ Source or Header  |  1990-12-06  |  14KB  |  730 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. #  include    <termio.h>
  23. #  undef    TIOCWINSZ    /* we can't handle it correctly yet */
  24. # else
  25. #  include    <sgtty.h>
  26. # endif
  27. #endif
  28.  
  29. #if TOS
  30. # include    <osbind.h>
  31. #endif
  32.  
  33. #if OSK
  34. # include    <sgstat.h>
  35. #endif
  36.  
  37. #include <signal.h>
  38.  
  39. extern char    *getenv();
  40. static void     starttcap();
  41.  
  42. /* variables, publicly available & used in the macros */
  43. short    ospeed;        /* speed of the tty, eg B2400 */
  44. #if OSK
  45. char    PC_;    /* Pad char */
  46. char    *BC;    /* backspace character string */
  47. #else
  48. char    PC;        /* Pad char */
  49. #endif
  50. WINDOW    *stdscr;    /* pointer into kbuf[] */
  51. WINDOW    kbuf[KBSIZ];    /* a very large output buffer */
  52. int    LINES;        /* :li#: number of rows */
  53. int    COLS;        /* :co#: number of columns */
  54. int    AM;        /* :am:  boolean: auto margins? */
  55. int    PT;        /* :pt:  boolean: physical tabs? */
  56. char    *VB;        /* :vb=: visible bell */
  57. char    *UP;        /* :up=: move cursor up */
  58. char    *SO;        /* :so=: standout start */
  59. char    *SE;        /* :se=: standout end */
  60. char    *US = "";    /* :us=: underline start */
  61. char    *UE = "";    /* :ue=: underline end */
  62. char    *MD = "";    /* :md=: bold start */
  63. char    *ME = "";    /* :me=: bold end */
  64. char    *AS;        /* :as=: alternate (italic) start */
  65. char    *AE;        /* :ae=: alternate (italic) end */
  66. char    *CM;        /* :cm=: cursor movement */
  67. char    *CE;        /* :ce=: clear to end of line */
  68. char    *CD;        /* :cd=: clear to end of screen */
  69. char    *AL;        /* :al=: add a line */
  70. char    *DL;        /* :dl=: delete a line */
  71. #if OSK
  72. char    *SR_;        /* :sr=: scroll reverse */
  73. #else
  74. char    *SR;        /* :sr=: scroll reverse */
  75. #endif
  76. char    *KS;        /* :ks=: init string for cursor */
  77. char    *KE;        /* :ke=: restore string for cursor */
  78. char    *KU;        /* :ku=: key sequence sent by up arrow */
  79. char    *KD;        /* :kd=: key sequence sent by down arrow */
  80. char    *KL;        /* :kl=: key sequence sent by left arrow */
  81. char    *KR;        /* :kr=: key sequence sent by right arrow */
  82. char    *HM;        /* :HM=: key sequence sent by the <Home> key */
  83. char    *EN;        /* :EN=: key sequence sent by the <End> key */
  84. char    *PU;        /* :PU=: key sequence sent by the <PgUp> key */
  85. char    *PD;        /* :PD=: key sequence sent by the <PgDn> key */
  86. char    *IM;        /* :im=: insert mode start */
  87. char    *IC = "";    /* :ic=: insert the following character */
  88. char    *EI;        /* :ei=: insert mode end */
  89. char    *DC;        /* :dc=: delete a character */
  90. char    *TI;        /* :ti=: terminal init */    /* GB */
  91. char    *TE;        /* :te=: terminal exit */    /* GB */
  92. #ifndef NO_CURSORSHAPE
  93. char    *CQ = (char *)0;/* :cQ=: normal cursor */
  94. char    *CX = (char *)1;/* :cX=: cursor used for EX command/entry */
  95. char    *CV = (char *)2;/* :cV=: cursor used for VI command mode */
  96. char    *CI = (char *)3;/* :cI=: cursor used for VI input mode */
  97. char    *CR = (char *)4;/* :cR=: cursor used for VI replace mode */
  98. #endif
  99. char    *aend = "";    /* end an attribute -- either UE or ME */
  100. char    ERASEKEY;    /* backspace key taken from ioctl structure */
  101.  
  102. #if ANY_UNIX
  103. # if UNIXV
  104. static struct termio    oldtermio;    /* original tty mode */
  105. static struct termio    newtermio;    /* cbreak/noecho tty mode */
  106. # else
  107. static struct sgttyb    oldsgttyb;    /* original tty mode */
  108. static struct sgttyb    newsgttyb;    /* cbreak/nl/noecho tty mode */
  109. static int        oldint;        /* ^C or DEL, the "intr" character */
  110. #  ifdef TIOCSLTC
  111. static int        oldswitch;    /* ^Z, the "suspend" character */
  112. static int        oldquote;    /* ^V, the "quote next char" char */
  113. #  endif
  114. # endif
  115. #endif
  116.  
  117. #if OSK
  118. static struct sgbuf    oldsgttyb;    /* orginal tty mode */
  119. static struct sgbuf    newsgttyb;    /* noecho tty mode */
  120. #endif
  121.  
  122. static char    *capbuf;    /* capability string buffer */
  123.  
  124.  
  125. void initscr()
  126. {
  127.     /* make sure TERM variable is set */
  128. #if MSDOS
  129.     char *val;
  130.     if (! (val = getenv("TERM"))
  131.     || !strcmp(val, "pcbios"))
  132. #else
  133.     if (!getenv("TERM"))
  134. #endif
  135.     {
  136. #if ANY_UNIX
  137.         write(2, "Environment variable TERM must be set\n", (unsigned)38);
  138.         exit(1);
  139. #endif
  140. #if OSK
  141.         writeln(2, "Environment variable TERM must be set\n", (unsigned)38);
  142.         exit(1);
  143. #endif
  144. #if MSDOS || TOS
  145.         getsize(0);
  146. #endif
  147.     }
  148.     else
  149.     {
  150. #if MSDOS
  151.         *o_pcbios=0;
  152. #endif
  153.         /* start termcap stuff */
  154.         starttcap();
  155.     }
  156.  
  157.     /* create stdscr and curscr */
  158.     stdscr = kbuf;
  159.  
  160.     /* change the terminal mode to cbreak/noecho */
  161. #if ANY_UNIX
  162. # if UNIXV
  163.     ioctl(2, TCGETA, &oldtermio);
  164. # else
  165.     ioctl(2, TIOCGETP, &oldsgttyb);
  166. # endif
  167. #endif
  168.  
  169. #if OSK
  170.     _gs_opt(0, &oldsgttyb);
  171. #endif
  172.     resume_curses(TRUE);
  173. }
  174.  
  175.  
  176. void endwin()
  177. {
  178.     /* change the terminal mode back the way it was */
  179.     suspend_curses();
  180. }
  181.  
  182.  
  183. static int curses_active = FALSE;
  184.  
  185. void suspend_curses()
  186. {
  187. #if ANY_UNIX && !UNIXV
  188.     struct tchars    tbuf;
  189. # ifdef TIOCSLTC
  190.     struct ltchars    ltbuf;
  191. # endif
  192. #endif
  193. #ifndef NO_CURSORSHAPE
  194.     if (has_CQ)
  195.     {
  196.         do_CQ();
  197.     }
  198. #endif
  199.     if (has_TE)                    /* GB */
  200.     {
  201.         do_TE();
  202.     }
  203.     if (has_KE)
  204.     {
  205.         do_KE();
  206.     }
  207.     refresh();
  208.  
  209.     /* change the terminal mode back the way it was */
  210. #if ANY_UNIX
  211. # if UNIXV
  212.     ioctl(2, TCSETAW, &oldtermio);
  213. # else
  214.     ioctl(2, TIOCSETP, &oldsgttyb);
  215.  
  216.     ioctl(2, TIOCGETC, &tbuf);
  217.     tbuf.t_intrc = oldint;
  218.     ioctl(2, TIOCSETC, &tbuf);
  219.  
  220. #  ifdef TIOCSLTC
  221.     ioctl(2, TIOCGLTC, <buf);
  222.     ltbuf.t_suspc = oldswitch;
  223.     ltbuf.t_lnextc = oldquote;
  224.     ioctl(2, TIOCSLTC, <buf);
  225. #  endif
  226. # endif
  227. #endif
  228. #if OSK
  229.     _ss_opt(0, &oldsgttyb);
  230. #endif
  231.     curses_active = FALSE;
  232. }
  233.  
  234. void resume_curses(quietly)
  235.     int    quietly;
  236. {
  237.     if (!curses_active)
  238.     {
  239.         /* change the terminal mode to cbreak/noecho */
  240. #if ANY_UNIX
  241. # if UNIXV
  242.         ospeed = (oldtermio.c_cflag & CBAUD);
  243.         ERASEKEY = oldtermio.c_cc[VERASE];
  244.         newtermio = oldtermio;
  245.         newtermio.c_iflag &= (IXON|IXOFF|IXANY|ISTRIP|IGNBRK);
  246.         newtermio.c_oflag &= ~OPOST;
  247.         newtermio.c_lflag &= ISIG;
  248.         newtermio.c_cc[VINTR] = ctrl('C'); /* always use ^C for interrupts */
  249.         newtermio.c_cc[VMIN] = 1;
  250.         newtermio.c_cc[VTIME] = 0;
  251. #  ifdef VSWTCH
  252.         newtermio.c_cc[VSWTCH] = 0;
  253. #  endif
  254.         ioctl(2, TCSETAW, &newtermio);
  255. # else /* BSD or V7 or Coherent or Minix */
  256.         struct tchars    tbuf;
  257. #  ifdef TIOCSLTC
  258.         struct ltchars    ltbuf;
  259. #  endif
  260.  
  261.         ospeed = oldsgttyb.sg_ospeed;
  262.         ERASEKEY = oldsgttyb.sg_erase;
  263.         newsgttyb = oldsgttyb;
  264.         newsgttyb.sg_flags |= CBREAK;
  265.         newsgttyb.sg_flags &= ~(CRMOD|ECHO|XTABS);
  266.         ioctl(2, TIOCSETP, &newsgttyb);
  267.  
  268.         ioctl(2, TIOCGETC, &tbuf);
  269.         oldint = tbuf.t_intrc;
  270.         tbuf.t_intrc = ctrl('C');    /* always use ^C for interrupts */
  271.         ioctl(2, TIOCSETC, &tbuf);
  272.  
  273. #  ifdef TIOCSLTC
  274.         ioctl(2, TIOCGLTC, <buf);
  275.         oldswitch = ltbuf.t_suspc;
  276.         ltbuf.t_suspc = 0;        /* disable ^Z for elvis */
  277.         oldquote = ltbuf.t_lnextc;
  278.         ltbuf.t_lnextc = 0;        /* disable ^V for elvis */
  279.         ioctl(2, TIOCSLTC, <buf);
  280. #  endif
  281.  
  282. # endif
  283. #endif
  284. #if OSK
  285.         newsgttyb = oldsgttyb;
  286.         newsgttyb.sg_echo = 0;
  287.         newsgttyb.sg_eofch = 0;
  288.         newsgttyb.sg_kbach = 0;
  289.         newsgttyb.sg_kbich = ctrl('C');
  290.         _ss_opt(0, &newsgttyb);
  291.         ospeed = oldsgttyb.sg_baud;
  292.         ERASEKEY = oldsgttyb.sg_bspch;
  293. #endif
  294.  
  295.         if (has_TI)                    /* GB */
  296.         {
  297.             do_TI();
  298.         }
  299.         if (has_KS)
  300.         {
  301.             do_KS();
  302.         }
  303.  
  304.         curses_active = TRUE;
  305.     }
  306.  
  307.     /* If we're supposed to quit quietly, then we're done */
  308.     if (quietly)
  309.     {
  310.         return;
  311.     }
  312.  
  313.     signal(SIGINT, SIG_IGN);
  314.  
  315.     move(LINES - 1, 0);
  316.     do_SO();
  317.     qaddstr("[Press <RETURN> to continue]");
  318.     do_SE();
  319.     refresh();
  320.     ttyread(kbuf, 20); /* in RAW mode, so <20 is very likely */
  321.     if (kbuf[0] == ':')
  322.     {
  323.         mode = MODE_COLON;
  324.         addch('\n');
  325.         refresh();
  326.     }
  327.     else
  328.     {
  329.         mode = MODE_VI;
  330.         redraw(MARK_UNSET, FALSE);
  331.     }    
  332.     exwrote = FALSE;
  333.  
  334. #if TURBOC
  335.     signal(SIGINT, (void(*)()) trapint);
  336. #else
  337.     signal(SIGINT, trapint);
  338. #endif
  339. }
  340.  
  341. static void lacking(s)
  342.     char    *s;
  343. {
  344.     write(2, "This termcap entry lacks the :", (unsigned)30);
  345.     write(2, s, (unsigned)2);
  346.     write(2, "=: capability\n", (unsigned)14);
  347. #if OSK
  348.     write(2, "\l", 1);
  349. #endif
  350.     exit(1);
  351. }
  352.  
  353. static void starttcap()
  354. {
  355.     char    *str;
  356.     static char    cbmem[800];
  357. #define MUSTHAVE(T,s)    if (!(T = tgetstr(s, &capbuf))) lacking(s)
  358. #define MAYHAVE(T,s)    if (str = tgetstr(s, &capbuf)) T = str
  359. #define PAIR(T,U,sT,sU)    T=tgetstr(sT,&capbuf);U=tgetstr(sU,&capbuf);if (!T||!U)T=U=""
  360.  
  361.     /* allocate memory for capbuf */
  362.     capbuf = cbmem;
  363.  
  364.     /* get the termcap entry */
  365.     switch (tgetent(kbuf, getenv("TERM")))
  366.     {
  367.       case -1:
  368.         write(2, "Can't read /etc/termcap\n", (unsigned)24);
  369. #if OSK
  370.         write(2, "\l", 1);
  371. #endif
  372.         exit(2);
  373.  
  374.       case 0:
  375.         write(2, "Unrecognized TERM type\n", (unsigned)23);
  376. #if OSK
  377.         write(2, "\l", 1);
  378. #endif
  379.         exit(3);
  380.     }
  381.  
  382.     /* get strings */
  383.     MUSTHAVE(UP, "up");
  384.     MAYHAVE(VB, "vb");
  385.     MUSTHAVE(CM, "cm");
  386.     PAIR(SO, SE, "so", "se");
  387.     PAIR(TI, TE, "ti", "te");
  388.     if (tgetnum("ug") <= 0)
  389.     {
  390.         PAIR(US, UE, "us", "ue");
  391.         PAIR(MD, ME, "md", "me");
  392.  
  393.         /* get italics, or have it default to underline */
  394.         PAIR(AS, AE, "as", "ae");
  395.         if (!*AS)
  396.         {
  397.             AS = US;
  398.             AE = UE;
  399.         }
  400.     }
  401.     MAYHAVE(AL, "al");
  402.     MAYHAVE(DL, "dl");
  403.     MUSTHAVE(CE, "ce");
  404.     MAYHAVE(CD, "cd");
  405. #if OSK
  406.     MAYHAVE(SR_, "sr");
  407. #else    
  408.     MAYHAVE(SR, "sr");
  409. #endif
  410.     PAIR(IM, EI, "im", "ei");
  411.     MAYHAVE(IC, "ic");
  412.     MAYHAVE(DC, "dc");
  413.  
  414.     /* other termcap stuff */
  415.     AM = tgetflag("am");
  416.     PT = tgetflag("pt");
  417.     getsize(0);
  418.  
  419.     /* Key sequences */
  420.     PAIR(KS, KE, "ks", "ke");
  421.     MAYHAVE(KU, "ku");        /* up */
  422.     MAYHAVE(KD, "kd");        /* down */
  423.     MAYHAVE(KL, "kl");        /* left */
  424.     MAYHAVE(KR, "kr");        /* right */
  425.     MAYHAVE(PU, "kP");        /* PgUp */
  426.     MAYHAVE(PD, "kN");        /* PgDn */
  427.     MAYHAVE(HM, "kh");        /* Home */
  428.     MAYHAVE(EN, "kH");        /* End */
  429. #ifndef CRUNCH
  430.     if (!PU) MAYHAVE(PU, "K2");    /* "3x3 pad" names for PgUp, etc. */
  431.     if (!PD) MAYHAVE(PD, "K5");
  432.     if (!HM) MAYHAVE(HM, "K1");
  433.     if (!EN) MAYHAVE(EN, "K4");
  434.  
  435.     MAYHAVE(PU, "PU");        /* old XENIX names for PgUp, etc. */
  436.     MAYHAVE(PD, "PD");        /* (overrides others, if used.) */
  437.     MAYHAVE(HM, "HM");
  438.     MAYHAVE(EN, "EN");
  439. #endif
  440.  
  441. #ifndef NO_CURSORSHAPE
  442.     /* cursor shapes */
  443.     CQ = tgetstr("cQ", &capbuf);
  444.     if (has_CQ)
  445.     {
  446.         CX = tgetstr("cX", &capbuf);
  447.         if (!CX) CX = CQ;
  448.         CV = tgetstr("cV", &capbuf);
  449.         if (!CV) CV = CQ;
  450.         CI = tgetstr("cI", &capbuf);
  451.         if (!CI) CI = CQ;
  452.         CR = tgetstr("cR", &capbuf);
  453.         if (!CR) CR = CQ;
  454.     }
  455. # ifndef CRUNCH
  456.     else
  457.     {
  458.         PAIR(CQ, CV, "ve", "vs");
  459.         CX = CI = CR = CQ;
  460.     }
  461. # endif /* !CRUNCH */
  462. #endif /* !NO_CURSORSHAPE */
  463.  
  464. #undef MUSTHAVE
  465. #undef MAYHAVE
  466. #undef PAIR
  467. }
  468.  
  469.  
  470. /* This function gets the window size.  It uses the TIOCGWINSZ ioctl call if
  471.  * your system has it, or tgetnum("li") and tgetnum("co") if it doesn't.
  472.  * This function is called once during initialization, and thereafter it is
  473.  * called whenever the SIGWINCH signal is sent to this process.
  474.  */
  475. int getsize(signo)
  476.     int    signo;
  477. {
  478.     int    lines;
  479.     int    cols;
  480. #ifdef TIOCGWINSZ
  481.     struct winsize size;
  482. #endif
  483.  
  484. #ifdef SIGWINCH
  485.     /* reset the signal vector */
  486.     signal(SIGWINCH, getsize);
  487. #endif
  488.  
  489.     /* get the window size, one way or another. */
  490.     lines = cols = 0;
  491. #ifdef TIOCGWINSZ
  492.     if (ioctl(2, TIOCGWINSZ, &size) >= 0)
  493.     {
  494.         lines = size.ws_row;
  495.         cols = size.ws_col;
  496.     }
  497. #endif
  498.     if ((lines == 0 || cols == 0) && signo == 0)
  499.     {
  500.         LINES = CHECKBIOS(v_rows(), tgetnum("li"));
  501.         COLS = CHECKBIOS(v_cols(), tgetnum("co"));
  502.     }
  503.     if (lines >= 2 && cols >= 30)
  504.     {
  505.         LINES = lines;
  506.         COLS = cols;
  507.     }
  508.  
  509.     /* Make sure we got values that we can live with */
  510.     if (LINES < 2 || COLS < 30)
  511.     {
  512.         write(2, "Screen too small\n", (unsigned)17);
  513. #if OSK
  514.         write(2, "\l", 1);
  515. #endif
  516.         endwin();
  517.         exit(2);
  518.     }
  519.  
  520.     /* !!! copy the new values into Elvis' options */
  521.     {
  522.         extern char    o_columns[], o_lines[];
  523.  
  524.         *o_columns = COLS;
  525.         *o_lines = LINES;
  526.     }
  527.  
  528.     return 0;
  529. }
  530.  
  531.  
  532. /* This is a function version of addch() -- it is used by tputs() */
  533. int faddch(ch)
  534.     int    ch;
  535. {
  536.     addch(ch);
  537.  
  538.     return 0;
  539. }
  540.  
  541. /* These functions are equivelent to the macros of the same names... */
  542.  
  543. void qaddstr(str)
  544.     char    *str;
  545. {
  546.     REG char *s_, *d_;
  547.  
  548. #if MSDOS
  549.     if (o_pcbios[0])
  550.     {
  551.         while (*str)
  552.             qaddch(*str++);
  553.         return;
  554.     }
  555. #endif
  556.     for (s_=(str), d_=stdscr; *d_++ = *s_++; )
  557.     {
  558.     }
  559.     stdscr = d_ - 1;
  560. }
  561.  
  562. void attrset(a)
  563.     int    a;
  564. {
  565.     do_aend();
  566.     if (a == A_BOLD)
  567.     {
  568.         do_MD();
  569.         aend = ME;
  570.     }
  571.     else if (a == A_UNDERLINE)
  572.     {
  573.         do_US();
  574.         aend = UE;
  575.     }
  576.     else if (a == A_ALTCHARSET)
  577.     {
  578.         do_AS();
  579.         aend = AE;
  580.     }
  581.     else
  582.     {
  583.         aend = "";
  584.     }
  585. }
  586.  
  587.  
  588. void insch(ch)
  589.     int    ch;
  590. {
  591.     if (has_IM)
  592.         do_IM();
  593.     do_IC();
  594.     qaddch(ch);
  595.     if (has_EI)
  596.         do_EI();
  597. }
  598.  
  599. #if MSDOS
  600.  
  601. static int alarmtime;
  602.  
  603. /* raw read - #defined to read (0, ...) on non-MSDOS.
  604.  * With MSDOS, am maximum of 1 byte is read.
  605.  * If more bytes should be read, just change the loop.
  606.  * The following code uses the IBM-PC-System-Timer, so probably wont't work
  607.  * on non-compatibles.
  608.  */
  609. /*ARGSUSED*/
  610. ttyread(buf, len)
  611.     char *buf;
  612.     int len;
  613. {
  614.     volatile char far *biostimer;
  615.     char oldtime;
  616.     int nticks = 0;
  617.     int pos = 0;
  618.  
  619.     biostimer = (char far *)0x0040006cl;
  620.     oldtime = *biostimer;
  621.  
  622.     while (!pos && (!alarmtime || nticks<alarmtime))
  623.     {    if (kbhit())
  624.             if ((buf[pos++] = getch()) == 0) /* function key */
  625.                 buf[pos-1] = '#';
  626.         if (oldtime != *biostimer)
  627.         {    nticks++;
  628.             oldtime = *biostimer;
  629.         }
  630.     }
  631.     return pos;
  632. }
  633.  
  634. alarm(time)
  635.     int time;
  636. {
  637.     alarmtime = 2 * time;        /* ticks are 1/18 sec. */
  638. }
  639.  
  640. sleep(seconds)
  641.     unsigned seconds;
  642. {
  643.     volatile char    far *biostimer = (char far *)0x0040006cl;
  644.     char        stop;
  645.  
  646.     stop = *biostimer + 18 * seconds;
  647.     while (*biostimer != stop)
  648.     {
  649.     }
  650. }
  651. #endif
  652.  
  653. #if TOS
  654.  
  655. static int alarmtime;
  656. static long timer;
  657.  
  658. static gettime()
  659. {
  660.     timer = *(long *)(0x4ba);
  661. }
  662.  
  663. /*ARGSUSED*/
  664. ttyread(buf, len)
  665.     char *buf;
  666.     int len;
  667. {
  668.     int    pos=0;
  669.     long    l;
  670.     long    endtime;
  671.  
  672.     Supexec(gettime);
  673.     endtime = timer+alarmtime;
  674.  
  675.     while (!pos && (!alarmtime || timer<endtime))
  676.     {
  677.         if (Bconstat(2))
  678.         {
  679.             l = Bconin(2);
  680.             if ((buf[pos++]=l) == '\0')
  681.             {
  682.                 buf[pos-1]='#';
  683.                 buf[pos++]=l>>16;
  684.             }
  685.         }
  686.         Supexec(gettime);
  687.     }
  688.     return pos;
  689. }
  690.  
  691. alarm(time)
  692.     int time;
  693. {
  694.     alarmtime = 50 * time;        /* ticks are 1/200 sec. */
  695. }
  696.  
  697. ttywrite(buf, len)
  698.     char *buf;
  699.     int len;
  700. {
  701.     while (len--)
  702.         Bconout(2, *buf++);
  703. }
  704. #endif
  705.  
  706. #if OSK
  707. ttyread(buf, len)
  708.     char *buf;
  709.     int len;
  710. {
  711.     REG int i;
  712.     if ((i = _gs_rdy(0)) > 0)
  713.         return read(0, buf, i < len ? i : len);
  714.     else
  715.         return read(0, buf, 1);
  716. }
  717.  
  718. alarm(time)
  719.     int time;
  720. {
  721. #define TIME(secs) ((secs << 8) | 0x80000000)
  722.     static int alrmid;
  723.  
  724.     if (time)    
  725.         alrmid = alm_set(SIGQUIT, TIME(time));
  726.     else    
  727.         alm_delete(alrmid);
  728. }
  729. #endif /* OSK */
  730.