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

  1. /* DEC/CMS REPLACEMENT HISTORY, Element CKVTIO.C */
  2. /* *6    29-AUG-1989 00:32:11 BUDA "Fix exquota problem" */
  3. /* *5     1-MAY-1989 23:05:45 BUDA "Add debugging code/general cleanup" */
  4. /* *4    24-APR-1989 22:54:08 BUDA "Work on parity" */
  5. /* *3    16-APR-1989 17:57:47 BUDA "" */
  6. /* *2    12-APR-1989 00:58:59 BUDA "Add some of the new support" */
  7. /*  1U1  12-APR-1989 00:31:27 BUDA "Lots of neat stuff added" */
  8. /* *1    12-APR-1989 00:30:04 BUDA "Initial Creation" */
  9. /* DEC/CMS REPLACEMENT HISTORY, Element CKVTIO.C */
  10. char *ckxv = "TTY I/O, 1.0(021), 08 Jul 89";
  11.  
  12. /*  C K V T I O  --  Terminal and Interrupt Functions for VAX/VMS  */
  13.  
  14. /* Edit History
  15.  * 021 08-Jul-89 mab    Add ^C/^Y abort server mode code.
  16.  * 020 13-Jun-89 mab    Fix on exquota problem on qiow(readvblk)
  17.  * 019 25-Apr-89 mab    Change baud to 110 for V4.x break routine as
  18.  *             50 baud is nto supported on most MUX's by VMS.
  19.  * 018 23-Apr-89 mab    Add some of Valerie Mates parity changes.
  20.  * 017 04-Apr-89 mab    Fix some minor bugs to lcl/remote code
  21.  * 016 23-Mar-89 mab    Add IO$M_BREAKTHRU to IO$_WRITEVBLK.
  22.  *            Add zchkspd() function to check for valid speed.
  23.  * 015 26 Feb 89 mab    Add dcl exit handler and minor cleanup
  24.  * 014 14 Feb 89 mab    Make break REALLY work.  Add IOSB's to all QIO's.
  25.  * 013 14 Sep 87 FdC    Add parity strip to ttinl(), add syscleanup().
  26.  * 012 11 Jul 85 FdC    Add gtimer(), rtimer() for timing statistics.
  27.  * 011  5 Jul 85 DS     Treat hangup of closed line as success.
  28.  * 010 25 Jun 85 MM     Added sysinit() to open console.
  29.  * 009 18 Jun 85 FdC    Move def of CTTNAM to ckcdeb.h so it can be shared.
  30.  * 008 11 Jun 85 MM     Fix definition of CTTNAM
  31.  *
  32.  * 007 16-May-85 FdC    Changed calling convention of ttopen(), make it
  33.  *                      set value of its argument "lcl", to tell whether
  34.  *                        C-Kermit is in local or remote mode.
  35.  *
  36.  * 006  8-May-85 MM    Got rid of "typeahead buffer" code as it didn't
  37.  *            solve the problem of data overruns at 4800 Baud.
  38.  *            Added vms "read a char" routine that checks for
  39.  *            CTRL/C, CTRL/Z, etc.
  40.  */
  41.  
  42. /* C-Kermit interrupt, terminal control & i/o functions for VMS systems */
  43.  
  44. /*  S. Rubenstein, Harvard University Chemical Labs  */
  45. /*  (c) 1985 President and Fellows of Harvard College  */
  46.  
  47. char *ckxsys = " VAX/VMS";
  48.  
  49.  
  50.  
  51. /*
  52.  Variables available to outside world:
  53.  
  54.    dftty  -- Pointer to default tty name string, like "/dev/tty".
  55.    dfloc  -- 0 if dftty is console(remote), 1 if external line(local).
  56.    dfprty -- Default parity
  57.    dfflow -- Default flow control
  58.    ckxech -- Flag for who echoes console typein:
  59.      1 - The program (system echo is turned off)
  60.      0 - The system (or front end, or terminal).
  61.    functions that want to do their own echoing should check this flag
  62.    before doing so.
  63.  
  64.    backgrd -- Flag indicating program executing in background ( & on 
  65.         end of shell command). Used to ignore INT and QUIT signals.
  66.    vms_status -- status returned by most recent system service
  67.         which may be used for error reporting.
  68.  
  69.  Functions for assigned communication line (either external or console tty):
  70.  
  71.    ttopen(ttname,local,mdmtyp) -- Open the named tty for exclusive access.
  72.    ttclos()                -- Close & reset the tty, releasing any access lock.
  73.    ttpkt(speed,flow)       -- Put the tty in packet mode and set the speed.
  74.    ttvt(speed,flow)        -- Put the tty in virtual terminal mode.
  75.                 or in DIALING or CONNECTED modem control state.
  76.    ttinl(dest,max,timo)    -- Timed read line from the tty.
  77.    ttinc(timo)             -- Timed read character from tty.
  78.    ttchk()                 -- See how many characters in tty input buffer.
  79.    ttxin(n,buf)            -- Read n characters from tty (untimed).
  80.    ttol(string,length)     -- Write a string to the tty.
  81.    ttoc(c)                 -- Write a character to the tty.
  82.    ttflui()                -- Flush tty input buffer.
  83.    tt_cancel()           -- Cancel any asynch I/O to tty
  84. */
  85.  
  86.  
  87.  
  88. /*
  89. Functions for console terminal:
  90.    congm()   -- Get console terminal modes.
  91.    concb(esc) -- Put the console in single-character wakeup mode with no echo.
  92.    conbin(esc) -- Put the console in binary (raw) mode.
  93.    conres()  -- Restore the console to mode obtained by congm().
  94.    conoc(c)  -- Unbuffered output, one character to console.
  95.    conol(s)  -- Unbuffered output, null-terminated string to the console.
  96.    conola(s) -- Unbuffered output, array of lines to the console, CRLFs added.
  97.    conxo(n,s) -- Unbuffered output, n characters to the console.
  98.    conchk()  -- Check if characters available at console (bsd 4.2).
  99.         Check if escape char (^\) typed at console (System III/V).
  100.    coninc(timo)  -- Timed get a character from the console.
  101.    conint()  -- Enable terminal interrupts on the console if not background.
  102.    connoi()  -- Disable terminal interrupts on the console if not background.
  103.    contti()  -- Get a character from either console or tty, whichever is first.
  104.  
  105. Time functions
  106.  
  107.    msleep(m) -- Millisecond sleep
  108.    ztime(&s) -- Return pointer to date/time string
  109.    rtimer()  -- Reset elapsed time counter
  110.    gtimer()  -- Get elapsed time
  111. */
  112.  
  113.  
  114.  
  115. /* Includes */
  116. #include "ckcker.h"
  117. #include "ckvvms.h"
  118. #include <stdio.h>            /* Unix Standard i/o */
  119. #include <signal.h>            /* Interrupts */
  120. #include <setjmp.h>            /* Longjumps */
  121. #include <iodef.h>
  122. #include <ttdef.h>
  123. #include <tt2def.h>
  124. #include <ssdef.h>
  125. #include <descrip.h>
  126. #include <dvidef.h>
  127. #include <dcdef.h>
  128. #include <devdef.h>
  129. #include "ckcdeb.h"            /* Formats for debug() */
  130.  
  131.  
  132.  
  133. /* Declarations */
  134.  
  135.     long time();            /* Get current time in secs */
  136.     void dcl_exit_h(unsigned long int *); /* Exit handler */
  137.     unsigned long int vms_assign_channel(char *);
  138.  
  139. /* dftty is the device name of the default device for file transfer */
  140. /* dfloc is 1 if dftty is the user's console terminal, 0 if an external line */
  141.  
  142.     char *dftty = CTTNAM;
  143.     int dfloc = 0;            /* Default location is local */
  144.     int dfprty = 0;            /* Parity (0 = none) */
  145.     int ttprty = 0;            /* Parity in use */
  146.     int ttmdm = 0;                      /* Modem in use. */
  147.     int dfflow = 1;            /* Xon/Xoff flow control */
  148.     int batch = 0;            /* Assume interactive */
  149.  
  150. int ckxech = 0; /* 0 if system normally echoes console characters, else 1 */
  151.  
  152. unsigned int vms_status;        /* Used for system service return status */
  153.  
  154. /* Structures used within this module */
  155.  
  156.  
  157. static struct {
  158.     unsigned char dec;
  159.     unsigned short int line;
  160.     } ttspeeds[] = {
  161.     {TT$C_BAUD_50,       50},
  162.     {TT$C_BAUD_75,       75},
  163.     {TT$C_BAUD_110,     110},
  164.     {TT$C_BAUD_134,     134},
  165.         {TT$C_BAUD_150,     150},
  166.     {TT$C_BAUD_300,     300},
  167.     {TT$C_BAUD_600,     600},
  168.     {TT$C_BAUD_1200,   1200}, 
  169.     {TT$C_BAUD_1800,   1800}, 
  170.     {TT$C_BAUD_2000,   2000},
  171.     {TT$C_BAUD_2400,   2400},
  172.     {TT$C_BAUD_3600,   3600}, 
  173.     {TT$C_BAUD_4800,   4800},
  174.     {TT$C_BAUD_7200,   7200},
  175.     {TT$C_BAUD_9600,   9600}, 
  176.     {TT$C_BAUD_19200, 19200},
  177.     {TT$C_BAUD_38400, 38400},
  178.     {0,                   0} };
  179.  
  180.  
  181. /* Declarations of variables global within this module */
  182.  
  183. static long tcount;            /* For timing statistics */
  184.  
  185. static char *brnuls = "\0\0\0\0\0\0\0"; /* A string of nulls */
  186.  
  187. static int conif = 0,            /* Console interrupts on/off flag */
  188.     conclass = 0,            /* Console device type */
  189.     cgmf = 0,                /* Flag that console modes saved */
  190.     xlocal = 0,                         /* Flag for tty local or remote */
  191.     ttychn = 0,                /* TTY i/o channe; */
  192.     conchn = 0,                /* Console i/o channel */
  193.     con_queued = 0,            /* console i/o queued in contti() */
  194.     tt_queued = 0,            /* tty i/o queued in contti() */
  195.     conch,                /* console input character buffer  */
  196.     ttch;                /* tty input character buffer */
  197. static unsigned char escchr;        /* Escape or attn character */
  198. static char ttnmsv[65];              /* copy of open path for tthang */
  199. static char lclnam[65];            /* Local device name */
  200.  
  201. static long int qio_maxbuf_size;    /* Maximum size of QIO to succeed */
  202. static unsigned long dclexh_status;    /* Exit status for DCL exit handler */
  203. static struct iosb_struct coniosb, ttiosb, wrk_iosb;
  204. static struct tt_mode
  205.     ttold, ttraw, tttvt,        /* for communication line */
  206.     ccold, ccraw, cccbrk,        /* and for console */
  207.     cctmp;
  208.  
  209. #if 0
  210. /* These aren't used */
  211. static int inbufc = 0;            /* stuff for efficient raw line */
  212. static int ungotn = -1;            /* pushback to unread character */
  213. #endif
  214.  
  215.  
  216.  
  217. /*  P R I N T _ M S G  --  Log an error message from VMS  */
  218.  
  219. print_msg(s) char *s; {
  220.     long int blen = 0;
  221.     char buf[PMSG_BUF_SIZE], msg[PMSG_MSG_SIZE];
  222.     struct dsc$descriptor_s b = {PMSG_BUF_SIZE-1,DSC$K_DTYPE_T,DSC$K_CLASS_S,&buf};
  223.  
  224.     if (!((vms_status = SYS$GETMSG(vms_status, &blen, &b, 0, 0)) & 1)) {
  225.     fprintf(stderr,"print_msg; SYS$GETMSG\n");
  226.     return(-1);
  227.     }
  228.  
  229.     buf[blen] = '\0';
  230.     sprintf(msg, "%s: %s\n", s, buf);
  231.     ermsg(msg);
  232. }
  233.  
  234.  
  235. /*  S Y S I N I T  --  System-dependent program initialization.  */
  236.  
  237. sysinit() {
  238. extern int speed;
  239. extern char ttname[];
  240. struct itmlst dviitm[] = {{64,DVI$_FULLDEVNAM,&lclnam,0},
  241.             {sizeof(conclass),DVI$_DEVCLASS,&conclass,0},
  242.             {0,0,0,0}};
  243.  
  244. static struct desblk {
  245.     long int *fl;        /* Forward link.  Used by VMS only */
  246.     void (*fncpnt)();        /* Function to call */
  247.     unsigned char argcnt;    /* Only one arg allowed */
  248.     unsigned char filler[3];    /* Filler.  Must be zero */
  249.     long int *sts;        /* Address of sts (written by VMS) */
  250.     } dclexh_ = {0,dcl_exit_h,1,{0,0,0},&dclexh_status};
  251.  
  252. /*
  253.  * Set up DCL Exit handler.  This allows us to reset terminal
  254.  * and any other modifications we have done.
  255.  */
  256.     if (!CHECK_ERR("sysinit: SYS$DCLEXH",
  257.     SYS$DCLEXH(&dclexh_))) return(0);
  258.  
  259.     if (ttychn)                         /* if comms line already opened */
  260.           return(0);
  261.     
  262.     if (!conchn)
  263.        conchn = vms_assign_channel(dftty);
  264. /*
  265.  * Parse console terminal device name.
  266.  */
  267.     CHECK_ERR("sysinit: SYS$GETDVIW",
  268.     SYS$GETDVIW(0, conchn, 0, &dviitm, &wrk_iosb, 0, 0, 0));
  269.     debug(F111,"sysinit","lclnam",lclnam);
  270.  
  271.     if (!CHECK_ERR("congm: SYS$QIOW",
  272.         SYS$QIOW(QIOW_EFN, conchn, IO$_SENSEMODE, &wrk_iosb, 0, 0,
  273.                  &ccold, sizeof(ccold), 0, 0, 0, 0))) return(-1);
  274.  
  275.     speed = ttispd((unsigned char) wrk_iosb.size);
  276.     debug(F111,"sysinit speed",lclnam,speed);
  277.     strncpy(ttname,lclnam,DEVNAMLEN);        /* Max because of ckcmai */
  278.  
  279.     return(0);
  280. }
  281.  
  282. /*
  283.  * DCL Exit handler.  This is the cleanup handler for program.
  284.  * Any final cleanup (closing channels etc) should be done at this
  285.  * point.
  286.  */
  287. void dcl_exit_h(unsigned long int *sts)
  288. {
  289.     syscleanup();
  290.     return;
  291. }
  292.  
  293.  
  294. /*  S Y S C L E A NU P -- System-dependent program epilog.  */
  295.  
  296. syscleanup() {
  297.     extern zclosf();
  298.  
  299.     ttclos();            /* Do the cleanup no matter what... */
  300.     conres();            /* for the console also... */
  301.     zclosf();            /* Close various files and kill child proc */
  302.     printf("\r");
  303.     return(0);
  304. }
  305.  
  306.  
  307.  
  308.  
  309. /*  T T O P E N  --  Open a tty for exclusive access.  */
  310.  
  311. /*  Returns 0 on success, -1 on failure.  */
  312. /*
  313.   If called with lcl < 0, sets value of lcl as follows:
  314.   0: the terminal named by ttname is the job's controlling terminal.
  315.   1: the terminal named by ttname is not the job's controlling terminal.
  316.   But watch out: if a line is already open, or if requested line can't
  317.   be opened, then lcl remains (and is returned as) -1.
  318. */
  319.  
  320. ttopen(ttname,lcl,modem) char *ttname; int *lcl, modem; {
  321.     extern int speed;
  322.     int s;
  323.     unsigned long int devchar, devclass, devsts;
  324.     char dvibuf[65];
  325.     struct dsc$descriptor_s devnam = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
  326.     struct itmlst dviitm[] = {{64,DVI$_FULLDEVNAM,&dvibuf,0},
  327.             {sizeof(devchar),DVI$_DEVCHAR,&devchar,0},
  328.             {sizeof(devclass),DVI$_DEVCLASS,&devclass,0},
  329.             {sizeof(devsts),DVI$_STS,&devsts,0},
  330.             {0,0,0,0}};
  331.  
  332.     devnam.dsc$w_length  = strlen(ttname);
  333.     devnam.dsc$a_pointer = ttname;
  334.     CHECK_ERR("ttopen: SYS$GETDVIW",
  335.     SYS$GETDVIW(0, 0, &devnam, &dviitm, &wrk_iosb, 0, 0, 0));
  336.  
  337.     if ((devclass != DC$_TERM) ||
  338.         !(devchar & DEV$M_AVL) ||
  339.     !(devsts & UCB$M_ONLINE)) {
  340.     fprintf(stderr,"%%CKERMIT-W-NOTTERM, Device '%s' is not a terminal\n",dvibuf);
  341.     return(-1);
  342.     }
  343.     dvibuf[65] = '\0';
  344.     if (ttychn) return(0);        /* Close channel if open */
  345.  
  346.     ttmdm = modem;            /* Make this available to other fns */
  347.     xlocal = *lcl;            /* Make this available to other fns */
  348. /*
  349.  * The following is 'kludgy', but it is the only way to make this work
  350.  * without modifying CKUUS3.  I copy the returned device name into
  351.  * the command line!  If another parameter were to follow this one (which
  352.  * it does not at this time), it would be overwritten, possibly.
  353.  */
  354.  
  355.     strncpy(ttname,dvibuf,50);
  356.  
  357.     ttychn = vms_assign_channel(ttname);
  358.  
  359.     debug(F111,"ttopen","modem",modem);
  360.     debug(F101," ttychn","",ttychn);
  361.  
  362.     if (!ttychn) return(-1);        /* If couldn't open, fail. */
  363.  
  364. /*
  365.  * Check for maximum size of QIO, so as to not get the dreaded exceeded quota
  366.  * status returned.  When doing a QIO that has a larger buffer than
  367.  * MAXBUF, exceeded quota wil be returned.  There is also another limit, lower
  368.  * than MAXBUF, as to when extra features are used in the QIO, that more
  369.  * space can be used.
  370.  * 
  371.  * Example: MAXBUF = 2048, QIO = 1936, overhead is 112 will succeed.
  372.  *        QIO of 1937 will fail.
  373.  *
  374.  * This can change for different versions of VMS.
  375.  */
  376.  
  377.     qio_maxbuf_size = get_qio_maxbuf_size(ttychn);
  378.  
  379.     strcpy(ttnmsv,ttname);        /* Open, keep copy of name locally. */
  380.  
  381. /* Caller wants us to figure out if line is controlling tty */
  382.  
  383.     debug(F111,"ttopen ok",ttname,*lcl);
  384.     if (*lcl < 0) {
  385.     if (conclass == DC$_TERM)
  386.         xlocal = (strncmp(ttname,lclnam,DEVNAMLEN) == 0) ? 0 : 1;
  387.     else
  388.         xlocal = 1;            /* If not a term, then we must be local*/
  389. /*
  390.  * xlocal = 1 = local
  391.  *          0 = remote
  392.  */
  393.     debug(F111,"ttyname",lclnam,xlocal);
  394.     }
  395.  
  396.     if (!CHECK_ERR("ttopen: SYS$QIOW",
  397.     SYS$QIOW(QIOW_EFN, ttychn, IO$_SENSEMODE, &wrk_iosb, 0, 0,
  398.          &ttold, sizeof(ttold), 0, 0, 0, 0))) return(-1);
  399.  
  400.     speed = ttispd((unsigned char) wrk_iosb.size);
  401.  
  402. /* Got the line, now set the desired value for local. */
  403.  
  404.     if (*lcl) *lcl = xlocal;
  405.  
  406.     tttvt = ttold;
  407.     ttraw = ttold;
  408.     debug(F101," lcl","",*lcl);
  409.     return(0);
  410. }
  411.  
  412.  
  413. unsigned long int vms_assign_channel(ttname) char *ttname;  {
  414.     unsigned int channel = 0;
  415.     struct dsc$descriptor_s d = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
  416.  
  417.     d.dsc$w_length  = strlen(ttname);
  418.     d.dsc$a_pointer = ttname;
  419.     if (!CHECK_ERR("vms_assign_channel: SYS$ASSIGN",
  420.     SYS$ASSIGN(&d, &channel, 0, 0))) return(0);
  421.     return(channel);
  422. }
  423.  
  424.  
  425.  
  426. /*  T T C L O S  --  Close the TTY, releasing any lock.  */
  427.  
  428. ttclos() {
  429.     if (!ttychn) return(0);        /* Wasn't open. */
  430.  
  431.     ttres();                /* Reset modes. */
  432.     if (!CHECK_ERR("ttclos: SYS$DASSGN",
  433.     SYS$DASSGN(ttychn))) return(-1);
  434.     ttychn = 0;                /* Mark it as closed. */
  435.     return(0);
  436. }
  437.  
  438.  
  439. /*  T T R E S  --  Restore terminal to "normal" mode.  */
  440.  
  441. ttres() {                /* Restore the tty to normal. */
  442.     if (!ttychn) return(-1);        /* Not open. */
  443.  
  444.     tt_cancel();            /* Cancel outstanding I/O */
  445.     msleep(250);            /* Wait for pending i/o to finish. */
  446.     debug(F101,"ttres, ttychn","",ttychn);
  447.     if (!CHECK_ERR("ttres: SYS$QIOW",
  448.     SYS$QIOW(QIOW_EFN, ttychn, IO$_SETMODE, &wrk_iosb, 0, 0,
  449.              &ttold, sizeof(ttold), 0, 0, 0, 0))) return(-1);
  450.     return(0);
  451. }
  452.  
  453.  
  454.  
  455. /*  T T P K T  --  Condition the communication line for packets. */
  456. /*        or for modem dialing */
  457.  
  458. #define DIALING    4        /* flags (via flow) for modem handling */
  459. #define CONNECT 5
  460.  
  461. /*  If called with speed > -1, also set the speed.  */
  462.  
  463. /*  Returns 0 on success, -1 on failure.  */
  464.  
  465. ttpkt(speed,flow,parity) int speed, flow, parity; {
  466.     extern char ttname[];
  467.     int s;
  468.  
  469.     if (!ttychn) return(-1);        /* Not open. */
  470.     ttprty = parity;
  471.     debug(F101,"ttpkt setting ttprty","",ttprty);
  472.  
  473.     if ((s = ttsspd(speed)) < 0) s = 0;
  474.     if (flow == 1) ttraw.basic |=  (TT$M_HOSTSYNC|TT$M_TTSYNC);
  475.     if (flow == 0) ttraw.basic &= ~(TT$M_HOSTSYNC|TT$M_TTSYNC);
  476. #ifdef TT2$M_PASTHRU
  477.     ttraw.extended |= TT2$M_PASTHRU;
  478. #else
  479.     ttraw.basic |= TT$M_PASSALL;
  480. #endif
  481. #ifdef TT2$M_ALTYPEAHD
  482.     ttraw.extended |= TT2$M_ALTYPEAHD;
  483. #endif
  484.     ttraw.basic |= TT$M_NOECHO | TT$M_EIGHTBIT;
  485.     ttraw.basic &= ~TT$M_WRAP;
  486.     if (!CHECK_ERR("ttpkt: SYS$QIOW",
  487.     SYS$QIOW(QIOW_EFN, ttychn, IO$_SETMODE, &wrk_iosb, 0, 0,
  488.                  &ttraw, sizeof(ttraw), s, 0, 0, 0))) return(-1);
  489.     ttflui();                /* Flush any pending input */
  490.     return(0);
  491. }
  492.  
  493.  
  494.  
  495. /*  T T V T -- Condition communication line for use as virtual terminal  */
  496.  
  497. ttvt(speed,flow) int speed, flow; {
  498.     extern char ttname[];
  499.     int s;
  500.  
  501.     if (!ttychn) return(-1);        /* Not open. */
  502.  
  503.     if ((s = ttsspd(speed)) < 0) s = 0;
  504.  
  505.     if (flow == 1) ttraw.basic |=  (TT$M_HOSTSYNC|TT$M_TTSYNC);
  506.     if (flow == 0) ttraw.basic &= ~(TT$M_HOSTSYNC|TT$M_TTSYNC);
  507. #ifdef TT2$M_PASTHRU
  508.     ttraw.extended |= TT2$M_PASTHRU;
  509. #else
  510.     ttraw.basic |= TT$M_PASSALL;
  511. #endif
  512. #ifdef TT2$M_ALTYPEAHD
  513.     ttraw.extended |= TT2$M_ALTYPEAHD;
  514. #endif
  515.     ttraw.basic |= TT$M_NOECHO | TT$M_EIGHTBIT;
  516.     ttraw.basic &= ~TT$M_WRAP;
  517.     if (!CHECK_ERR("ttvt: SYS$QIOW",
  518.     SYS$QIOW(QIOW_EFN, ttychn, IO$_SETMODE, &wrk_iosb, 0, 0,
  519.               &ttraw, sizeof(ttraw), s, 0, 0, 0))) return(-1);
  520.     return(0);
  521. }
  522.  
  523.  
  524. /* T T I S P D  -- Return binary baud rate for internal coded speed */
  525.  
  526. int
  527. ttispd(ispeed) unsigned char ispeed; {
  528.     int s;
  529.  
  530. /* When the line is set, grab the line speed  and save it */
  531.  
  532.     for (s = 0;  ttspeeds[s].dec && 
  533.     (ttspeeds[s].dec != ispeed);  s++)
  534.         ;
  535.  
  536. /* If speed is zero, then no match.  Set speed to -1 so it is undefined */
  537.  
  538.     return(ttspeeds[s].line ? (int) ttspeeds[s].line : -1);
  539.  
  540. }
  541.  
  542.  
  543. /*  T T S S P D  --  Return the internal baud rate code for 'speed'.  */
  544.  
  545. int
  546. ttsspd(speed) int speed; {
  547.     int s;
  548.     char msg[50];
  549.  
  550.     if (speed < 0)            /* 006 Unknown speed fails    */
  551.     return (-1);
  552.     for (s = 0;  ttspeeds[s].line && (ttspeeds[s].line != speed);  s++) ;
  553.     if (ttspeeds[s].line)
  554.     return(ttspeeds[s].dec);
  555.     else {
  556.     sprintf(msg,"Unsupported line speed - %d\n",speed);
  557.     ermsg(msg);
  558.     ermsg("Current speed not changed\n");
  559.     return(-1);
  560.     }
  561. }
  562.  
  563. /*  T T F L U I  --  Flush tty input buffer */
  564.  
  565. ttflui() {
  566.  
  567.     long n;
  568.  
  569.     if (!ttychn) return(-1);        /* Not open. */
  570.  
  571.     if (!CHECK_ERR("ttflui: SYS$QIOW",
  572.     SYS$QIOW(QIOW_EFN, ttychn, IO$_READVBLK|IO$M_TIMED|IO$M_PURGE,
  573.          &wrk_iosb, 0, 0, &n, 0, 0, 0, 0, 0))) perror("flush failed");
  574.  
  575. #if 0
  576.     /* Note: unused */
  577.     inbufc = 0;
  578.     ungotn = -1;
  579. #endif
  580.     return(0);
  581. }
  582.  
  583.  
  584.  
  585. /* Interrupt Functions */
  586.  
  587.  
  588. /*  C O N I N T  --  Console Interrupt setter  */
  589.  
  590. conint(f) int (*f)(); {            /* Set an interrupt trap. */
  591.  
  592.     if (batch) return;        /* must ignore signals in bkgrd */
  593.  
  594.     if (conif) return;            /* Nothing to do if already on. */
  595.  
  596. /* check if invoked in background -- if so signals set to be ignored */
  597.  
  598.     if (signal(SIGINT,SIG_IGN) == SIG_IGN) {
  599.     batch = 1;            /*   means running in background */
  600.     return;
  601.     }
  602.     signal(SIGINT,f);            /* Function to trap to. */
  603.     conif = 1;                /* Flag console interrupts on. */
  604. }
  605.  
  606.  
  607. /*  C O N N O I  --  Reset console terminal interrupts */
  608.  
  609. connoi() {                /* Console-no-interrupts */
  610.  
  611.     if (batch) return;            /* must ignore signals in bkgrd */
  612.  
  613.     signal(SIGINT,SIG_DFL);
  614.     conif = 0;
  615. }
  616.  
  617.  
  618.  
  619. /*  T T C H K  --  Tell how many characters are waiting in tty input buffer  */
  620.  
  621. ttchk() {
  622.     static struct {
  623.     unsigned short count; 
  624.     unsigned char first; 
  625.     unsigned char reserved1; 
  626.     long reserved2; } ttchk_struct;
  627.  
  628.     /* inbufc + (ungotn >= 0) +        -- 006 Note: unused    */
  629.     CHECK_ERR("ttchk: SYS$QIOW",
  630.     SYS$QIOW(QIOW_EFN, ttychn, IO$_SENSEMODE|IO$M_TYPEAHDCNT, &wrk_iosb, 0, 0,
  631.       &ttchk_struct, sizeof(ttchk_struct), 0, 0, 0, 0));
  632.     debug(F101,"ttchk","",(int)ttchk_struct.count);
  633.     return(vms_status & 1 ? ttchk_struct.count : 0);
  634. }
  635.  
  636.  
  637. /*  T T X I N  --  Get n characters from tty input buffer  */
  638.  
  639. ttxin(n,buf) int n; char *buf; {
  640.     int i;
  641.     unsigned char *cp;
  642.     static int trmmsk[2] = {0,0};
  643.  
  644.     if (!CHECK_ERR("ttxin: SYS$QIOW",
  645.     SYS$QIOW(QIOW_EFN, ttychn, IO$_READVBLK, &wrk_iosb, 0, 0,
  646.               buf, n, 0, &trmmsk, 0, 0))
  647.     || !CHECK_ERR("ttxin: wrk_iosb.status",wrk_iosb.status)) return(-1);
  648.     if (ttprty)
  649.     for (i = wrk_iosb.size, cp = buf; (i) ;i--)
  650.         *cp++ &= 0177;
  651.     buf[n] = '\0';
  652.     return(wrk_iosb.size);
  653. }
  654.  
  655.  
  656.  
  657. /*  T T O L  --  Similar to "ttinl", but for writing.  */
  658. /*
  659.  * This probably should be buffered with a flush command added.
  660.  */
  661.  
  662. ttol(s,n) int n; char *s; {
  663.     int x;
  664.  
  665.     if (!ttychn) return(-1);        /* Not open. */
  666.     if (CHECK_ERR("ttol: SYS$QIOW",
  667.     SYS$QIOW(QIOW_EFN, ttychn, IO$_WRITEVBLK|IO$M_BREAKTHRU, &wrk_iosb, 0, 0,
  668.         s, n, 0, 0, 0, 0))) x = 0;
  669.     else x = -1;
  670.     debug(F111,"ttol",s,n);
  671.     if (x < 0) debug(F101,"ttol failed","",x);
  672.     return(x);
  673. }
  674.  
  675.  
  676. /*  T T O C  --  Output a character to the communication line  */
  677.  
  678. ttoc(c) char c; {
  679.     if (!ttychn) return(-1);        /* Not open. */
  680.  
  681.     if (CHECK_ERR("ttoc: SYS$QIOW",
  682.     SYS$QIOW(QIOW_EFN, ttychn, IO$_WRITEVBLK|IO$M_BREAKTHRU, &wrk_iosb, 0, 0,
  683.         &c, 1, 0, 0, 0, 0))) return(0);
  684.     return(-1);
  685. }
  686.  
  687.  
  688.  
  689. /*  T T I N L  --  Read a record (up to break character) from comm line.  */
  690. /*
  691.   If no break character encountered within "max", return "max" characters,
  692.   with disposition of any remaining characters undefined.  Otherwise, return
  693.   the characters that were read, including the break character, in "dest" and
  694.   the number of characters read as the value of function, or 0 upon end of
  695.   file, or -1 if an error occurred or, -2 if two ^C's were typed.  Times
  696.   out & returns error if not completed within "timo" seconds.
  697. */
  698.  
  699. ttinl(dest,max,timo,eol) int max,timo; char *dest, eol; {
  700.     int x, y, c, i;
  701.     static int trmmsk[2] = {0,0};
  702.     static int trmlong[8] = {0,0,0,0,0,0,0,0};
  703.     int ccnt = 0;        /* Control C counter */
  704.     int func;
  705.     unsigned char *cp;
  706.  
  707.     if (!ttychn) return(-1);        /* Not open. */
  708.  
  709.     if (ttprty) {
  710.     trmmsk[0] = sizeof(trmlong);
  711.     trmmsk[1] = &trmlong;
  712.     trmlong[0] = (1 << eol) | CKV_M_CTRLC | CKV_M_CTRLY;
  713.     trmlong[4] = (1 << eol) | CKV_M_CTRLC | CKV_M_CTRLY;
  714.     } else {
  715.     trmmsk[0] = 0;
  716.     trmmsk[1] = (1 << eol) | CKV_M_CTRLC | CKV_M_CTRLY;
  717.     }
  718.  
  719.     func = IO$_READVBLK;
  720.     if (timo > 0) func |= IO$M_TIMED;
  721.  
  722. /*
  723.  * Limit size of QIO so we do not get exquota error.
  724.  */
  725.     if (max > qio_maxbuf_size) max = qio_maxbuf_size;
  726.  
  727.     do {
  728.     vms_status = SYS$QIOW(QIOW_EFN, ttychn, func, &wrk_iosb, 0, 0,
  729.               dest, max, timo, &trmmsk, 0, 0);
  730.  
  731. /*
  732.  * Did any type of error occur on submission of QIO or execution of QIO?
  733.  */
  734.     if ((!(vms_status & 1)) ||
  735.         (!(wrk_iosb.status & 1))) {
  736. /*
  737.  * If we got a time out, then fine, return with a failure, but no messages
  738.  */
  739.         if (wrk_iosb.status == SS$_TIMEOUT)
  740.         return(-1);
  741. /*
  742.  * If the submission of QIO was fine, but the execution failed
  743.  * then save the status so when the error is printed out, we know
  744.  */
  745.     
  746.         if (!(vms_status & 1))
  747.         print_msg("ttinl: SYS$QIOW");
  748.         if (!(wrk_iosb.status & 1)) {
  749.         vms_status = wrk_iosb.status;
  750.         print_msg("ttinl: SYS$QIOW(iosb)");
  751.         }
  752.         return(-1);
  753.     }
  754. /*
  755.  * Check for a control C being typed
  756.  */
  757.     if ((((unsigned char) wrk_iosb.terminator & 0177) == CKV_K_CTRLC) ||
  758.          (((unsigned char) wrk_iosb.terminator & 0177) == CKV_K_CTRLY)) {
  759.         if (++ccnt > 1) {
  760.         fprintf(stderr,"^C...");
  761.         ttres();
  762.         fprintf(stderr,"\n");
  763.         return(-2);
  764.         }
  765.         }
  766.     else
  767.         ccnt = 0;
  768.     } while (ccnt);
  769.  
  770.     if (ttprty)
  771.     for (i=wrk_iosb.size, cp=dest; (i); i--) {
  772.         *cp++ &= 0177;
  773.         }
  774.     return(wrk_iosb.size);
  775. }
  776.  
  777.  
  778.  
  779. /*  T T I N C --  Read a character from the communication line  */
  780.  
  781. ttinc(timo) int timo; {
  782.     unsigned char ch[1];
  783.     static int trmmsk[2] = {0,0};
  784.     int func;
  785.  
  786.     if (!ttychn) return(-1);        /* Not open. */
  787.     func = IO$_READVBLK;
  788.     if (timo > 0) func |= IO$M_TIMED;
  789.     if (!CHECK_ERR("ttinc: SYS$QIOW",
  790.     SYS$QIOW(QIOW_EFN, ttychn, func, &wrk_iosb, 0, 0,
  791.               &ch, 1, timo, &trmmsk, 0, 0))
  792.     || wrk_iosb.status == SS$_TIMEOUT    /* Check separately so no err msg */
  793.     || !CHECK_ERR("ttinc: wrk_iosb.status",wrk_iosb.status)) return(-1);
  794.     return(ttprty ? ch[0] & 0177 : ch[0]);
  795. }
  796.  
  797.  
  798.  
  799. /*  T T _ C A N C E L  --  Cancel i/o on tty channel if not complete  */
  800.  
  801. tt_cancel() {
  802.     int mask;
  803.  
  804.     CHECK_ERR("tt_cancel: SYS$CANCEL",SYS$CANCEL(ttychn));
  805.     tt_queued = 0;
  806. }
  807.  
  808. /*  C O N _ C A N C E L  --  Cancel i/o on console channel if not complete  */
  809.  
  810. con_cancel() {
  811.     int mask;
  812.  
  813.     CHECK_ERR("con_cancel: SYS$CANCEL",SYS$CANCEL(conchn));
  814.     con_queued = 0;
  815. }
  816.  
  817. /*  T T S N D B  --  Send a BREAK signal  */
  818.  
  819. ttsndb() {
  820.     int long x = 0;
  821.     struct iosb_struct  tmp_ttiosb;
  822.     struct tt_mode ttchr;
  823.  
  824.     if (!ttychn) return(-1);        /* Not open. */
  825.  
  826.     tt_cancel();
  827. #ifndef TT$M_BREAK
  828.     if (!CHECK_ERR("ttsndb: SENSEMODE",
  829.     SYS$QIOW(QIOW_EFN, ttychn, IO$_SENSEMODE, &wrk_iosb, 0, 0,
  830.         &ttchr, sizeof(ttchr), 0, 0, 0, 0))) return(-1);
  831.     if (!CHECK_ERR("ttsndb: SETMODE(1)",
  832.     SYS$QIOW(QIOW_EFN, ttychn, IO$_SETMODE, &tmp_ttiosb, 0, 0,
  833.         &ttchr, sizeof(ttchr), TT$C_BAUD_110, 0, 0, 0))) return(-1);
  834.     if (!CHECK_ERR("ttsndb: writing nulls",
  835.     SYS$QIOW(QIOW_EFN, ttychn, IO$_WRITEVBLK|IO$M_BREAKTHRU, &tmp_ttiosb, 0, 0,
  836.         brnuls, 6, 0, 0, 0, 0))) return(-1);
  837.     if (!CHECK_ERR("ttsndb: SETMODE(2)",
  838.     SYS$QIOW(QIOW_EFN, ttychn, IO$_SETMODE, &tmp_ttiosb, 0, 0,
  839.         &ttchr, sizeof(ttchr), wrk_iosb.size, 0, 0, 0))) return(-1);
  840. #else
  841.     if (!CHECK_ERR("ttsndb: SENSEMODE",
  842.     SYS$QIOW(QIOW_EFN, ttychn, IO$_SENSEMODE, &wrk_iosb, 0, 0,
  843.         &ttchr, sizeof(ttchr), 0, 0, 0, 0))) return(-1);
  844.  
  845. /* Break signal on */
  846.     x = TT$M_BREAK;    
  847.     if (!CHECK_ERR("ttsndb: SETMODE(1)",
  848.     SYS$QIOW(QIOW_EFN, ttychn, IO$_SETMODE, &wrk_iosb, 0, 0,
  849.         &ttchr, sizeof(ttchr), 0, 0, x, 0))) return(-1);
  850.     msleep(275);
  851.  
  852. /* Break signal off */
  853.     x = 0;
  854.     if (!CHECK_ERR("ttsndb: SETMODE(2)",
  855.     SYS$QIOW(QIOW_EFN, ttychn, IO$_SETMODE, &wrk_iosb, 0, 0,
  856.         &ttchr, sizeof(ttchr), 0, 0, x, 0))) return(-1);
  857.  
  858. #endif
  859.     return(0);
  860. }
  861.  
  862.  
  863.  
  864. /*  T T H A N G  --  Hang up the communications line  */
  865.  
  866. tthang() {
  867.     if (!ttychn) return(0);            /* Not open. */
  868.  
  869.     tt_cancel();
  870.     if (!CHECK_ERR("tthang: SYS$QIOW",
  871.     SYS$QIOW(QIOW_EFN, ttychn, IO$_SETMODE|IO$M_HANGUP, &wrk_iosb, 0, 0,
  872.         0, 0, 0, 0, 0, 0))) return(-1);
  873.     return(0);
  874. }
  875.  
  876.  
  877.  
  878. /*  M S L E E P  --  Millisecond version of sleep().  */
  879.  
  880. /*
  881.  Handles intervals up to about 7 minutes (2**32 / 10**7 seconds)
  882. */
  883.  
  884. msleep(m) int m; {
  885.  
  886.     struct time_struct {
  887.     long int hi, lo;
  888.     } t;
  889.     if (m <= 0) return(0);
  890.     t.hi = -10000 * m;  /*  Time in 100-nanosecond units  */
  891.     t.lo = -1;
  892.     if (!CHECK_ERR("msleep: SYS$SCHDWK",
  893.     SYS$SCHDWK(0, 0, &t, 0))) return(-1);
  894.     SYS$HIBER();
  895.     return(0);
  896. }
  897.  
  898.  
  899. /*  R T I M E R --  Reset elapsed time counter  */
  900.  
  901. rtimer() {
  902.     tcount = time( (long *) 0);
  903. }
  904.  
  905.  
  906. /*  G T I M E R --  Get current value of elapsed time counter in seconds  */
  907.  
  908. gtimer() {
  909.     int x;
  910.     x = (int) (time( (long *) 0 ) - tcount);
  911.     rtimer();
  912.     return( (x < 0) ? 0 : x );
  913. }
  914.  
  915.  
  916. /*  Z T I M E  --  Return date/time string  */
  917.  
  918. ztime(s) char **s; {
  919.     static char time_string[24];
  920.     struct dsc$descriptor_s t =
  921.     {sizeof(time_string)-1,DSC$K_DTYPE_T,DSC$K_CLASS_S,&time_string};
  922.  
  923.     if (!CHECK_ERR("ztime: SYS$ASCTIM",
  924.     SYS$ASCTIM(0, &t, 0, 0))) return(-1);
  925.     time_string[t.dsc$w_length] = '\0';
  926.     *s = &time_string;
  927. }
  928.  
  929.  
  930.  
  931. /*  C O N G M  --  Get console terminal modes.  */
  932.  
  933. /*
  934.  Saves current console mode, and establishes variables for switching between 
  935.  current (presumably normal) mode and other modes.
  936. */
  937.  
  938. congm() {
  939.     char s[] = "SYS$INPUT:";
  940.     struct itmlst dviitm[] = { {4,DVI$_DEVCLASS,&dviitm[0].adr,0},
  941.             {0,0,0,0}};
  942.     struct dsc$descriptor_s
  943.     r = {sizeof(s),DSC$K_DTYPE_T,DSC$K_CLASS_S,&s};
  944.  
  945.     if (cgmf) return(-1);        /* If called already, then nop */
  946.  
  947.     if (!CHECK_ERR("congm: SYS$GETDVIW",
  948.     SYS$GETDVIW(0, 0, &r, &dviitm, &wrk_iosb, 0, 0, 0))) return(-1);
  949.     debug(F101, "congm: devclass", "", (unsigned long int) dviitm[0].adr);
  950.     if ((unsigned long int) dviitm[0].adr != DC$_TERM)
  951.     batch = 1;
  952.     else {
  953.     if (conchn == 0 && (conchn = vms_assign_channel("SYS$INPUT:")) == 0)
  954.         return(-1);
  955.         debug(F101, "congm: conchn", "", conchn);
  956.         if (!CHECK_ERR("congm: SYS$QIOW",
  957.         SYS$QIOW(QIOW_EFN, conchn, IO$_SENSEMODE, &wrk_iosb, 0, 0,
  958.                  &ccold, sizeof(ccold), 0, 0, 0, 0))) return(-1);
  959.         ccraw = cccbrk = ccold;
  960.     }
  961.     cgmf = 1;                /* Flag that we got them. */
  962.     return(0);
  963. }
  964.  
  965.  
  966. /*  C O N C B --  Put console in cbreak mode.  */
  967.  
  968. /*  Returns 0 if ok, -1 if not  */
  969.  
  970. concb(esc) char esc; {
  971.     int x;
  972.  
  973.     if (batch) return(0);
  974.     if (!cgmf) congm();            /* Get modes if necessary. */
  975.     escchr = esc;            /* Make this available to other fns */
  976.     ckxech = 1;                /* Program can echo characters */
  977. #ifdef TT2$M_PASTHRU
  978.     cccbrk.extended |= TT2$M_PASTHRU | TT2$M_DMA;
  979. #else
  980.     cccbrk.basic |= TT$M_PASSALL;
  981. #endif
  982. #ifdef TT2$M_ALTYPEAHD
  983.     cccbrk.extended |= TT2$M_ALTYPEAHD;
  984. #endif
  985.     cccbrk.basic |= TT$M_NOECHO | TT$M_EIGHTBIT;
  986.     cccbrk.basic &= ~(TT$M_WRAP);
  987. /*    cccbrk.basic &= ~(TT$M_WRAP | TT$M_HOSTSYNC | TT$M_TTSYNC); */
  988.     if (!CHECK_ERR("concb: SYS$QIOW",
  989.     SYS$QIOW(QIOW_EFN, conchn, IO$_SETMODE, &wrk_iosb, 0, 0,
  990.                  &cccbrk, sizeof(cccbrk), 0, 0, 0, 0))) return(-1);
  991.     return(0);
  992. }
  993.  
  994.  
  995.  
  996. /*  C O N B I N  --  Put console in binary mode  */
  997.  
  998.  
  999. /*  Returns 0 if ok, -1 if not  */
  1000.  
  1001. conbin(esc) char esc; {
  1002.     if (batch) return(0);
  1003.     if (!cgmf) congm();        /* Get modes if necessary. */
  1004.  
  1005.     debug(F100,"conbin","",0);
  1006.     escchr = esc;            /* Make this available to other fns */
  1007.     ckxech = 1;                /* Program can echo characters */
  1008. #ifdef TT2$M_PASTHRU
  1009.     ccraw.extended |= TT2$M_PASTHRU | TT2$M_DMA;
  1010. #else
  1011.     ccraw.basic |= TT$M_PASSALL;
  1012. #endif
  1013. #ifdef TT2$M_ALTYPEAHD
  1014.     ccraw.extended |= TT2$M_ALTYPEAHD;
  1015. #endif
  1016.     ccraw.basic |= TT$M_NOECHO | TT$M_EIGHTBIT;
  1017.     ccraw.basic &= ~(TT$M_WRAP | TT$M_HOSTSYNC | TT$M_TTSYNC);
  1018.     if (!CHECK_ERR("conbin: SYS$QIOW",
  1019.     SYS$QIOW(QIOW_EFN, conchn, IO$_SETMODE, &wrk_iosb, 0, 0,
  1020.                  &ccraw, sizeof(ccraw), 0, 0, 0, 0))) return(-1);
  1021.     return(0);
  1022. }
  1023.  
  1024.  
  1025. /*  C O N R E S  --  Restore the console terminal  */
  1026.  
  1027. conres() {
  1028.     debug(F100," conres","",0);
  1029.     if (!cgmf) return(0);        /* Don't do anything if modes */
  1030.     if (batch) return(0);
  1031.  
  1032. #ifdef mab
  1033.     msleep(250);            /*  not known! */
  1034. #endif
  1035.     ckxech = 0;                /* System should echo chars */
  1036.     if (!CHECK_ERR("conres: SYS$QIOW",
  1037.     SYS$QIOW(QIOW_EFN, conchn, IO$_SETMODE, &wrk_iosb, 0, 0,
  1038.     &ccold, sizeof(ccold), 0, 0, 0, 0))) return(-1);
  1039.     return(0);
  1040. }
  1041.  
  1042.  
  1043. /*  C O N R E S N E --  Restore the console terminal with No Echo */
  1044.  
  1045. conresne() {
  1046.     if (!cgmf) return(0);        /* Don't do anything if modes */
  1047.     if (batch) return(0);
  1048.  
  1049.     msleep(250);            /*  not known! */
  1050.     ckxech = 1;                /* Program should echo chars */
  1051.  
  1052.     cctmp = ccold;
  1053.     cctmp.basic |= TT$M_NOECHO;
  1054.     if (!CHECK_ERR("conres: SYS$QIOW",
  1055.     SYS$QIOW(QIOW_EFN, conchn, IO$_SETMODE, &wrk_iosb, 0, 0,
  1056.     &cctmp, sizeof(cctmp), 0, 0, 0, 0))) return(-1);
  1057.     return(0);
  1058. }
  1059.  
  1060.  
  1061.  
  1062.  
  1063. /*  C O N O C  --  Output a character to the console terminal  */
  1064.  
  1065. conoc(c) char c; {
  1066.     if (batch) putchar(c);
  1067.     else
  1068.     CHECK_ERR("conoc: SYS$QIOW",
  1069.         SYS$QIOW(QIOW_EFN, conchn, IO$_WRITEVBLK|IO$M_BREAKTHRU, &wrk_iosb, 0, 0, &c,
  1070.         1, 0, 0, 0, 0));
  1071. }
  1072.  
  1073. /*  C O N X O  --  Write x characters to the console terminal  */
  1074.  
  1075. conxo(x,s) char *s; int x; {
  1076.     if (batch) fprintf(stdout, "%.*s", x, s);
  1077.     else CHECK_ERR("conxo: SYS$QIOW",
  1078.     SYS$QIOW(QIOW_EFN, conchn, IO$_WRITEVBLK|IO$M_BREAKTHRU, &wrk_iosb, 0, 0, s, x, 0, 0, 0, 0));
  1079. }
  1080.  
  1081. /*  C O N O L  --  Write a line to the console terminal  */
  1082.  
  1083. conol(s) char *s; {
  1084.     int len;
  1085.  
  1086.     if (batch) fputs(s, stdout);
  1087.     else {
  1088.     len = strlen(s);
  1089.     CHECK_ERR("conol: SYS$QIOW",
  1090.         SYS$QIOW(QIOW_EFN, conchn, IO$_WRITEVBLK|IO$M_BREAKTHRU, &wrk_iosb, 0, 0,
  1091.              s, len, 0, 0, 0, 0));
  1092.     }
  1093. }
  1094.  
  1095. /*  C O N O L A  --  Write an array of lines to console, with CRLFs added */
  1096.  
  1097. conola(s) char *s[]; {
  1098.     int i;
  1099.     char t[100], *cp;
  1100.  
  1101.     for (i=0 ; *s[i] ; i++) {
  1102.     strncpy(t,s[i],100);
  1103.     for (cp = t + strlen(t); --cp >= t;) {
  1104.         if (*cp != '\n' && *cp != '\r') {
  1105.         cp++;
  1106.         *cp++ = '\r'; *cp++ = '\n'; *cp++ = '\0';
  1107.         break;
  1108.         }
  1109.     }
  1110.     conol(t);
  1111.     }  
  1112. }
  1113.  
  1114. /*  C O N O L L  --  Output a string followed by CRLF  */
  1115.  
  1116. conoll(s) char *s; {
  1117.     conol(s);
  1118.     conol("\r\n");
  1119. }
  1120.  
  1121.  
  1122. /*  C O N C H K  --  Check if characters available at console  */
  1123.  
  1124. conchk() {
  1125.     struct {
  1126.     unsigned short count; 
  1127.     unsigned char first; 
  1128.     unsigned char reserved1; 
  1129.     long reserved2;
  1130.     } t;
  1131.  
  1132.     if (batch) return(0);
  1133.     return(CHECK_ERR("conchk: SYS$QIOW",
  1134.     SYS$QIOW(QIOW_EFN, conchn, IO$_SENSEMODE|IO$M_TYPEAHDCNT, &wrk_iosb, 0, 0,
  1135.     &t, sizeof(t), 0, 0, 0, 0)) ? t.count : 0);
  1136. }
  1137.  
  1138.  
  1139.  
  1140. /*  C O N I N C  --  Get a character from the console  */
  1141.  
  1142. coninc(timo) int timo; {
  1143.     int n = 0;
  1144.     unsigned char ch;
  1145.     int func, mask;
  1146.  
  1147.     if (batch) return(getchar());
  1148.     mask = 1 << CON_EFN;
  1149.     if (con_queued) {
  1150.     if (timo > 0) {
  1151.         struct { int hi, lo; } qtime;
  1152.         qtime.hi = -10*1000*1000*timo;  /* Max about seven minutes */
  1153.         qtime.lo = -1;
  1154.         SYS$SETIMR(TIM_EFN, &qtime, 0, 0);
  1155.         mask |= TIM_EFN;
  1156.     }
  1157.     SYS$WFLOR(CON_EFN, mask);
  1158.     SYS$READEF(CON_EFN, &mask);
  1159.     if (mask & (1 << CON_EFN)) {
  1160.         ch = (unsigned char) conch;
  1161.         CHECK_ERR("coninc: coniosb.status", coniosb.status);
  1162.         con_queued = 0;
  1163.     } else {
  1164.         ch = -1;
  1165.         vms_status = SS$_TIMEOUT;
  1166.     }
  1167.     } else {
  1168.     func = IO$_READVBLK;
  1169.     if (timo > 0) func |= IO$M_TIMED;
  1170.     CHECK_ERR("coninc: SYS$QIOW",
  1171.         SYS$QIOW(QIOW_EFN, conchn, func, &wrk_iosb, 0, 0, &ch, 1, timo, 0, 0, 0));
  1172.     }
  1173.     if (ch == '\r') ch = '\n';
  1174.     if (vms_status & 1) return(ch);
  1175.     return(-1);
  1176. }
  1177.  
  1178.  
  1179. /*  V M S _ G E T C H A R -- get a character from the console (no echo).
  1180.  *    Since we use raw reads, we must check for ctrl/c, ctrl/y and
  1181.  *    ctrl/z ourselves.  We probably should post a "mailbox" for
  1182.  *    ctrl/c and ctrl/y so the poor user can abort a runaway Kermit.
  1183.  *    Note: this routine intends for ctrl/z (eof) to be "permanent".
  1184.  *    Currently, no kermit routine calls "clearerror".  If this
  1185.  *    changes, the following code must be rewritten.
  1186.  */
  1187.  
  1188. int
  1189. vms_getchar()
  1190. {
  1191.     register unsigned int    ch;
  1192.     static int    ateof = FALSE;
  1193.  
  1194.     if (ateof)
  1195.     return (EOF);
  1196.     ch = coninc(0);
  1197.     switch (ch) {
  1198.     case ('Y' - 64):
  1199.     case ('C' - 64):
  1200.         ttclos();            /* Close down other terminal    */
  1201.         conres();            /* And cleanup console modes    */
  1202.         exit(SS$_ABORT);        /* Fatal exit.            */
  1203.  
  1204.     case ('Z' - 64):
  1205.         ateof = TRUE;
  1206.         return (EOF);
  1207.  
  1208.     default:
  1209.         return (ch);
  1210.     }
  1211. }
  1212.  
  1213.  
  1214.  
  1215. /*  C O N T T I  --  Get character from console then from tty  */
  1216. /*    This is used in conect() when NO_FORK is defined.  */
  1217. /*    src is returned with 1 if the character came from the comm. line, */
  1218. /*    0 if it was from the console, and with -1 if there was any error.  */
  1219.  
  1220. contti(c, src)  int *c, *src;  {
  1221.     int mask = 1<<CON_EFN | 1<<TTY_EFN;
  1222.  
  1223.     *src = -1;
  1224.     if (batch) {
  1225.     if ((*c = getchar()) != EOF) {
  1226.         *src = 0;
  1227.     } else {
  1228.         *src = 1;
  1229.         *c = ttinc(0);
  1230.     }
  1231.     } else {                /* If interactive */
  1232.         if (!con_queued)
  1233.             if (!CHECK_ERR("contti: console SYS$QIO",
  1234.             SYS$QIO(CON_EFN, conchn, IO$_READVBLK, &coniosb, 0, 0,
  1235.                     &conch, 1, 0, 0, 0, 0))) return(-1);
  1236.         con_queued = 1;
  1237.         if (!tt_queued)
  1238.             if (!CHECK_ERR("contti: tty SYS$QIO",
  1239.             SYS$QIO(TTY_EFN, ttychn, IO$_READVBLK, &ttiosb, 0, 0,
  1240.                     &ttch, 1, 0, 0, 0, 0))) return(-1);
  1241.         tt_queued = 1;
  1242.         if (!CHECK_ERR("contti: SYS$WFLOR",
  1243.             SYS$WFLOR(CON_EFN, mask))) return(-1);
  1244.         if (!CHECK_ERR("contti: SYS$READEF",
  1245.             SYS$READEF(CON_EFN, &mask))) return(-1);        
  1246.         if (!(*src = ((mask & 1<<CON_EFN) ? 0 : 1))) {
  1247.             *c = conch;
  1248.             CHECK_ERR("contti: coniosb.status", coniosb.status);
  1249.             con_queued = 0;
  1250.         } else {
  1251.             *c = (ttprty ? ttch & 0177 : ttch);
  1252.             CHECK_ERR("contti: ttiosb.status", ttiosb.status);
  1253.             tt_queued = 0;
  1254.         }
  1255.         if (!(vms_status & 1)) *src = -1;
  1256.     }
  1257.     return(0);
  1258. }
  1259.  
  1260. /*  C A N C I O  --  Cancel any pending i/o requests on the console or the
  1261.         comm. line.
  1262. */
  1263.  
  1264. cancio()  {
  1265.     if (!batch) {
  1266.         CHECK_ERR("cancio: console SYS$CANCEL",
  1267.             SYS$CANCEL(conchn));
  1268.         CHECK_ERR("cancio: tty SYS$CANCEL",
  1269.             SYS$CANCEL(ttychn));
  1270.         con_queued = 0;
  1271.         tt_queued = 0;
  1272.     }
  1273. }
  1274.  
  1275. /* get_qio_maxbuf_size()
  1276.  *
  1277.  * Get maximum size of QIO that can occur without getting the dreaded
  1278.  * exceeded quota status.
  1279.  */
  1280.  
  1281. int get_qio_maxbuf_size(ttychn)
  1282. unsigned long int ttychn;
  1283. {
  1284.     int long max=2048;
  1285.     char tmpbuf[2049];
  1286.  
  1287.     if (!ttychn) return(-1);
  1288.  
  1289.     for (; max > 0; max -= 16) {
  1290.     if (!test_qio(ttychn,max,&tmpbuf)) return(max);
  1291.     }
  1292.  
  1293.     printf("\n%%CKERMIT-F-get_qio_maxbuf_size, Could not get maxbuf size\n");
  1294.     exit(SS$_ABORT);        /* Fatal exit */
  1295.  
  1296. }
  1297.  
  1298. int test_qio(ttychn,max,dest)
  1299. unsigned long int ttychn;
  1300. long int max;
  1301. unsigned char *dest;
  1302. {
  1303.     static int trmmsk[2] = {0,0};
  1304.  
  1305. /*    trmmsk[1] = 1 << eol; */
  1306.  
  1307.     vms_status = SYS$QIOW(QIOW_EFN, ttychn, IO$_READVBLK|IO$M_TIMED, &wrk_iosb, 0, 0,
  1308.               dest, max, 0, &trmmsk, 0, 0);
  1309.     return( !(vms_status & 1) ||
  1310.     (!(wrk_iosb.status & 1)) && wrk_iosb.status != SS$_TIMEOUT);
  1311. }
  1312.