home *** CD-ROM | disk | FTP | other *** search
/ vsiftp.vmssoftware.com / VSIPUBLIC@vsiftp.vmssoftware.com.tar / FREEWARE / FREEWARE40.ZIP / flistfrontend / src / getraw.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-10-21  |  6.8 KB  |  328 lines

  1. #ifndef NO_IDENT
  2. static char *Id = "$Id: getraw.c,v 1.9 1995/10/21 18:55:13 tom Exp $";
  3. #endif
  4.  
  5. /*
  6.  * Title:    getraw.c
  7.  * Author:    T.E.Dickey
  8.  * Created:    03 May 1984
  9.  * Last update:
  10.  *        18 Feb 1995, removed syi-testing.
  11.  *        24 Feb 1989, when reading from a command-file, suppress lines
  12.  *                 which do not begin with '$' (with optional blanks)
  13.  *        17 Aug 1988, use SYS$COMMAND instead of SYS$INPUT.
  14.  *        10 Jun 1985, ensure type-ahead is killed if CTRL/X
  15.  *        08 Jun 1985, added code for interactive type-ahead
  16.  *        10 Apr 1985, made command-files nest, some better error checks.
  17.  *        06 Apr 1985, added file-input, CTRL/X-ast
  18.  *        29 Mar 1985, added 'status' to 'error'.
  19.  *        24 Feb 1985, removed ^C^C.
  20.  *        02 Dec 1984, added entry 'gotraw' to do QIO (no wait)
  21.  *        09 Jul 1984, use virtual-block instead on TTY_READALL
  22.  *        04 Jul 1984, make debug more readable
  23.  *        27 Jun 1984, do debug-print to look for lockup
  24.  *        22 Jun 1984, test status from 'iosb'
  25.  *        20 Jun 1984, added timeout test
  26.  *        18 Jun 1984, do 'fflush' to attempt fix for spurious lockups
  27.  *        31 May 1984, double ^C causes walkback-exit
  28.  *        10 May 1984, provide passall mode if no echo
  29.  *        07 May 1984, to make echo optional, other arguments.
  30.  *
  31.  * Function:    Obtain a single character from the terminal without echo.
  32.  *
  33.  * References:    VAX/VMS I/O User's Guide
  34.  *        (1-16 to 1-19) - sys$qiow
  35.  *        (2-3) - Discussion of escapes vs read-terminator
  36.  */
  37.  
  38. #include    <stdlib.h>
  39. #include    <ctype.h>
  40. #include    <string.h>
  41.  
  42. #include    <starlet.h>
  43. #include    <lib$routines.h>
  44. #include    <descrip.h>
  45. #include    <iodef.h>
  46. #include    <ssdef.h>
  47. #include    <stsdef.h>
  48.  
  49. #include    "bool.h"
  50. #include    "flist.h"
  51. #include    "getraw.h"
  52. #include    "rmsio.h"
  53. #include    "rmscc.h"
  54.  
  55. /*
  56.  * Local definitions:
  57.  */
  58. #define    OK(f)    $VMS_STATUS_SUCCESS(status=f)
  59. #define    SYS(f)    if (!OK(f)) lib$stop(status)
  60.  
  61. /* patch: Should I use 'lib$get_ef' ? */
  62. #define    ef2    2
  63.  
  64. #define    QA(efn,func,b,len,t)\
  65.     efn,        /* Event flag number        */\
  66.     tty_chan,\
  67.     func,\
  68.     &iosb,0,0,\
  69.     b,        /* buffer address        */\
  70.     len,        /* buffer size            */\
  71.     t,        /* timeout count        */\
  72.     0,        /* read terminator desc-blk addr */\
  73.     0,        /* prompt-string buffer address */\
  74.     0        /* prompt-string buffer size    */
  75.  
  76. typedef    struct    { short    sts, count; unsigned device; } IOSB;
  77.  
  78. #undef  CFP
  79. #define    CFP    struct _cmd_fp
  80.  
  81. CFP    {
  82.     CFP    *nest;        /* linked-list to nest    */
  83.     RFILE    *file;        /* File-pointer            */
  84.     char    *text;        /* => I/O buffer        */
  85.     unsigned mark;        /* = record-address        */
  86.     short    size;        /* I/O buffer size        */
  87.     short    rlen;        /* = length of current record    */
  88.     short    used;        /* number of chars used so far    */
  89.     short    iscc;        /* TRUE if format is carriage-control */
  90.     };
  91.  
  92. #define    CFP_TEXT(n)    cfp->text[cfp->n]
  93.  
  94. /*
  95.  * Local (static) data:
  96.  */
  97. $DESCRIPTOR(tty_name,"SYS$COMMAND");
  98.  
  99. static    CFP    *cfp    = nullS(CFP);    /* command-file-pointer    */
  100. static    unsigned
  101.     short    tty_chan = 0,
  102.         ast_chan = 0,
  103.         init    = FALSE;    /* Force auto-init */
  104. static    unsigned ctlx_flag = FALSE;
  105. static    char    typeahead;        /* input-buffer    */
  106.  
  107. static    void    getraw_free (void);
  108.  
  109. /*
  110.  * Provide a publicly-testable CTRL/X-flag, which is set only if the AST-routine
  111.  * is called:
  112.  */
  113. void
  114. ctlx_ast (void)
  115. {
  116.     unsigned status;
  117.  
  118.     SYS(sys$cancel(tty_chan));
  119.     ctlx_flag = TRUE;
  120.     typeahead = EOS;
  121. }
  122.  
  123. void
  124. ctlx_clr (void)
  125. {
  126.     ctlx_flag = FALSE;
  127. }
  128.  
  129. int
  130. ctlx_tst (void)
  131. {
  132.     return(ctlx_flag);
  133. }
  134.  
  135. /* <getraw_init>:
  136.  * The initialization routine for this module may be either called explicitly
  137.  * (to call in a new command file), or implicitly (when the module is first
  138.  * invoked).
  139.  *
  140.  * Arguments:
  141.  *    cmd_    => command-file name
  142.  *    dft_    => file-specification default
  143.  */
  144. void
  145. getraw_init (char *cmd_, char *dft_)
  146. {
  147.     int    bmask[2] = {0, 0x01000000};
  148.     unsigned status;
  149.  
  150.     /*
  151.      * If a command-file argument is provided, open the file for input.
  152.      * We will read from this file until we get an end-of-file.
  153.      */
  154.     if (cmd_)
  155.     {
  156.         if (*cmd_)
  157.         {
  158.         CFP    *old = cfp;
  159.             cfp = calloc(1, sizeof(CFP));
  160.             cfp->nest = old;
  161.             if (cfp->file = ropen2 (cmd_, dft_, "r"))
  162.             {
  163.                 cfp->size = 4 + rsize(cfp->file);
  164.                 cfp->text = calloc(1, cfp->size);
  165.                 cfp->iscc = rmscc(cfp->file) > 0;
  166.             }
  167.             else
  168.                 getraw_free ();
  169.         }
  170.     }
  171.  
  172.     if (! tty_chan)
  173.     {
  174.         SYS(sys$assign(&tty_name, &tty_chan, 0,0));
  175.     }
  176.  
  177.     if (! ast_chan)
  178.     {
  179.         SYS(sys$assign(&tty_name,&ast_chan,0,0));
  180.  
  181.         /* Establish CTRL/X AST routine */
  182.         SYS(sys$qiow(ef2,ast_chan,IO$_SETMODE | IO$M_OUTBAND,0,0,0,
  183.             &ctlx_ast,&bmask,0,0,0,0));
  184.     }
  185.     init = TRUE;
  186. }
  187.  
  188. /*
  189.  * Wait for, read one or more characters for commands:
  190.  */
  191. int
  192. getraw (void)
  193. {
  194.     int    gotc    = FALSE,
  195.         status;
  196.     char    newc;
  197.     IOSB    iosb;
  198.  
  199.     if (!init)    getraw_init(0,0);
  200.  
  201.     if (cfp)
  202.     {
  203.         if (cfp->used >= cfp->rlen)
  204.         {
  205. get_cmd:
  206.             if ((cfp->rlen = rgetr(cfp->file, cfp->text,
  207.                            cfp->size, &cfp->mark)) >= 0)
  208.             {
  209.                 strcpy (&CFP_TEXT(rlen++),
  210.                     cfp->iscc ? "\r" : "");
  211.                 cfp->used = 0;
  212.                 while (isspace(CFP_TEXT(used)))
  213.                     cfp->used++;
  214.                 if (CFP_TEXT(used++) != '$') goto get_cmd;
  215.                 while (    (CFP_TEXT(used) == ' ')
  216.                 ||    (CFP_TEXT(used) == '\t'))
  217.                     cfp->used++;
  218.             }
  219.             else
  220.                 getraw_free();
  221.         }
  222.         if (cfp)    /* Still here if no end-of-file    */
  223.         {
  224.             if (gotc = (cfp->used < cfp->rlen))
  225.                 newc = CFP_TEXT(used++);
  226.         }
  227.     }
  228.  
  229.     /*
  230.      * Use data from call on 'gotraw':
  231.      */
  232.     if (! gotc && typeahead)
  233.     {
  234.         gotc    = TRUE;
  235.         newc    = typeahead;
  236.     }
  237.  
  238.     /*
  239.      * If neither command-file, nor type-ahead, wait for input from the
  240.      * terminal:
  241.      */
  242.     while (! gotc)
  243.     {
  244.         if (ctlx_tst())
  245.         {
  246.             newc = CTL('X');
  247.             ctlx_clr();        /* Reset flag after use !! */
  248.             break;
  249.         }
  250.         if (! OK(sys$qiow (QA(0,
  251.             IO$_READVBLK | IO$M_NOFILTR | IO$M_NOECHO,
  252.             &typeahead,1,0))))
  253.             error (status, 0);
  254.  
  255.         gotc = (iosb.sts == SS$_NORMAL);
  256.         newc = typeahead;
  257.         /* CTRL/X yields SS$_ABORT */
  258.     }
  259.  
  260.     typeahead = EOS;
  261.     return (newc);
  262. }
  263.  
  264. /* <gotraw>:
  265.  * Return TRUE iff we have already another character in the input buffer,
  266.  * following the one which we have (just) read.  This test lets us optimize
  267.  * screen outputs by combining several refreshes together (e.g., postponing
  268.  * updates of an input line until we have a carriage-return).
  269.  */
  270. int
  271. gotraw (void)
  272. {
  273.     int    status;
  274.     IOSB    iosb;
  275.  
  276.     if (cfp)
  277.         return (cfp->used < cfp->rlen);
  278.     else if (! typeahead)
  279.     {
  280.         if (! OK(sys$qio (QA(ef2,
  281.             IO$M_TIMED | IO$_READVBLK | IO$M_NOFILTR | IO$M_NOECHO,
  282.             &typeahead,1,0))))
  283.             error (status, 0);
  284.  
  285.         sys$waitfr (ef2);
  286.         if (iosb.sts != SS$_NORMAL)    typeahead = EOS;
  287.     }
  288.     return (isprint(typeahead));
  289. }
  290.  
  291. /* <getraw_free>:
  292.  * Close the current command-file, returning buffer space.  If there is an
  293.  * error, print the message.
  294.  */
  295. static void
  296. getraw_free (void)
  297. {
  298.     char    msg[CRT_COLS];
  299.  
  300.     if (cfp)
  301.     {
  302.     CFP    *old = cfp->nest;
  303.         if (cfp->text)    cfree (cfp->text);
  304.         if (cfp->file)
  305.         {
  306.             if (erstat (cfp->file, msg, sizeof(msg)))
  307.                 warn (msg);
  308.             rclose (cfp->file);
  309.         }
  310.         else
  311.             rerror();    /* Show file-not-found message    */
  312.         cfree (cfp);
  313.         cfp = old;
  314.     }
  315.     rclear();    /* Reset I/O-error latch    */
  316. }
  317.  
  318. /*
  319.  * <getraw_flush>:
  320.  * Discard the remainder of the current command-file line.
  321.  */
  322. void
  323. getraw_flush(void)
  324. {
  325.     if (cfp)
  326.         cfp->used = cfp->rlen + 1;
  327. }
  328.