home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / old / ckermit4e / ckvtio.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  27KB  |  942 lines

  1. char *ckxv = "VMS tty I/O, 1.0(013), 14 Sep 87";
  2.  
  3. /*  C K V T I O  --  Terminal and Interrupt Functions for VAX/VMS  */
  4.  
  5. /* Edit History
  6.  * 013 14 Sep 87 FdC    Add parity strip to ttinl(), add syscleanup().
  7.  * 012 11 Jul 85 FdC    Add gtimer(), rtimer() for timing statistics.
  8.  * 011  5 Jul 85 DS     Treat hangup of closed line as success.
  9.  * 010 25 Jun 85 MM     Added sysinit() to open console.
  10.  * 009 18 Jun 85 FdC    Move def of CTTNAM to ckcdeb.h so it can be shared.
  11.  * 008 11 Jun 85 MM     Fix definition of CTTNAM
  12.  *
  13.  * 007 16-May-85 FdC    Changed calling convention of ttopen(), make it
  14.  *                      set value of its argument "lcl", to tell whether
  15.  *                        C-Kermit is in local or remote mode.
  16.  *
  17.  * 006  8-May-85 MM    Got rid of "typeahead buffer" code as it didn't
  18.  *            solve the problem of data overruns at 4800 Baud.
  19.  *            Added vms "read a char" routine that checks for
  20.  *            CTRL/C, CTRL/Z, etc.
  21.  */
  22.  
  23. /* C-Kermit interrupt, terminal control & i/o functions for VMS systems */
  24.  
  25. /*  S. Rubenstein, Harvard University Chemical Labs  */
  26. /*  (c) 1985 President and Fellows of Harvard College  */
  27.  
  28. char *ckxsys = " Vax/VMS";
  29.  
  30.  
  31. /*
  32.  Variables available to outside world:
  33.  
  34.    dftty  -- Pointer to default tty name string, like "/dev/tty".
  35.    dfloc  -- 0 if dftty is console, 1 if external line.
  36.    dfprty -- Default parity
  37.    dfflow -- Default flow control
  38.    ckxech -- Flag for who echoes console typein:
  39.      1 - The program (system echo is turned off)
  40.      0 - The system (or front end, or terminal).
  41.    functions that want to do their own echoing should check this flag
  42.    before doing so.
  43.  
  44.    backgrd -- Flag indicating program executing in background ( & on 
  45.         end of shell command). Used to ignore INT and QUIT signals.
  46.    vms_status -- status returned by most recent system service
  47.         which may be used for error reporting.
  48.  
  49.  Functions for assigned communication line (either external or console tty):
  50.  
  51.    ttopen(ttname,local,mdmtyp) -- Open the named tty for exclusive access.
  52.    ttclos()                -- Close & reset the tty, releasing any access lock.
  53.    ttpkt(speed,flow)       -- Put the tty in packet mode and set the speed.
  54.    ttvt(speed,flow)        -- Put the tty in virtual terminal mode.
  55.                 or in DIALING or CONNECTED modem control state.
  56.    ttinl(dest,max,timo)    -- Timed read line from the tty.
  57.    ttinc(timo)             -- Timed read character from tty.
  58.    ttchk()                 -- See how many characters in tty input buffer.
  59.    ttxin(n,buf)            -- Read n characters from tty (untimed).
  60.    ttol(string,length)     -- Write a string to the tty.
  61.    ttoc(c)                 -- Write a character to the tty.
  62.    ttflui()                -- Flush tty input buffer.
  63. */
  64.  
  65.  
  66. /*
  67. Functions for console terminal:
  68.  
  69.    congm()   -- Get console terminal modes.
  70.    concb(esc) -- Put the console in single-character wakeup mode with no echo.
  71.    conbin(esc) -- Put the console in binary (raw) mode.
  72.    conres()  -- Restore the console to mode obtained by congm().
  73.    conoc(c)  -- Unbuffered output, one character to console.
  74.    conol(s)  -- Unbuffered output, null-terminated string to the console.
  75.    conola(s) -- Unbuffered output, array of lines to the console, CRLFs added.
  76.    conxo(n,s) -- Unbuffered output, n characters to the console.
  77.    conchk()  -- Check if characters available at console (bsd 4.2).
  78.         Check if escape char (^\) typed at console (System III/V).
  79.    coninc(timo)  -- Timed get a character from the console.
  80.    conint()  -- Enable terminal interrupts on the console if not background.
  81.    connoi()  -- Disable terminal interrupts on the console if not background.
  82.    contti()  -- Get a character from either console or tty, whichever is first.
  83.  
  84. Time functions
  85.  
  86.    msleep(m) -- Millisecond sleep
  87.    ztime(&s) -- Return pointer to date/time string
  88.    rtimer()  -- Reset elapsed time counter
  89.    gtimer()  -- Get elapsed time
  90. */
  91.  
  92.  
  93. /* Includes */
  94. #include "ckcker.h"
  95. #include <stdio.h>            /* Unix Standard i/o */
  96. #include <signal.h>            /* Interrupts */
  97. #include <setjmp.h>            /* Longjumps */
  98. #include <iodef.h>
  99. #include <ttdef.h>
  100. #include <ssdef.h>
  101. #include <descrip.h>
  102. #include <dvidef.h>
  103. #include <dcdef.h>
  104. #include "ckcdeb.h"            /* Formats for debug() */
  105.  
  106.  
  107. /* Declarations */
  108.  
  109.     long time();            /* Get current time in secs */
  110.  
  111. /* dftty is the device name of the default device for file transfer */
  112. /* dfloc is 0 if dftty is the user's console terminal, 1 if an external line */
  113.  
  114.     char *dftty = "TT:";
  115.     int dfloc = 0;            /* Default location is remote */
  116.     int dfprty = 0;            /* Parity (0 = none) */
  117.     int ttprty = 0;            /* Parity in use */
  118.     int dfflow = 1;            /* Xon/Xoff flow control */
  119.     int batch = 0;            /* Assume interactive */
  120.  
  121. int ckxech = 0; /* 0 if system normally echoes console characters, else 1 */
  122.  
  123. int vms_status;        /* Used for system service return status */
  124.  
  125. /* Structures used within this module */
  126.  
  127. struct tt_mode {
  128.     char class, type;
  129.     short width;
  130.     int basic : 24;
  131.     char length;
  132.     long extended;
  133. };
  134.  
  135. struct iosb_struct {
  136.     short status, size, terminator, termsize;
  137. };
  138.  
  139. /* Declarations of variables global within this module */
  140.  
  141. static int conif = 0,            /* Console interrupts on/off flag */
  142.     cgmf = 0,                /* Flag that console modes saved */
  143.     ttychn = 0,                /* TTY i/o channe; */
  144.     conchn = 0,                /* Console i/o channel */
  145.     con_queued = 0,            /* console i/o queued in contti() */
  146.     tt_queued = 0,            /* tty i/o queued in contti() */
  147.     conch,                /* console input character buffer  */
  148.     ttch;                /* tty input character buffer */
  149. static struct iosb_struct coniosb, ttiosb;
  150. static char escchr;            /* Escape or attn character */
  151. static struct tt_mode
  152.     ttold, ttraw, tttvt,        /* for communication line */
  153.     ccold, ccraw, cccbrk;        /* and for console */
  154.  
  155. static long tcount;            /* For timing statistics */
  156.  
  157. /*  Event flags used for I/O completion testing  */
  158. #define CON_EFN 1
  159. #define TTY_EFN 2
  160. #define TIM_EFN 3
  161. #define SUCCESS(x) (((vms_status = (x)) & 7) == 1)
  162. #define CHECK_ERR(s,x) (SUCCESS(x) ? 1 : print_msg(s))
  163.  
  164. #if 0
  165. /* These aren't used */
  166. static int inbufc = 0;            /* stuff for efficient raw line */
  167. static int ungotn = -1;            /* pushback to unread character */
  168. #endif
  169.  
  170.  
  171. /*  P R I N T _ M S G  --  Log an error message from VMS  */
  172.  
  173. print_msg(s) char *s; {
  174.     struct dsc$descriptor_s b;
  175.     short blen;
  176.     char buf[80], msg[120];
  177.  
  178.     b.dsc$w_length  = sizeof buf;
  179.     b.dsc$b_dtype   = DSC$K_DTYPE_T;
  180.     b.dsc$b_class   = DSC$K_CLASS_S;
  181.     b.dsc$a_pointer = buf;
  182.     SYS$GETMSG(vms_status, &blen, &b, 0, 0);
  183.     buf[blen] = '\0';
  184.     sprintf(msg, "%s: %s\n", s, buf);
  185.     ermsg(msg);
  186. }
  187.  
  188. /*  S Y S I N I T  --  System-dependent program initialization.  */
  189.  
  190. sysinit() {
  191.     if (conchn == 0)
  192.        conchn = vms_assign_channel("SYS$INPUT:");
  193.     return(0);
  194. }
  195.  
  196. /*  S Y S C L E A NU P -- System-dependent program epilog.  */
  197.  
  198. syscleanup() {
  199.     return(0);
  200. }
  201.  
  202.  
  203.  
  204. /*  T T O P E N  --  Open a tty for exclusive access.  */
  205.  
  206. /*  Returns 0 on success, -1 on failure.  */
  207.  
  208. ttopen(ttname,lcl,modem) char *ttname; int *lcl, modem; {
  209.  
  210.     if (ttychn != 0) return(0);        /* If already open, ignore this call */
  211.     ttychn = vms_assign_channel(ttname);
  212.     if (ttychn == 0) return(-1);
  213.     if (!CHECK_ERR("ttopen: SYS$QIOW",
  214.     SYS$QIOW(0, ttychn, IO$_SENSEMODE, 0, 0, 0,
  215.          &ttold, sizeof ttold, 0, 0, 0, 0))) return(-1);
  216.  
  217. /* Tell whether local or remote */
  218.  
  219.     *lcl = (strcmp(ttname,CTTNAM) == 0) ? 0 : 1;
  220.  
  221.     tttvt = ttold;
  222.     ttraw = ttold;
  223.     /*
  224.      * Possibly add "purge I/O" call here.
  225.      */
  226.     return(0);
  227. }
  228.  
  229.  
  230. vms_assign_channel(ttname) char *ttname;  {
  231.     int channel;
  232.     struct dsc$descriptor_s d;
  233.  
  234.     d.dsc$w_length  = strlen(ttname);
  235.     d.dsc$a_pointer = ttname;
  236.     d.dsc$b_class   = DSC$K_CLASS_S;
  237.     d.dsc$b_dtype   = DSC$K_DTYPE_T;
  238.     if (!CHECK_ERR("vms_assign_channel: SYS$ASSIGN",
  239.     SYS$ASSIGN(&d, &channel, 0, 0))) return(0);
  240.     else return(channel & 0xFFFF);
  241. }
  242.  
  243.  
  244. /*  T T C L O S  --  Close the TTY, releasing any lock.  */
  245.  
  246. ttclos() {
  247.     if (ttychn == 0) return(0);        /* Wasn't open. */
  248.     ttres();                /* Reset modes. */
  249.     if (!CHECK_ERR("ttclos: SYS$DASSGN",
  250.     SYS$DASSGN(ttychn))) return(-1);
  251.     ttychn = 0;                /* Mark it as closed. */
  252.     return(0);
  253. }
  254.  
  255.  
  256. /*  T T R E S  --  Restore terminal to "normal" mode.  */
  257.  
  258. ttres() {                /* Restore the tty to normal. */
  259.     if (ttychn == 0) return(-1);        /* Not open. */
  260.     sleep(1);                /* Wait for pending i/o to finish. */
  261.     debug(F101,"ttres, ttychn","",ttychn);
  262.     if (!CHECK_ERR("ttres: SYS$QIOW",
  263.     SYS$QIOW(0, ttychn, IO$_SETMODE, 0, 0, 0,
  264.              &ttold, sizeof ttold, 0, 0, 0, 0))) return(-1);
  265.     return(0);
  266. }
  267.  
  268.  
  269. /*  T T P K T  --  Condition the communication line for packets. */
  270. /*        or for modem dialing */
  271.  
  272. #define DIALING    4        /* flags (via flow) for modem handling */
  273. #define CONNECT 5
  274.  
  275. /*  If called with speed > -1, also set the speed.  */
  276.  
  277. /*  Returns 0 on success, -1 on failure.  */
  278.  
  279. ttpkt(speed,flow) int speed, flow; {
  280.     extern char ttname[];
  281.     int s;
  282.     if (ttychn == 0) return(-1);        /* Not open. */
  283.     s = ttsspd(speed);            /* Check the speed */
  284. #ifdef TT2$M_PASTHRU
  285.     ttraw.extended |= TT2$M_PASTHRU;
  286. #else
  287.     ttraw.basic |= TT$M_PASSALL;
  288. #endif
  289. #ifdef TT2$M_ALTYPEAHD
  290.     ttraw.extended |= TT2$M_ALTYPEAHD;
  291. #endif
  292.     ttraw.basic |= TT$M_NOECHO | TT$M_EIGHTBIT;
  293.     ttraw.basic &= ~TT$M_WRAP & ~TT$M_HOSTSYNC & ~TT$M_TTSYNC;
  294.     if (!CHECK_ERR("ttpkt: SYS$QIOW",
  295.     SYS$QIOW(0, ttychn, IO$_SETMODE, 0, 0, 0,
  296.                  &ttraw, sizeof ttraw, s, 0, 0, 0))) return(-1);
  297.     ttflui();                /* Flush any pending input */
  298.     return(0);
  299. }
  300.  
  301.  
  302. /*  T T V T -- Condition communication line for use as virtual terminal  */
  303.  
  304. ttvt(speed,flow) int speed, flow; {
  305.     extern char ttname[];
  306.     int s;
  307.     if (ttychn == 0) return(-1);        /* Not open. */
  308.  
  309.     s = ttsspd(speed);            /* Check the speed */
  310. #ifdef TT2$M_PASTHRU
  311.     ttraw.extended |= TT2$M_PASTHRU;
  312. #else
  313.     ttraw.basic |= TT$M_PASSALL;
  314. #endif
  315. #ifdef TT2$M_ALTYPEAHD
  316.     ttraw.extended |= TT2$M_ALTYPEAHD;
  317. #endif
  318.     ttraw.basic |= TT$M_NOECHO | TT$M_EIGHTBIT | TT$M_HOSTSYNC | TT$M_TTSYNC;
  319.     ttraw.basic &= ~TT$M_WRAP;
  320.     if (!CHECK_ERR("ttvt: SYS$QIOW",
  321.     SYS$QIOW(0, ttychn, IO$_SETMODE, 0, 0, 0,
  322.               &ttraw, sizeof ttraw, s, 0, 0, 0))) return(-1);
  323. }
  324.  
  325.  
  326. /*  T T S S P D  --  Return the internal baud rate code for 'speed'.  */
  327.  
  328. int speeds[] = {
  329.     110, 150, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, 0 } ;
  330.  
  331. static int speedcodes[] = {
  332.     TT$C_BAUD_110,  TT$C_BAUD_150,  TT$C_BAUD_300,  TT$C_BAUD_600,
  333.     TT$C_BAUD_1200, TT$C_BAUD_1800, TT$C_BAUD_2400, TT$C_BAUD_4800,
  334.     TT$C_BAUD_9600, TT$C_BAUD_19200 } ;
  335.  
  336. int
  337. ttsspd(speed) int speed; {
  338.     int s;
  339.     char msg[50];
  340.  
  341.     if (speed < 0)            /* 006 Unknown speed fails    */
  342.     return (0);
  343.     for (s = 0;  speeds[s] != 0 && speeds[s] != speed;  s++) ;
  344.     if (speeds[s] != 0)
  345.     return(speedcodes[s]);
  346.     else {
  347.     sprintf(msg,"Unsupported line speed - %d\n",speed);
  348.     ermsg(msg);
  349.     ermsg("Current speed not changed\n");
  350.     return(-1);
  351.     }
  352. }
  353.  
  354.  
  355.  
  356. /*  T T F L U I  --  Flush tty input buffer */
  357.  
  358. ttflui() {
  359.  
  360.     long n;
  361.     if (ttychn == 0) return(-1);        /* Not open. */
  362.  
  363.     if (!CHECK_ERR("ttflui: SYS$QIOW",
  364.     SYS$QIOW(0, ttychn, IO$_READVBLK|IO$M_TIMED|IO$M_PURGE,
  365.          0, 0, 0, &n, 0, 0, 0, 0, 0))) perror("flush failed");
  366.  
  367. #if 0
  368.     /* Note: unused */
  369.     inbufc = 0;
  370.     ungotn = -1;
  371. #endif
  372.     return(0);
  373. }
  374.  
  375.  
  376. /* Interrupt Functions */
  377.  
  378.  
  379. /*  C O N I N T  --  Console Interrupt setter  */
  380.  
  381. conint(f) int (*f)(); {            /* Set an interrupt trap. */
  382.  
  383.     if (batch) return;        /* must ignore signals in bkgrd */
  384.  
  385.     if (conif) return;            /* Nothing to do if already on. */
  386.  
  387. /* check if invoked in background -- if so signals set to be ignored */
  388.  
  389.     if (signal(SIGINT,SIG_IGN) == SIG_IGN) {
  390.     batch = 1;            /*   means running in background */
  391.     return;
  392.     }
  393.     signal(SIGINT,f);            /* Function to trap to. */
  394.     conif = 1;                /* Flag console interrupts on. */
  395. }
  396.  
  397.  
  398. /*  C O N N O I  --  Reset console terminal interrupts */
  399.  
  400. connoi() {                /* Console-no-interrupts */
  401.  
  402.     if (batch) return;            /* must ignore signals in bkgrd */
  403.  
  404.     signal(SIGINT,SIG_DFL);
  405.     conif = 0;
  406. }
  407.  
  408.  
  409. /*  T T C H K  --  Tell how many characters are waiting in tty input buffer  */
  410.  
  411. ttchk() {
  412.     struct { short count;  char first;  char reserved1;  long reserved2; } t;
  413.     return (/* inbufc + (ungotn >= 0) +        -- 006 Note: unused    */
  414.     (CHECK_ERR("ttchk: SYS$QIOW",
  415.     SYS$QIOW(0, ttychn, IO$_SENSEMODE|IO$M_TYPEAHDCNT, 0, 0, 0,
  416.               &t, sizeof t, 0, 0, 0, 0)) ? t.count : 0));
  417. }
  418.  
  419.  
  420. /*  T T X I N  --  Get n characters from tty input buffer  */
  421.  
  422. ttxin(n,buf) int n; char *buf; {
  423.     int x;
  424.     long trmmsk[2];
  425.  
  426.     trmmsk[0] = 0;
  427.     trmmsk[1] = 0;
  428.     if (!CHECK_ERR("ttxin: SYS$QIOW",
  429.     SYS$QIOW(0, ttychn, IO$_READVBLK, &ttiosb, 0, 0,
  430.               buf, n, 0, trmmsk, 0, 0))
  431.     || !CHECK_ERR("ttxin: ttiosb.status",ttiosb.status)) return(-1);
  432.     buf[n] = '\0';
  433.     return(ttiosb.size);
  434. }
  435.  
  436.  
  437. /*  T T O L  --  Similar to "ttinl", but for writing.  */
  438. /*
  439.  * This probably should be buffered with a flush command added.
  440.  */
  441.  
  442. ttol(s,n) int n; char *s; {
  443.     int x;
  444.     if (ttychn == 0) return(-1);        /* Not open. */
  445.     if (CHECK_ERR("ttol: SYS$QIOW",
  446.     SYS$QIOW(0, ttychn, IO$_WRITEVBLK, 0, 0, 0,
  447.         s, n, 0, 0, 0, 0))) x = 0;
  448.     else x = -1;
  449.     debug(F111,"ttol",s,n);
  450.     if (x < 0) debug(F101,"ttol failed","",x);
  451.     return(x);
  452. }
  453.  
  454.  
  455. /*  T T O C  --  Output a character to the communication line  */
  456.  
  457. ttoc(c) char c; {
  458.     if (ttychn == 0) return(-1);        /* Not open. */
  459.     if (CHECK_ERR("ttoc: SYS$QIOW",
  460.     SYS$QIOW(0, ttychn, IO$_WRITEVBLK, 0, 0, 0,
  461.         &c, 1, 0, 0, 0, 0))) return(0);
  462.     else return(-1);
  463. }
  464.  
  465.  
  466. /*  T T I N L  --  Read a record (up to break character) from comm line.  */
  467. /*
  468.   If no break character encountered within "max", return "max" characters,
  469.   with disposition of any remaining characters undefined.  Otherwise, return
  470.   the characters that were read, including the break character, in "dest" and
  471.   the number of characters read as the value of function, or 0 upon end of
  472.   file, or -1 if an error occurred.  Times out & returns error if not completed
  473.   within "timo" seconds.
  474. */
  475. /*** WARNING: THIS MIGHT NOT WORK ANY MORE, BECAUSE IT IS NOW THIS ***/
  476. /*** FUNCTION'S JOB TO STRIP PARITY.  I PUT IN SOME CODE THAT LOOKS LIKE ***/
  477. /*** IT SHOULD DO IT, BUT IT'S NOT TESTED.  - Frank, C-Kermit 4E ***/
  478.  
  479. ttinl(dest,max,timo,eol) int max,timo; char *dest; {
  480.     int x, y, c, i;
  481.     int trmmsk[2], func;
  482.  
  483.     if (ttychn == 0) return(-1);        /* Not open. */
  484.     trmmsk[0] = 0;
  485.     trmmsk[1] = 1 << eol;        /* Assumes eol is a control char */
  486.     func = IO$_READVBLK;
  487.     if (timo > 0) func |= IO$M_TIMED;
  488.     if (!CHECK_ERR("ttinl: SYS$QIOW",
  489.     SYS$QIOW(0, ttychn, func, &ttiosb, 0, 0,
  490.               dest, max, timo, trmmsk, 0, 0))
  491.     || ttiosb.status == SS$_TIMEOUT    /* Check separately so no err msg */
  492.     || !CHECK_ERR("ttinl: ttiosb.status",ttiosb.status)) return(-1);
  493.  
  494.     if (ttprty) {
  495.         for (i = 0; i < ttiosb.size; i++) dest[i] &= 0177; /* strip parity */
  496.     }
  497.     return(ttiosb.size);
  498. }
  499.  
  500.  
  501. /*  T T I N C --  Read a character from the communication line  */
  502.  
  503. ttinc(timo) int timo; {
  504.     int n;
  505.     CHAR ch;
  506.  
  507.     int trmmsk[2], func;
  508.  
  509.     if (ttychn == 0) return(-1);        /* Not open. */
  510.     trmmsk[0] = 0;
  511.     trmmsk[1] = 0;
  512.     func = IO$_READVBLK;
  513.     if (timo > 0) func |= IO$M_TIMED;
  514.     if (!CHECK_ERR("ttinc: SYS$QIOW",
  515.     SYS$QIOW(0, ttychn, func, &ttiosb, 0, 0,
  516.               &ch, 1, timo, trmmsk, 0, 0))
  517.     || ttiosb.status == SS$_TIMEOUT    /* Check separately so no err msg */
  518.     || !CHECK_ERR("ttinc: ttiosb.status",ttiosb.status)) return(-1);
  519.     return(ch & 0377);
  520. }
  521.  
  522.  
  523. /*  T T _ C A N C E L  --  Cancel i/o on tty channel if not complete  */
  524.  
  525. tt_cancel() {
  526.     int mask;
  527.     if (tt_queued) {
  528.     if (!CHECK_ERR("tt_cancel: SYS$READEF",
  529.     SYS$READEF(TTY_EFN, &mask))) return(-1);
  530.     if ((mask & (1<<TTY_EFN)) == 0) {
  531.         SYS$CANCEL(ttychn);
  532.         tt_queued = 0;
  533.     }
  534.     }
  535. }
  536.  
  537. /*  T T S N D B  --  Send a BREAK signal  */
  538.  
  539. ttsndb() {
  540.     int x;
  541.     struct tt_mode ttchr;
  542.  
  543.     if (ttychn == 0) return(-1);        /* Not open. */
  544.  
  545.     tt_cancel();
  546.     if (!CHECK_ERR("ttsndb: SENSEMODE",
  547.     SYS$QIOW(0, ttychn, IO$_SENSEMODE, &ttiosb, 0, 0,
  548.         &ttchr, sizeof ttchr, 0, 0, 0, 0))) return(-1);
  549.     if (!CHECK_ERR("ttsndb: SETMODE(1)",
  550.     SYS$QIOW(0, ttychn, IO$_SETMODE, 0, 0, 0,
  551.         &ttchr, sizeof ttchr, TT$C_BAUD_50, 0, 0, 0))) return(-1);
  552.     x = 0;
  553.     if (!CHECK_ERR("ttsndb: writing nulls",
  554.     SYS$QIOW(0, ttychn, IO$_WRITEVBLK, 0, 0, 0,
  555.         &x, 2, 0, 0, 0, 0))) return(-1);
  556.     if (!CHECK_ERR("ttsndb: SETMODE(2)",
  557.     SYS$QIOW(0, ttychn, IO$_SETMODE, 0, 0, 0,
  558.         &ttchr, sizeof ttchr, ttiosb.size, 0, 0, 0))) return(-1);
  559.     return(0);
  560. }
  561.  
  562.  
  563. /*  T T H A N G  --  Hang up the communications line  */
  564.  
  565. tthang() {
  566.     if (ttychn == 0) return(0);            /* Not open. */
  567.  
  568.     tt_cancel();
  569.     if (!CHECK_ERR("tthang: SYS$QIOW",
  570.     SYS$QIOW(0, ttychn, IO$_SETMODE|IO$M_HANGUP, 0, 0, 0,
  571.         0, 0, 0, 0, 0, 0))) return(-1);
  572.     return(0);
  573. }
  574.  
  575.  
  576. /*  M S L E E P  --  Millisecond version of sleep().  */
  577.  
  578. /*
  579.  Handles intervals up to about 7 minutes (2**32 / 10**7 seconds)
  580. */
  581.  
  582. msleep(m) int m; {
  583.  
  584.     struct time_struct {
  585.     long int hi, lo;
  586.     } t;
  587.     if (m <= 0) return(0);
  588.     t.hi = -10000 * m;  /*  Time in 100-nanosecond units  */
  589.     t.lo = -1;
  590.     if (!CHECK_ERR("msleep: SYS$SCHDWK",
  591.     SYS$SCHDWK(0, 0, &t, 0))) return(-1);
  592.     SYS$HIBER();
  593.     return(0);
  594. }
  595.  
  596. /*  R T I M E R --  Reset elapsed time counter  */
  597.  
  598. rtimer() {
  599.     tcount = time(0);
  600. }
  601.  
  602.  
  603. /*  G T I M E R --  Get current value of elapsed time counter in seconds  */
  604.  
  605. gtimer() {
  606.     return( time( (long *) 0 ) - tcount );
  607. }
  608.  
  609.  
  610. /*  Z T I M E  --  Return date/time string  */
  611.  
  612. ztime(s) char **s; {
  613.     struct dsc$descriptor_s t;
  614.     static char time_string[24];
  615.     t.dsc$w_length  = sizeof time_string - 1;  /*  Leave room for null  */
  616.     t.dsc$a_pointer = time_string;
  617.     t.dsc$b_class   = DSC$K_CLASS_S;
  618.     t.dsc$b_dtype   = DSC$K_DTYPE_T;
  619.     if (!CHECK_ERR("ztime: SYS$ASCTIM",
  620.     SYS$ASCTIM(0, &t, 0, 0))) return(-1);
  621.     time_string[t.dsc$w_length] = '\0';
  622.     *s = time_string;
  623. }
  624.  
  625.  
  626. /*  C O N G M  --  Get console terminal modes.  */
  627.  
  628. /*
  629.  Saves current console mode, and establishes variables for switching between 
  630.  current (presumably normal) mode and other modes.
  631. */
  632.  
  633. congm() {
  634.     struct { short len, code; char *buf, *retlen; } itmlst[2];
  635.     int devclass, context;
  636.     struct dsc$descriptor_s f, r;
  637.     char buf[100], *strchr();
  638.  
  639.     r.dsc$w_length  = sizeof buf;
  640.     r.dsc$b_dtype   = DSC$K_DTYPE_T;
  641.     r.dsc$b_class   = DSC$K_CLASS_S;
  642.     r.dsc$a_pointer = buf;
  643.     f.dsc$w_length  = 10;
  644.     f.dsc$b_dtype   = DSC$K_DTYPE_T;
  645.     f.dsc$b_class   = DSC$K_CLASS_S;
  646.     f.dsc$a_pointer = "SYS$INPUT:";
  647.     context = 0;
  648.     lib$find_file(&f, &r, &context);
  649.     r.dsc$w_length = strchr(buf, ' ') - buf;
  650.     itmlst[0].len    = 4;
  651.     itmlst[0].code   = DVI$_DEVCLASS;
  652.     itmlst[0].buf    = &devclass;
  653.     itmlst[0].retlen = 0;
  654.     itmlst[1].len    = 0;
  655.     itmlst[1].code   = 0;
  656.     if (!CHECK_ERR("congm: SYS$GETDVI",
  657.     SYS$GETDVI(0, 0, &r, itmlst, 0, 0, 0, 0))) return(-1);
  658.     SYS$WAITFR(0);
  659.     debug(F101, "congm: devclass", "", devclass);
  660.     if (devclass != DC$_TERM)
  661.     batch = 1;
  662.     else {
  663.     if (conchn == 0 && (conchn = vms_assign_channel("SYS$INPUT:")) == 0)
  664.         return(-1);
  665.         debug(F101, "congm: conchn", "", conchn);
  666.         if (!CHECK_ERR("congm: SYS$QIOW",
  667.         SYS$QIOW(0, conchn, IO$_SENSEMODE, 0, 0, 0,
  668.                  &ccold, sizeof ccold, 0, 0, 0, 0))) return(-1);
  669.         ccraw = cccbrk = ccold;
  670.     }
  671.     cgmf = 1;                /* Flag that we got them. */
  672.     return(0);
  673. }
  674.  
  675.  
  676. /*  C O N C B --  Put console in cbreak mode.  */
  677.  
  678. /*  Returns 0 if ok, -1 if not  */
  679.  
  680. concb(esc) char esc; {
  681.     int x;
  682.     if (cgmf == 0) congm();        /* Get modes if necessary. */
  683.     if (batch) return(0);
  684.     escchr = esc;            /* Make this available to other fns */
  685.     ckxech = 1;                /* Program can echo characters */
  686. #ifdef TT2$M_PASTHRU
  687.     cccbrk.extended |= TT2$M_PASTHRU;
  688. #else
  689. #ifdef TT2$M_ALTYPEAHD
  690.     cccbrk.extended |= TT2$M_ALTYPEAHD;
  691. #endif
  692.     cccbrk.basic |= TT$M_PASSALL;
  693. #endif
  694.     cccbrk.basic |= TT$M_NOECHO | TT$M_EIGHTBIT;
  695.     cccbrk.basic &= ~TT$M_WRAP & ~TT$M_HOSTSYNC & ~TT$M_TTSYNC;
  696.     if (!CHECK_ERR("concb: SYS$QIOW",
  697.     SYS$QIOW(0, conchn, IO$_SETMODE, 0, 0, 0,
  698.                  &cccbrk, sizeof cccbrk, 0, 0, 0, 0))) return(-1);
  699.     return(0);
  700. }
  701.  
  702.  
  703. /*  C O N B I N  --  Put console in binary mode  */
  704.  
  705.  
  706. /*  Returns 0 if ok, -1 if not  */
  707.  
  708. conbin(esc) char esc; {
  709.     if (cgmf == 0) congm();        /* Get modes if necessary. */
  710.     if (batch) return(0);
  711.     escchr = esc;            /* Make this available to other fns */
  712.     ckxech = 1;                /* Program can echo characters */
  713. #ifdef TT2$M_PASTHRU
  714.     ccraw.extended |= TT2$M_PASTHRU;
  715. #else
  716. #ifdef TT2$M_ALTYPEAHD
  717.     ccraw.extended |= TT2$M_ALTYPEAHD;
  718. #endif
  719.     ccraw.basic |= TT$M_PASSALL;
  720. #endif
  721.     ccraw.basic |= TT$M_NOECHO | TT$M_EIGHTBIT;
  722.     ccraw.basic &= ~TT$M_WRAP & ~TT$M_HOSTSYNC & ~TT$M_TTSYNC;
  723.     if (!CHECK_ERR("conbin: SYS$QIOW",
  724.     SYS$QIOW(0, conchn, IO$_SETMODE, 0, 0, 0,
  725.                  &ccraw, sizeof ccraw, 0, 0, 0, 0))) return(-1);
  726.     return(0);
  727. }
  728.  
  729.  
  730. /*  C O N R E S  --  Restore the console terminal  */
  731.  
  732. conres() {
  733.     if (cgmf == 0) return(0);        /* Don't do anything if modes */
  734.     if (batch) return(0);
  735.     sleep(1);                /*  not known! */
  736.     ckxech = 0;                /* System should echo chars */
  737.     if (!CHECK_ERR("conres: SYS$QIOW",
  738.     SYS$QIOW(0, conchn, IO$_SETMODE, 0, 0, 0,
  739.     &ccold, sizeof ccold, 0, 0, 0, 0))) return(-1);
  740.     return(0);
  741. }
  742.  
  743.  
  744. /*  C O N O C  --  Output a character to the console terminal  */
  745.  
  746. conoc(c) char c; {
  747.     if (batch) putchar(c);
  748.     else
  749.     CHECK_ERR("conoc: SYS$QIOW",
  750.         SYS$QIOW(0, conchn, IO$_WRITEVBLK, 0, 0, 0, &c, 1, 0, 0, 0, 0));
  751. }
  752.  
  753. /*  C O N X O  --  Write x characters to the console terminal  */
  754.  
  755. conxo(x,s) char *s; int x; {
  756.     if (batch) fprintf(stdout, "%.*s", x, s);
  757.     else CHECK_ERR("conxo: SYS$QIOW",
  758.     SYS$QIOW(0, conchn, IO$_WRITEVBLK, 0, 0, 0, s, x, 0, 0, 0, 0));
  759. }
  760.  
  761. /*  C O N O L  --  Write a line to the console terminal  */
  762.  
  763. conol(s) char *s; {
  764.     int len;
  765.     if (batch) fputs(s, stdout);
  766.     else {
  767.     len = strlen(s);
  768.     CHECK_ERR("conol: SYS$QIOW",
  769.         SYS$QIOW(0, conchn, IO$_WRITEVBLK, 0, 0, 0,
  770.              s, len, 0, 0, 0, 0));
  771.     }
  772. }
  773.  
  774. /*  C O N O L A  --  Write an array of lines to console, with CRLFs added */
  775.  
  776. conola(s) char *s[]; {
  777.     int i;
  778.     char t[100], *cp;
  779.     for (i=0 ; *s[i] ; i++) {
  780.     strncpy(t,s[i],100);
  781.     for (cp = t + strlen(t); --cp >= t;) {
  782.         if (*cp != '\n' && *cp != '\r') {
  783.         cp++;
  784.         *cp++ = '\r'; *cp++ = '\n'; *cp++ = '\0';
  785.         break;
  786.         }
  787.     }
  788.     conol(t);
  789.     }  
  790. }
  791.  
  792. /*  C O N O L L  --  Output a string followed by CRLF  */
  793.  
  794. conoll(s) char *s; {
  795.     conol(s);
  796.     conol("\r\n");
  797. }
  798.  
  799.  
  800. /*  C O N C H K  --  Check if characters available at console  */
  801.  
  802. conchk() {
  803.     struct { short count;  char first;  char reserved1;  long reserved2; } t;
  804.     if (batch) return(0);
  805.     return(CHECK_ERR("conchk: SYS$QIOW",
  806.     SYS$QIOW(0, conchn, IO$_SENSEMODE|IO$M_TYPEAHDCNT, 0, 0, 0,
  807.     &t, sizeof t, 0, 0, 0, 0)) ? t.count : 0);
  808. }
  809.  
  810.  
  811. /*  C O N I N C  --  Get a character from the console  */
  812.  
  813. coninc(timo) int timo; {
  814.     int n = 0; char ch;
  815.     int func, mask;
  816.     if (batch) return(getchar());
  817.     mask = 1 << CON_EFN;
  818.     if (con_queued) {
  819.     if (timo > 0) {
  820.         struct { int hi, lo; } qtime;
  821.         qtime.hi = -10*1000*1000*timo;  /* Max about seven minutes */
  822.         qtime.lo = -1;
  823.         SYS$SETIMR(TIM_EFN, &qtime, 0, 0);
  824.         mask |= TIM_EFN;
  825.     }
  826.     SYS$WFLOR(CON_EFN, mask);
  827.     SYS$READEF(CON_EFN, &mask);
  828.     if (mask & (1 << CON_EFN)) {
  829.         ch = conch & 0377;
  830.         CHECK_ERR("coninc: coniosb.status", coniosb.status);
  831.         con_queued = 0;
  832.     } else {
  833.         ch = -1;
  834.         vms_status = SS$_TIMEOUT;
  835.     }
  836.     } else {
  837.     func = IO$_READVBLK;
  838.     if (timo > 0) func |= IO$M_TIMED;
  839.     CHECK_ERR("coninc: SYS$QIOW",
  840.         SYS$QIOW(0, conchn, func, 0, 0, 0, &ch, 1, timo, 0, 0, 0));
  841.     ch &= 0377;
  842.     }
  843.     if (ch == '\r') ch = '\n';
  844.     if ((vms_status & 7) == 1) return(ch);
  845.     else return(-1);
  846. }
  847.  
  848. /*  V M S _ G E T C H A R -- get a character from the console (no echo).
  849.  *    Since we use raw reads, we must check for ctrl/c, ctrl/y and
  850.  *    ctrl/z ourselves.  We probably should post a "mailbox" for
  851.  *    ctrl/c and ctrl/y so the poor user can abort a runaway Kermit.
  852.  *    Note: this routine intends for ctrl/z (eof) to be "permanent".
  853.  *    Currently, no kermit routine calls "clearerror".  If this
  854.  *    changes, the following code must be rewritten.
  855.  */
  856.  
  857. int
  858. vms_getchar()
  859. {
  860.     register int    ch;
  861.     static int    ateof = FALSE;
  862.  
  863.     if (ateof)
  864.         return (EOF);
  865.     ch = coninc(0);
  866.     switch (ch) {
  867.     case ('Y' & 0x1F):
  868.     case ('C' & 0x1F):
  869.         ttclos();            /* Close down other terminal    */
  870.         conres();            /* And cleanup console modes    */
  871.         exit(SS$_ABORT);        /* Fatal exit.            */
  872.  
  873.     case ('Z' & 0x1F):
  874.         ateof = TRUE;
  875.         return (EOF);
  876.  
  877.     default:
  878.         return (ch);
  879.     }
  880. }
  881.  
  882.  
  883. /*  C O N T T I  --  Get character from console or tty, whichever comes  */
  884. /*    first.  This is used in conect() when NO_FORK is defined.  */
  885. /*    src is returned with 1 if the character came from the comm. line, */
  886. /*    0 if it was from the console, and with -1 if there was any error.  */
  887.  
  888. contti(c, src)  int *c, *src;  {
  889.     int mask = 1<<CON_EFN | 1<<TTY_EFN;
  890.  
  891.     *src = -1;
  892.     if (batch) {
  893.     if ((*c = getchar()) != EOF) {
  894.         *src = 0;
  895.     } else {
  896.         *src = 1;
  897.         *c = ttinc(0);
  898.     }
  899.     } else {
  900.         if (!con_queued)
  901.             if (!CHECK_ERR("contti: console SYS$QIO",
  902.             SYS$QIO(CON_EFN, conchn, IO$_READVBLK, &coniosb, 0, 0,
  903.                     &conch, 1, 0, 0, 0, 0))) return(-1);
  904.         con_queued = 1;
  905.         if (!tt_queued)
  906.             if (!CHECK_ERR("contti: tty SYS$QIO",
  907.             SYS$QIO(TTY_EFN, ttychn, IO$_READVBLK, &ttiosb, 0, 0,
  908.                     &ttch, 1, 0, 0, 0, 0))) return(-1);
  909.         tt_queued = 1;
  910.         if (!CHECK_ERR("contti: SYS$WFLOR",
  911.             SYS$WFLOR(CON_EFN, mask))) return(-1);
  912.         if (!CHECK_ERR("contti: SYS$READEF",
  913.             SYS$READEF(CON_EFN, &mask))) return(-1);
  914.         if (*src = (mask & (1<<TTY_EFN)) != 0) {
  915.             *c = ttch;
  916.             CHECK_ERR("contti: ttiosb.status", ttiosb.status);
  917.             tt_queued = 0;
  918.         } else {
  919.             *c = conch;
  920.             CHECK_ERR("contti: coniosb.status", coniosb.status);
  921.             con_queued = 0;
  922.         }
  923.         if ((vms_status & 7) != 1) *src = -1;
  924.     }
  925.     return(0);
  926. }
  927.  
  928. /*  C A N C I O  --  Cancel any pending i/o requests on the console or the
  929.         comm. line.
  930. */
  931.  
  932. cancio()  {
  933.     if (!batch) {
  934.         CHECK_ERR("cancio: console SYS$CANCEL",
  935.             SYS$CANCEL(conchn));
  936.         con_queued = 0;
  937.         CHECK_ERR("cancio: tty SYS$CANCEL",
  938.             SYS$CANCEL(ttychn));
  939.         tt_queued = 0;
  940.     }
  941. }
  942.