home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / VILE327.ZIP / VILE327.TAR / vile3.27 / termio.c < prev    next >
C/C++ Source or Header  |  1992-12-14  |  27KB  |  1,167 lines

  1. /*
  2.  * The functions in this file negotiate with the operating system for
  3.  * characters, and write characters in a barely buffered fashion on the display.
  4.  * All operating systems.
  5.  *
  6.  * $Log: termio.c,v $
  7.  * Revision 1.51  1992/12/05  13:58:20  foxharp
  8.  * added missing TTclose to ttclean, for Tom Dickey on his apollo -- I'm not
  9.  * convinced this seems right, but I'll try it for now.
  10.  *
  11.  * Revision 1.50  1992/12/04  09:18:04  foxharp
  12.  * added another flush
  13.  *
  14.  * Revision 1.49  1992/08/20  23:40:48  foxharp
  15.  * typo fixes -- thanks, eric
  16.  *
  17.  * Revision 1.48  1992/08/19  23:02:47  foxharp
  18.  * ignore errors in ttunclean
  19.  *
  20.  * Revision 1.47  1992/08/04  20:14:58  foxharp
  21.  * invert sense of ifdef -- it seems filio.h isn't as common as I thought
  22.  *
  23.  * Revision 1.46  1992/07/24  07:49:27  foxharp
  24.  * aix has no filio.h
  25.  *
  26.  * Revision 1.45  1992/07/20  22:50:40  foxharp
  27.  * use putchar/getchar instead of fputc/fgetc
  28.  *
  29.  * Revision 1.44  1992/07/17  19:19:47  foxharp
  30.  * took out commented cruft
  31.  *
  32.  * Revision 1.43  1992/07/01  17:04:33  foxharp
  33.  * always use && and || in #if statements, and
  34.  * MSC now uses getch() to get characters, and
  35.  * use TTputc() to put out cr-nl pairs instead of ttputc()
  36.  *
  37.  * Revision 1.42  1992/06/26  22:19:32  foxharp
  38.  * improved (i hope) the FIONREAD ifdefs.  needs testing.
  39.  *
  40.  * Revision 1.41  1992/06/25  23:00:50  foxharp
  41.  * changes for dos/ibmpc
  42.  *
  43.  * Revision 1.40  1992/06/22  08:35:13  foxharp
  44.  * AIX has the fcntl bug, but isn't BERK.  also added ifdef VSWTCH protection
  45.  *
  46.  * Revision 1.39  1992/06/14  11:33:54  foxharp
  47.  * fcntl hack for AIX
  48.  *
  49.  * Revision 1.38  1992/06/11  09:44:10  foxharp
  50.  * try to avoid the fcntl() bug with better ifdefing
  51.  *
  52.  * Revision 1.37  1992/05/27  19:16:22  foxharp
  53.  * took out extra call to setbuffer()
  54.  *
  55.  * Revision 1.36  1992/05/25  21:34:29  foxharp
  56.  * moved extern func declarations to header
  57.  *
  58.  * Revision 1.34  1992/05/20  18:55:42  foxharp
  59.  * don't use fcntl on a/ux, either
  60.  *
  61.  * Revision 1.33  1992/05/16  12:00:31  pgf
  62.  * prototypes/ansi/void-int stuff/microsoftC
  63.  *
  64.  * Revision 1.32  1992/05/13  09:13:41  pgf
  65.  * make X11 do even less in ttclean/unclean routines
  66.  *
  67.  * Revision 1.31  1992/04/14  08:40:11  pgf
  68.  * added osf hack, to use sgtty instead of posix, and fixed sun hack, to use
  69.  * fionread instead of fcntl, to prevent output flush during typeahead check
  70.  *
  71.  * Revision 1.30  1992/04/10  18:50:22  pgf
  72.  * always include termios.h, not sys/termios.h, and
  73.  * don't call setbuffer on odt or isc
  74.  *
  75.  * Revision 1.29  1992/03/26  09:16:59  pgf
  76.  * ifdef cleanup
  77.  *
  78.  * Revision 1.28  1992/03/25  19:13:17  pgf
  79.  * BSD portability changes
  80.  *
  81.  * Revision 1.27  1992/03/20  08:59:28  pgf
  82.  * kbd_is_polled was out of sync after ttclean/unclean
  83.  *
  84.  * Revision 1.26  1992/03/19  23:27:20  pgf
  85.  * SIGT for signals, linux port
  86.  *
  87.  * Revision 1.25  1992/03/19  23:09:46  pgf
  88.  * TIOCSETP is now TIOCSETN, in all cases
  89.  *
  90.  * Revision 1.24  1992/03/07  10:25:58  pgf
  91.  * AIX support (where is termios.h supposed to be?)
  92.  *
  93.  * Revision 1.23  1992/01/22  20:28:28  pgf
  94.  * call TTclose in ttunclean, to support tcapclose().  i hope this is safe
  95.  * for other screen types
  96.  *
  97.  * Revision 1.22  1992/01/10  08:11:41  pgf
  98.  * fixed signal handling, for sysV style handling.  also
  99.  * fixed 2nd arg to tcsetattr()
  100.  *
  101.  * Revision 1.21  1992/01/02  22:42:40  pgf
  102.  * oops -- dropped the termio restoral in ttclean
  103.  *
  104.  * Revision 1.20  1992/01/01  16:30:14  pgf
  105.  * more ifdef'ing on V_SUSP (for pyramid?), and
  106.  * now get tty chars under X11, though we still don't set new modes
  107.  *
  108.  * Revision 1.19  1991/12/20  08:12:00  pgf
  109.  * check the error return from tcsetattr()
  110.  *
  111.  * Revision 1.18  1991/12/04  09:22:19  pgf
  112.  * a little more massaging of ifdefs
  113.  *
  114.  * Revision 1.17  1991/11/27  10:13:10  pgf
  115.  * code split/re-arranged, cleaner posix support
  116.  *
  117.  * Revision 1.16  1991/11/16  18:35:55  pgf
  118.  * changed the ifdefing so termio or sgtty can be used independently of
  119.  * other UNIX choices
  120.  *
  121.  * Revision 1.15  1991/11/14  08:58:17  pgf
  122.  * switch to TCSETAW from TSSETAF in ttclean and unclean -- don't want to
  123.  * flush input needlessly
  124.  *
  125.  * Revision 1.14  1991/11/13  20:09:27  pgf
  126.  * X11 changes, from dave lemke
  127.  *
  128.  * Revision 1.13  1991/11/07  02:00:32  pgf
  129.  * lint cleanup
  130.  *
  131.  * Revision 1.12  1991/11/01  14:38:00  pgf
  132.  * saber cleanup
  133.  *
  134.  * Revision 1.11  1991/10/15  12:18:39  pgf
  135.  * fetch more termio chars at startup, like wkillc, suspc, etc.
  136.  *
  137.  * Revision 1.10  1991/08/12  15:05:43  pgf
  138.  * rearranged read-ahead in one of the tgetc options
  139.  *
  140.  * Revision 1.9  1991/08/07  12:35:07  pgf
  141.  * added RCS log messages
  142.  *
  143.  * revision 1.8
  144.  * date: 1991/07/19 17:17:49;
  145.  * change backspace action to back_char_to_bol()
  146.  * 
  147.  * revision 1.7
  148.  * date: 1991/06/28 10:54:00;
  149.  * change a config ifdef
  150.  * 
  151.  * revision 1.6
  152.  * date: 1991/04/22 09:06:57;
  153.  * POSIX/ULTRIX changes
  154.  * 
  155.  * revision 1.5
  156.  * date: 1991/02/14 15:50:41;
  157.  * fixed size problem on olstate/nlstate
  158.  * 
  159.  * revision 1.4
  160.  * date: 1990/12/06 18:54:48;
  161.  * tried to get ttgetc to return -1 on interrupt -- doesn't work
  162.  * 
  163.  * revision 1.3
  164.  * date: 1990/10/12 19:32:11;
  165.  * do SETAF, not SETA in ttunclean
  166.  * 
  167.  * revision 1.2
  168.  * date: 1990/10/03 16:01:04;
  169.  * make backspace work for everyone
  170.  * 
  171.  * revision 1.1
  172.  * date: 1990/09/21 10:26:10;
  173.  * initial vile RCS revision
  174.  */
  175. #include        <stdio.h>
  176. #include    "estruct.h"
  177. #include        "edef.h"
  178.  
  179. #if UNIX
  180. #include    <errno.h>
  181. extern int errno;
  182.  
  183. /* there are three copies of the tt...() routines here -- one each for
  184.     POSIX termios, traditional termio, and sgtty.  If you have a
  185.     choice, I recommend them in that order. */
  186.  
  187. /* ttopen() and ttclose() are responsible for putting the terminal in raw
  188.     mode, setting up terminal signals, etc.
  189.    ttclean() prepares the terminal for shell escapes, and ttunclean() gets
  190.        us back into vile's mode
  191. */
  192.  
  193. #include    <signal.h>
  194.  
  195. /* I suppose this config stuff should move to estruct.h */
  196.  
  197. #if OSF1        /* don't know why termios doesn't yet work in osf 1.1 */
  198. # undef POSIX
  199. # undef BERK
  200. # define BERK 1
  201. #endif
  202.  
  203.  
  204. #if POSIX
  205. # define USE_POSIX_TERMIOS 1
  206. # define USE_FCNTL 1
  207. #else
  208. # if USG
  209. #  define USE_TERMIO 1
  210. #  define USE_FCNTL 1
  211. # else
  212. #  if BERK || V7
  213. #   define USE_SGTTY 1
  214. #   define USE_FIONREAD 1
  215. #  else
  216.  huh?
  217. #  endif
  218. # endif
  219. #endif
  220.  
  221. #if (BERK || AIX || AUX2) && !defined(FIONREAD)
  222. /* try harder to get it */
  223. # if SUNOS
  224. #  include "filio.h"
  225. # else
  226. #  include "ioctl.h"
  227. # endif
  228. #endif
  229.  
  230. #if X11    /* don't use either one */
  231. # undef USE_FCNTL
  232. # undef USE_FIONREAD
  233. #else
  234. # if defined(FIONREAD)
  235.   /* there seems to be a bug in someone's implementation of fcntl -- it
  236.    * causes output to be flushed if you change to ndelay input while output
  237.    * is pending.  for these systems, we use FIONREAD instead, if possible. 
  238.    * In fact, if try and use FIONREAD in any case if present.  If you have
  239.    * the problem with fcntl, you'll notice that the screen doesn't always
  240.    * refresh correctly, as if the fcntl is interfering with the output drain
  241.    */
  242. #  undef USE_FCNTL
  243. #  define USE_FIONREAD     1
  244. # endif
  245. #endif
  246.  
  247. #if USE_FCNTL
  248. /* this is used to determine whether input is pending from the user */
  249. #include    <fcntl.h>
  250. int kbd_flags;            /* saved keyboard fcntl flags    */
  251. int kbd_is_polled;        /* in O_NDELAY mode?        */
  252. int kbd_char_present;        /* there is a char in kbd_char    */
  253. char kbd_char;            /* the char we've already read    */
  254. #endif
  255.  
  256. #define SMALL_STDOUT 1
  257.  
  258. #if defined(SMALL_STDOUT) && (defined (USE_FCNTL) || defined(USE_FIONREAD))
  259. #define    TBUFSIZ    128 /* Provide a smaller terminal output buffer so that
  260.        the type-ahead detection works better (more often).
  261.        That is, we overlap screen writing with more keyboard polling */
  262. #else
  263. #define    TBUFSIZ    1024    /* reduces the number of writes */
  264. #endif
  265.  
  266. extern CMDFUNC f_backchar;
  267. extern CMDFUNC f_backchar_to_bol;
  268.  
  269.  
  270. #if USE_POSIX_TERMIOS
  271.  
  272. #include <termios.h>
  273.  
  274. struct termios otermios, ntermios;
  275.  
  276. char tobuf[TBUFSIZ];        /* terminal output buffer */
  277.  
  278. void
  279. ttopen()
  280. {
  281.     int s;
  282.     s = tcgetattr(0, &otermios);
  283.     if (s < 0) {
  284.         perror("ttopen tcgetattr");
  285.         exit(1);
  286.     }
  287. #if ODT || ISC
  288.     setvbuf(stdout, tobuf, _IOLBF, TBUFSIZ);
  289. #else
  290.       setbuffer(stdout, tobuf, TBUFSIZ);
  291. #endif
  292.  
  293.     suspc =   otermios.c_cc[VSUSP];
  294.     intrc =   otermios.c_cc[VINTR];
  295.     killc =   otermios.c_cc[VKILL];
  296.     startc =  otermios.c_cc[VSTART];
  297.     stopc =   otermios.c_cc[VSTOP];
  298.     backspc = otermios.c_cc[VERASE];
  299. #ifdef VWERASE  /* Sun has it.  any others? */
  300.     wkillc = otermios.c_cc[VWERASE];
  301. #else
  302.     wkillc =  tocntrl('W');
  303. #endif
  304.  
  305.     { /* this could probably be done more POSIX'ish? */
  306.     signal(SIGTSTP,SIG_DFL);    /* set signals so that we can */
  307.     signal(SIGCONT,rtfrmshell);    /* suspend & restart */
  308.     signal(SIGTTOU,SIG_IGN);    /* ignore output prevention */
  309.     }
  310.  
  311. #if USE_FCNTL
  312.     kbd_flags = fcntl( 0, F_GETFL, 0 );
  313.     kbd_is_polled = FALSE;
  314. #endif
  315.  
  316. #if ! X11
  317.     ntermios = otermios;
  318.  
  319.     /* setup new settings, preserve flow control, and allow BREAK */
  320.     ntermios.c_iflag = BRKINT|(otermios.c_iflag & IXON|IXANY|IXOFF);
  321.     ntermios.c_oflag = 0;
  322.     ntermios.c_lflag = ISIG;
  323.     ntermios.c_cc[VMIN] = 1;
  324.     ntermios.c_cc[VTIME] = 0;
  325. #ifdef    VSWTCH
  326.     ntermios.c_cc[VSWTCH] = -1;
  327. #endif
  328.     ntermios.c_cc[VSUSP] = -1;
  329.     ntermios.c_cc[VSTART] = -1;
  330.     ntermios.c_cc[VSTOP] = -1;
  331. #endif
  332.  
  333.     ttmiscinit();
  334.  
  335.     ttunclean();
  336.  
  337.  
  338. }
  339.  
  340. void
  341. ttclose()
  342. {
  343.     ttclean(TRUE);
  344. }
  345.  
  346. void
  347. ttclean(f)
  348. int f;
  349. {
  350. #if !X11
  351.     if (f) {
  352.         movecursor(term.t_nrow, ttcol); /* don't care about column */
  353.         TTputc('\n');
  354.         TTputc('\r');
  355.     }
  356.     fflush(stdout);
  357. #if ! LINUX
  358.     tcdrain(1);
  359. #endif
  360.     tcsetattr(0, TCSADRAIN, &otermios);
  361.     TTclose();
  362.     TTflush();
  363. #if USE_FCNTL
  364.     fcntl(0, F_SETFL, kbd_flags);
  365.     kbd_is_polled = FALSE;
  366. #endif
  367. #endif
  368. }
  369.  
  370. void
  371. ttunclean()
  372. {
  373. #if ! X11
  374. #if ! LINUX
  375.     tcdrain(1);
  376. #endif
  377.     tcsetattr(0, TCSADRAIN, &ntermios);
  378. #endif
  379. }
  380.  
  381.  
  382. #endif /* USE_POSIX_TERMIOS */
  383.  
  384. #if USE_TERMIO
  385.  
  386. #include    <termio.h>
  387.  
  388. /* original terminal characteristics and characteristics to use inside */
  389. struct    termio    otermio, ntermio;
  390.  
  391. #ifdef AVAILABLE  /* setbuffer() isn't on most termio systems */
  392. char tobuf[TBUFSIZ];        /* terminal output buffer */
  393. #endif
  394.  
  395. void
  396. ttopen()
  397. {
  398.  
  399.     ioctl(0, TCGETA, &otermio);    /* save old settings */
  400. #ifdef AVAILABLE
  401.     setbuffer(stdout, tobuf, TBUFSIZ);
  402. #endif
  403.  
  404.     intrc =   otermio.c_cc[VINTR];
  405.     killc =   otermio.c_cc[VKILL];
  406.     startc =  tocntrl('Q');
  407.     stopc =   tocntrl('S');
  408.     backspc = otermio.c_cc[VERASE];
  409.     wkillc =  tocntrl('W');
  410.  
  411. #if USE_FCNTL
  412.     kbd_flags = fcntl( 0, F_GETFL, 0 );
  413.     kbd_is_polled = FALSE;
  414. #endif
  415.  
  416. #if SIGTSTP
  417. /* be careful here -- VSUSP is sometimes out of the range of the c_cc array */
  418. # ifdef VSUSP /* ODT (all POSIX?) uses this... */
  419.     ntermio.c_cc[VSUSP] = -1;
  420.     ntermio.c_cc[VSTART] = -1;
  421.     ntermio.c_cc[VSTOP] = -1;
  422.     suspc =   otermio.c_cc[VSUSP];
  423. # else /* use V_SUSP */
  424. #  ifdef V_SUSP
  425.     ntermio.c_cc[V_SUSP] = -1;
  426.     suspc = otermio.c_cc[V_SUSP];
  427. #  else
  428.     suspc = -1;
  429. #  endif
  430. #  ifdef V_DSUSP
  431.     ntermio.c_cc[V_DSUSP] = -1;
  432. #  endif
  433. # endif
  434.     {
  435.     signal(SIGTSTP,SIG_DFL);    /* set signals so that we can */
  436.     signal(SIGCONT,rtfrmshell);    /* suspend & restart */
  437.     signal(SIGTTOU,SIG_IGN);    /* ignore output prevention */
  438.     }
  439. #else /* no SIGTSTP */
  440.     suspc =   tocntrl('Z');
  441. #endif
  442.  
  443. #if ! X11
  444.     ntermio = otermio;
  445.  
  446.     /* setup new settings, preserve flow control, and allow BREAK */
  447.     ntermio.c_iflag = BRKINT|(otermio.c_iflag & IXON|IXANY|IXOFF);
  448.     ntermio.c_oflag = 0;
  449.     ntermio.c_lflag = ISIG;
  450.     ntermio.c_cc[VMIN] = 1;
  451.     ntermio.c_cc[VTIME] = 0;
  452. #ifdef    VSWTCH
  453.     ntermio.c_cc[VSWTCH] = -1;
  454. #endif
  455. #endif
  456.  
  457.     ttmiscinit();
  458.     ttunclean();
  459.  
  460. }
  461.  
  462. void
  463. ttclose()
  464. {
  465.     ttclean(TRUE);
  466. }
  467.  
  468. void
  469. ttclean(f)
  470. int f;
  471. {
  472. #if    X11
  473.     TTflush();
  474.     TTclose();
  475. #else
  476.     if (f) {
  477.         movecursor(term.t_nrow, ttcol); /* don't care about column */
  478.         TTputc('\n');
  479.         TTputc('\r');
  480.     }
  481.     TTflush();
  482.     TTclose();
  483.     ioctl(0, TCSETAF, &otermio);
  484. #if USE_FCNTL
  485.     fcntl(0, F_SETFL, kbd_flags);
  486.     kbd_is_polled = FALSE;
  487. #endif
  488. #endif    /* X11 */
  489. }
  490.  
  491. void
  492. ttunclean()
  493. {
  494. #if ! X11
  495.     ioctl(0, TCSETAW, &ntermio);
  496. #endif
  497. }
  498.  
  499. #endif /* USE_TERMIO */
  500.  
  501. #if USE_SGTTY
  502.  
  503. #if USE_FIONREAD
  504. char tobuf[TBUFSIZ];        /* terminal output buffer */
  505. #endif
  506.  
  507. #undef    CTRL
  508. #include        <sgtty.h>        /* for stty/gtty functions */
  509. struct  sgttyb  ostate;          /* saved tty state */
  510. struct  sgttyb  nstate;          /* values for editor mode */
  511. struct  sgttyb  rnstate;          /* values for raw editor mode */
  512. int olstate;        /* Saved local mode values */
  513. int nlstate;        /* new local mode values */
  514. struct ltchars    oltchars;    /* Saved terminal special character set */
  515. struct ltchars    nltchars = { -1, -1, -1, -1, -1, -1 }; /* a lot of nothing */
  516. struct tchars    otchars;    /* Saved terminal special character set */
  517. struct tchars    ntchars; /*  = { -1, -1, -1, -1, -1, -1 }; */
  518.  
  519. void
  520. ttopen()
  521. {
  522.     ioctl(0,TIOCGETP,&ostate); /* save old state */
  523.     killc = ostate.sg_kill;
  524.     backspc = ostate.sg_erase;
  525.  
  526. #if ! X11
  527.     nstate = ostate;
  528.         nstate.sg_flags |= CBREAK;
  529.         nstate.sg_flags &= ~(ECHO|CRMOD);       /* no echo for now... */
  530.     ioctl(0,TIOCSETN,&nstate); /* set new state */
  531. #endif
  532.  
  533.     rnstate = nstate;
  534.         rnstate.sg_flags &= ~CBREAK;
  535.         rnstate.sg_flags |= RAW;
  536.  
  537.     ioctl(0, TIOCGETC, &otchars);        /* Save old characters */
  538.     intrc =  otchars.t_intrc;
  539.     startc = otchars.t_startc;
  540.     stopc =  otchars.t_stopc;
  541.  
  542. #if ! X11
  543.     ntchars = otchars;
  544.     ntchars.t_brkc = -1;
  545.     ntchars.t_eofc = -1;
  546.     ioctl(0, TIOCSETC, &ntchars);        /* Place new character into K */
  547. #endif
  548.  
  549.     ioctl(0, TIOCGLTC, &oltchars);        /* Save old characters */
  550.     wkillc = oltchars.t_werasc;
  551.     suspc = oltchars.t_suspc;
  552. #if ! X11
  553.     ioctl(0, TIOCSLTC, &nltchars);        /* Place new character into K */
  554. #endif
  555.  
  556. #ifdef    TIOCLGET
  557.     ioctl(0, TIOCLGET, &olstate);
  558. #if ! X11
  559.     nlstate = olstate;
  560.     nlstate |= LLITOUT;
  561.     ioctl(0, TIOCLSET, &nlstate);
  562. #endif
  563. #endif
  564. #if USE_FIONREAD
  565.     setbuffer(stdout, tobuf, TBUFSIZ);
  566. #endif
  567. #if ! X11
  568.     {
  569.     signal(SIGTSTP,SIG_DFL);    /* set signals so that we can */
  570.     signal(SIGCONT,rtfrmshell);    /* suspend & restart */
  571.     signal(SIGTTOU,SIG_IGN);    /* ignore output prevention */
  572.     }
  573. #endif
  574.  
  575.     ttmiscinit();
  576.  
  577. }
  578.  
  579. void
  580. ttclose()
  581. {
  582.     ttclean(TRUE);
  583. }
  584.  
  585. void
  586. ttclean(f)
  587. int f;
  588. {
  589. #if ! X11
  590.     if (f) {
  591.         movecursor(term.t_nrow, ttcol); /* don't care about column */
  592.         TTputc('\n');
  593.         TTputc('\r');
  594.     }
  595.     TTflush();
  596.     TTclose();
  597.     ioctl(0, TIOCSETN, &ostate);
  598.     ioctl(0, TIOCSETC, &otchars);
  599.     ioctl(0, TIOCSLTC, &oltchars);
  600. #ifdef    TIOCLSET
  601.     ioctl(0, TIOCLSET, &olstate);
  602. #endif
  603. #endif
  604. }
  605.  
  606. void
  607. ttunclean()
  608. {
  609. #if ! X11
  610.     ioctl(0, TIOCSETN, &nstate);
  611.     ioctl(0, TIOCSETC, &ntchars);
  612.     ioctl(0, TIOCSLTC, &nltchars);
  613. #ifdef    TIOCLSET
  614.     ioctl(0, TIOCLSET, &nlstate);
  615. #endif
  616. #endif
  617. }
  618.  
  619. #endif /* USE_SGTTY */
  620.  
  621. void
  622. ttputc(c)
  623. int c;
  624. {
  625.         putchar(c);
  626. }
  627.  
  628. void
  629. ttflush()
  630. {
  631.         fflush(stdout);
  632. }
  633.  
  634. extern int tungotc;
  635.  
  636. /*
  637.  * Read a character from the terminal, performing no editing and doing no echo
  638.  * at all.
  639.  */
  640. int
  641. ttgetc()
  642. {
  643. #if    USE_FCNTL
  644.     int n;
  645.     if( kbd_char_present ) {
  646.         kbd_char_present = FALSE;
  647.     } else {
  648.         if( kbd_is_polled && fcntl( 0, F_SETFL, kbd_flags ) < 0 )
  649.             imdying(2);
  650.         kbd_is_polled = FALSE;
  651.         n = read(0, &kbd_char, 1);
  652.         if (n <= 0) {
  653.             if (n < 0 && errno == EINTR)
  654.                 return -1;
  655.             imdying(2);
  656.         }
  657.     }
  658.     return ( kbd_char & 0x7f );
  659. #else /* USE_FCNTL */
  660.     int c;
  661.         c = getchar();
  662.     if (c == EOF) {
  663.         if (errno == EINTR)
  664.             return -1;
  665.         imdying(2);
  666.     } else {
  667.         c &= 0x7f;
  668.     }
  669.     return c;
  670. #endif
  671. }
  672.  
  673.  
  674. /* typahead:    Check to see if any characters are already in the
  675.         keyboard buffer
  676. */
  677. int
  678. typahead()
  679. {
  680. #if    NeWS
  681.     return(inhibit_update) ;
  682. #else
  683. # if X11
  684.     return x_key_events_ready();
  685. # else
  686.  
  687.     if (tungotc > 0)
  688.         return TRUE;
  689.  
  690. #  if    USE_FIONREAD
  691.     {
  692.     long x;
  693.     return((ioctl(0,FIONREAD,&x) < 0) ? 0 : (int)x);
  694.     }
  695. #  else
  696. #   if    USE_FCNTL
  697.     if( !kbd_char_present )
  698.     {
  699.         if( !kbd_is_polled &&
  700.                 fcntl(0, F_SETFL, kbd_flags|O_NDELAY ) < 0 )
  701.             return(FALSE);
  702.         kbd_is_polled = TRUE;  /* I think */
  703.         kbd_char_present = (1 == read( 0, &kbd_char, 1 ));
  704.     }
  705.     return ( kbd_char_present );
  706. #   else
  707.     return FALSE;
  708. #   endif/* USE_FCNTL */
  709. #  endif/* USE_FIONREAD */
  710. # endif    /* X11 */
  711. #endif    /* NeWS */
  712. }
  713.  
  714. /* this takes care of some stuff that's common across all ttopen's.  Some of
  715.     it should arguably be somewhere else, but... */
  716. void
  717. ttmiscinit()
  718. {
  719.     /* make sure backspace is bound to backspace */
  720.     asciitbl[backspc] = &f_backchar_to_bol;
  721.  
  722.     /* make sure backspace is considered a backspace by the code */
  723.     _chartypes_[backspc] |= _bspace;
  724.  
  725.     /* no buffering on input */
  726.     setbuf(stdin, NULL);
  727. }
  728.  
  729. #else /* not UNIX */
  730.  
  731. #if   MSDOS && (TURBO || MSC)
  732. #include <conio.h>
  733. #endif
  734.  
  735. #if     AMIGA
  736. #define NEW 1006L
  737. #define AMG_MAXBUF      1024L
  738. static long terminal;
  739. static char     scrn_tmp[AMG_MAXBUF+1];
  740. static long     scrn_tmp_p = 0;
  741. #endif
  742.  
  743. #if ST520 && MEGAMAX
  744. #include <osbind.h>
  745.     int STscancode = 0;    
  746. #endif
  747.  
  748. #if     VMS
  749. #include        <stsdef.h>
  750. #include        <ssdef.h>
  751. #include        <descrip.h>
  752. #include        <iodef.h>
  753. #include        <ttdef.h>
  754. #include    <tt2def.h>
  755.  
  756. #define NIBUF   128                     /* Input buffer size            */
  757. #define NOBUF   1024                    /* MM says bug buffers win!     */
  758. #define EFN     0                       /* Event flag                   */
  759.  
  760. char    obuf[NOBUF];                    /* Output buffer                */
  761. int     nobuf;                  /* # of bytes in above    */
  762. char    ibuf[NIBUF];                    /* Input buffer          */
  763. int     nibuf;                  /* # of bytes in above  */
  764. int     ibufi;                  /* Read index                   */
  765. int     oldmode[3];                     /* Old TTY mode bits            */
  766. int     newmode[3];                     /* New TTY mode bits            */
  767. short   iochan;                  /* TTY I/O channel             */
  768. #endif
  769.  
  770. #if     CPM
  771. #include        <bdos.h>
  772. #endif
  773.  
  774. #if     MSDOS && (LATTICE || TURBO || AZTEC || MWC86 || ZTC)
  775. union REGS rg;        /* cpu register for use of DOS calls */
  776. int nxtchar = -1;    /* character held from type ahead    */
  777. #endif
  778.  
  779. #if RAINBOW
  780. #include "rainbow.h"
  781. #endif
  782.  
  783. extern CMDFUNC f_backchar;
  784. extern CMDFUNC f_backchar_to_bol;
  785.  
  786. void
  787. ttopen()
  788. {
  789. #if     AMIGA
  790.     char oline[NSTRING];
  791. #if    AZTEC
  792.     extern    Enable_Abort;    /* Turn off ctrl-C interrupt */
  793.  
  794.     Enable_Abort = 0;    /* for the Manx compiler */
  795. #endif
  796.     strcpy(oline, "RAW:0/0/640/200/");
  797.     strcat(oline, PROGNAME);
  798.     strcat(oline, " ");
  799.     strcat(oline, VERSION);
  800.     strcat(oline, "/Amiga");
  801.         terminal = Open(oline, NEW);
  802. #endif
  803. #if     VMS
  804.         struct  dsc$descriptor  idsc;
  805.         struct  dsc$descriptor  odsc;
  806.         char    oname[40];
  807.         int     iosb[2];
  808.         int     status;
  809.  
  810.         odsc.dsc$a_pointer = "TT";
  811.         odsc.dsc$w_length  = strlen(odsc.dsc$a_pointer);
  812.         odsc.dsc$b_dtype        = DSC$K_DTYPE_T;
  813.         odsc.dsc$b_class        = DSC$K_CLASS_S;
  814.         idsc.dsc$b_dtype        = DSC$K_DTYPE_T;
  815.         idsc.dsc$b_class        = DSC$K_CLASS_S;
  816.         do {
  817.                 idsc.dsc$a_pointer = odsc.dsc$a_pointer;
  818.                 idsc.dsc$w_length  = odsc.dsc$w_length;
  819.                 odsc.dsc$a_pointer = &oname[0];
  820.                 odsc.dsc$w_length  = sizeof(oname);
  821.                 status = LIB$SYS_TRNLOG(&idsc, &odsc.dsc$w_length, &odsc);
  822.                 if (status!=SS$_NORMAL && status!=SS$_NOTRAN)
  823.                         exit(status);
  824.                 if (oname[0] == 0x1B) {
  825.                         odsc.dsc$a_pointer += 4;
  826.                         odsc.dsc$w_length  -= 4;
  827.                 }
  828.         } while (status == SS$_NORMAL);
  829.         status = SYS$ASSIGN(&odsc, &iochan, 0, 0);
  830.         if (status != SS$_NORMAL)
  831.                 exit(status);
  832.         status = SYS$QIOW(EFN, iochan, IO$_SENSEMODE, iosb, 0, 0,
  833.                           oldmode, sizeof(oldmode), 0, 0, 0, 0);
  834.         if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
  835.                 exit(status);
  836.         newmode[0] = oldmode[0];
  837.         newmode[1] = oldmode[1] | TT$M_NOECHO;
  838.         newmode[1] &= ~(TT$M_TTSYNC|TT$M_HOSTSYNC);
  839.         newmode[2] = oldmode[2] | TT2$M_PASTHRU;
  840.         status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
  841.                           newmode, sizeof(newmode), 0, 0, 0, 0);
  842.         if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
  843.                 exit(status);
  844.         term.t_nrow = (newmode[1]>>24) - 1;
  845.         term.t_ncol = newmode[0]>>16;
  846.  
  847. #endif
  848. #if     CPM
  849. #endif
  850.  
  851. #if     MSDOS && (HP150 == 0) && LATTICE
  852.     /* kill the ctrl-break interrupt */
  853.     rg.h.ah = 0x33;        /* control-break check dos call */
  854.     rg.h.al = 1;        /* set the current state */
  855.     rg.h.dl = 0;        /* set it OFF */
  856.     intdos(&rg, &rg);    /* go for it! */
  857. #endif
  858.  
  859.     /* make sure backspace is bound to backspace */
  860.     asciitbl[backspc] = &f_backchar_to_bol;
  861.  
  862.     /* make sure backspace is considered a backspace by the code */
  863.     _chartypes_[backspc] |= _bspace;
  864. }
  865.  
  866. void
  867. ttclose()
  868. {
  869. #if     AMIGA
  870. #if    LATTICE
  871.         amg_flush();
  872.         Close(terminal);
  873. #endif
  874. #if    AZTEC
  875.         amg_flush();
  876.     Enable_Abort = 1;    /* Fix for Manx */
  877.         Close(terminal);
  878. #endif
  879. #endif
  880.  
  881. #if     VMS
  882.         int     status;
  883.         int     iosb[1];
  884.  
  885.         ttflush();
  886.         status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
  887.                  oldmode, sizeof(oldmode), 0, 0, 0, 0);
  888.         if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
  889.                 exit(status);
  890.         status = SYS$DASSGN(iochan);
  891.         if (status != SS$_NORMAL)
  892.                 exit(status);
  893. #endif
  894. #if     MSDOS && (HP150 == 0) && LATTICE
  895.     /* restore the ctrl-break interrupt */
  896.     rg.h.ah = 0x33;        /* control-break check dos call */
  897.     rg.h.al = 1;        /* set the current state */
  898.     rg.h.dl = 1;        /* set it ON */
  899.     intdos(&rg, &rg);    /* go for it! */
  900. #endif
  901.  
  902.     ttclean(TRUE);
  903. }
  904.  
  905. void
  906. ttclean(f)
  907. int f;
  908. {
  909.     if (f) {
  910.         movecursor(term.t_nrow, ttcol); /* don't care about column */
  911.         TTputc('\n');
  912.         TTputc('\r');
  913.     }
  914.     TTflush();
  915.     TTclose();
  916.     TTkclose();
  917. }
  918.  
  919. void
  920. ttunclean()
  921. {
  922. }
  923.  
  924. /*
  925.  * Write a character to the display. On VMS, terminal output is buffered, and
  926.  * we just put the characters in the big array, after checking for overflow.
  927.  * On CPM terminal I/O unbuffered, so we just write the byte out. Ditto on
  928.  * MS-DOS (use the very very raw console output routine).
  929.  */
  930. void
  931. ttputc(c)
  932. int c;
  933. {
  934. #if     AMIGA
  935.         scrn_tmp[scrn_tmp_p++] = c;
  936.         if(scrn_tmp_p>=AMG_MAXBUF)
  937.                 amg_flush();
  938. #endif
  939. #if    ST520 && MEGAMAX
  940.     Bconout(2,c);
  941. #endif
  942. #if     VMS
  943.         if (nobuf >= NOBUF)
  944.                 ttflush();
  945.         obuf[nobuf++] = c;
  946. #endif
  947. #if     CPM
  948.         bios(BCONOUT, c, 0);
  949. #endif
  950. #if     MSDOS && MWC86
  951.         putcnb(c);
  952. #endif
  953. #if    MSDOS && (LATTICE || AZTEC) && ~IBMPC
  954.     bdos(6, c, 0);
  955. #endif
  956. #if RAINBOW
  957.         Put_Char(c);                    /* fast video */
  958. #endif
  959. }
  960.  
  961. #if    AMIGA
  962. amg_flush()
  963. {
  964.         if(scrn_tmp_p)
  965.                 Write(terminal,scrn_tmp,scrn_tmp_p);
  966.         scrn_tmp_p = 0;
  967. }
  968. #endif
  969.  
  970. /*
  971.  * Flush terminal buffer. Does real work where the terminal output is buffered
  972.  * up. A no-operation on systems where byte at a time terminal I/O is done.
  973.  */
  974. void
  975. ttflush()
  976. {
  977. #if     AMIGA
  978.         amg_flush();
  979. #endif
  980. #if     VMS
  981.         int     status;
  982.         int     iosb[2];
  983.  
  984.         status = SS$_NORMAL;
  985.         if (nobuf != 0) {
  986.                 status = SYS$QIOW(EFN, iochan, IO$_WRITELBLK|IO$M_NOFORMAT,
  987.                          iosb, 0, 0, obuf, nobuf, 0, 0, 0, 0);
  988.                 if (status == SS$_NORMAL)
  989.                         status = iosb[0] & 0xFFFF;
  990.                 nobuf = 0;
  991.         }
  992.         return (status);
  993. #endif
  994.  
  995. #if     CPM
  996. #endif
  997.  
  998. #if     MSDOS
  999. #endif
  1000. }
  1001.  
  1002. extern int tungotc;
  1003.  
  1004. /*
  1005.  * Read a character from the terminal, performing no editing and doing no echo
  1006.  * at all. More complex in VMS that almost anyplace else, which figures. Very
  1007.  * simple on CPM, because the system can do exactly what you want.
  1008.  */
  1009. int
  1010. ttgetc()
  1011. {
  1012. #if     AMIGA
  1013.     {
  1014.         char ch;
  1015.  
  1016.         amg_flush();
  1017.         Read(terminal, &ch, 1L);
  1018.         return(255 & (int)ch);
  1019.     }
  1020. #endif
  1021. #if    ST520 && MEGAMAX
  1022.     {
  1023.     long ch;
  1024.  
  1025. /*
  1026.  * blink the cursor only if nothing is happening, this keeps the
  1027.  * cursor on steadily during movement making it easier to track
  1028.  */
  1029.     STcurblink(TRUE);  /* the cursor blinks while we wait */
  1030.     ch = Bconin(2);
  1031.     STcurblink(FALSE); /* the cursor is steady while we work */
  1032.     STscancode = (ch >> 16) & 0xff;
  1033.            return(255 & (int)ch);
  1034.     }
  1035. #endif
  1036. #if     VMS
  1037.     {
  1038.         int     status;
  1039.         int     iosb[2];
  1040.         int     term[2];
  1041.  
  1042.         while (ibufi >= nibuf) {
  1043.                 ibufi = 0;
  1044.                 term[0] = 0;
  1045.                 term[1] = 0;
  1046.                 status = SYS$QIOW(EFN, iochan, IO$_READLBLK|IO$M_TIMED,
  1047.                          iosb, 0, 0, ibuf, NIBUF, 0, term, 0, 0);
  1048.                 if (status != SS$_NORMAL)
  1049.                         exit(status);
  1050.                 status = iosb[0] & 0xFFFF;
  1051.                 if (status!=SS$_NORMAL && status!=SS$_TIMEOUT)
  1052.                         exit(status);
  1053.                 nibuf = (iosb[0]>>16) + (iosb[1]>>16);
  1054.                 if (nibuf == 0) {
  1055.                         status = SYS$QIOW(EFN, iochan, IO$_READLBLK,
  1056.                                  iosb, 0, 0, ibuf, 1, 0, term, 0, 0);
  1057.                         if (status != SS$_NORMAL
  1058.                         || (status = (iosb[0]&0xFFFF)) != SS$_NORMAL)
  1059.                                 exit(status);
  1060.                         nibuf = (iosb[0]>>16) + (iosb[1]>>16);
  1061.                 }
  1062.         }
  1063.         return (ibuf[ibufi++] & 0xFF);    /* Allow multinational  */
  1064.  
  1065.     }
  1066. #endif
  1067. #if     CPM
  1068.     {
  1069.         return (biosb(BCONIN, 0, 0));
  1070.  
  1071.     }
  1072. #endif
  1073. #if RAINBOW
  1074.     {
  1075.     int c;
  1076.  
  1077.         while ((c = Read_Keyboard()) < 0);
  1078.  
  1079.         if ((c & Function_Key) == 0)
  1080.                 if (!((c & 0xFF) == 015 || (c & 0xFF) == 0177))
  1081.                         c &= 0xFF;
  1082.  
  1083.         return c;
  1084.     }
  1085. #endif
  1086. #if     MSDOS && MWC86
  1087.     {
  1088.         return (getcnb());
  1089.  
  1090.     }
  1091. #endif
  1092. #if    MSDOS && MSC
  1093.     {
  1094.     return getch();
  1095.     }
  1096. #endif
  1097. #if    MSDOS && (LATTICE || TURBO || AZTEC || ZTC)
  1098.     {
  1099.     int c;
  1100.  
  1101.     /* if a char already is ready, return it */
  1102.     if (nxtchar >= 0) {
  1103.         c = nxtchar;
  1104.         nxtchar = -1;
  1105.         return(c);
  1106.     }
  1107.  
  1108.     /* call the dos to get a char */
  1109.     rg.h.ah = 7;        /* dos Direct Console Input call */
  1110.     intdos(&rg, &rg);
  1111.     c = rg.h.al;        /* grab the char */
  1112.     return(c & 0xff);
  1113.     }
  1114. #endif
  1115.  
  1116. }
  1117.  
  1118.  
  1119. /* typahead:    Check to see if any characters are already in the
  1120.         keyboard buffer
  1121. */
  1122. int
  1123. typahead()
  1124. {
  1125.  
  1126. #if    MSDOS && (MSC || TURBO || ZTC)
  1127.     if (tungotc > 0)
  1128.         return TRUE;
  1129.  
  1130.     if (kbhit() != 0)
  1131.         return(TRUE);
  1132.     else
  1133.         return(FALSE);
  1134. #endif
  1135.  
  1136. #if    MSDOS && (LATTICE || AZTEC || MWC86)
  1137.     int c;        /* character read */
  1138.     int flags;    /* cpu flags from dos call */
  1139.  
  1140.     if (tungotc > 0)
  1141.         return TRUE;
  1142.  
  1143.     if (nxtchar >= 0)
  1144.         return(TRUE);
  1145.  
  1146.     rg.h.ah = 6;    /* Direct Console I/O call */
  1147.     rg.h.dl = 255;    /*         does console input */
  1148. #if    LATTICE || AZTEC
  1149.     flags = intdos(&rg, &rg);
  1150. #else
  1151.     intcall(&rg, &rg, 0x21);
  1152.     flags = rg.x.flags;
  1153. #endif
  1154.     c = rg.h.al;    /* grab the character */
  1155.  
  1156.     /* no character pending */
  1157.     if ((flags & 0x40) != 0)
  1158.         return(FALSE);
  1159.  
  1160.     /* save the character and return true */
  1161.     nxtchar = c;
  1162.     return(TRUE);
  1163. #endif
  1164. }
  1165.  
  1166. #endif /* not UNIX */
  1167.