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

  1. #ifndef NO_IDENT
  2. static char *Id = "$Id: dircmd.c,v 1.15 1995/10/27 11:37:00 tom Exp $";
  3. #endif
  4.  
  5. /*
  6.  * Title:    dircmd.c
  7.  * Author:    T.E.Dickey
  8.  * Created:    10 May 1984
  9.  * Last update:
  10.  *        27 Oct 1995, added "create" command.
  11.  *        26 Oct 1995, mods for animated "Working..." message
  12.  *        24 Oct 1995, added commands to sort-by-username
  13.  *        27 May 1995, prototypes
  14.  *        04 Nov 1988- added "/dexpired" table entry, and matching sort
  15.  *        11 Jul 1988- fix side-effect of "<number> -" from dclarg fix.
  16.  *        01 Jul 1988- added LSEDIT command
  17.  *        12 Nov 1985, added '?owner' command.
  18.  *        05 Oct 1985, added '/width' command to permit 80/132-column
  19.  *                 switch on VT100's.  Also, permit additional
  20.  *                 keyword on HELP.
  21.  *        21 Sep 1985, merged all VCMD2-tables by handling '/', '?'
  22.  *                 prefixes in 'dirarg' module.  Added '/protection'
  23.  *                 as alias for PROTECT (SET PROTECTION) and '?daytime'
  24.  *                 as alias for ?DATE (SHOW [DAY]TIME).  Use 'debrief'
  25.  *                 to show possible commands user may mean if he forgets
  26.  *                 the unambiguous-abbreviation.
  27.  *        31 Jul 1985, added 'UPDATE' command.
  28.  *        25 Jul 1985, added '?READ' command.
  29.  *        20 Jul 1985, added DUMP command, for debugging structured heap.
  30.  *        05 Jul 1985, corrected release of memory in 'dircmd_doit'.
  31.  *        03 Jul 1985, cleanup of 'filelist' definition.  Use 'scanint'
  32.  *                 instead of 'sscanf' to bypass CC2.0 bug.
  33.  *        15 Jun 1985, reference '(func)' as '(*func)' to make CC2.0 happy
  34.  *        10 Jun 1985, added 'SHELL', '?FIND' commands
  35.  *        24 May 1985, corrected treatment of '?' (for '?HELP').  Added
  36.  *                 log-file for /MARK and other commands which imply
  37.  *                 operations on the current file.
  38.  *        19 May 1985, added '/CWIDTH' command.
  39.  *        18 May 1985, added '/' alone as a scroll-to-top command.
  40.  *        14 May 1985, thrashed for a while before finding a bug in the
  41.  *                 cmdstk module.  Leave debug-code inline for later
  42.  *                 use.
  43.  *        05 May 1985, completed 'keydefs' code.  (Must still merge the
  44.  *                 two vcmd-tables and check arguments).
  45.  *        01 May 1985, began 'keydefs' code, restructured command invokes
  46.  *                 to use a single (redefinable) table of key-defs,
  47.  *                 rather than the combination return-code to main-case
  48.  *                 with special keypad stuff, and then visible commands
  49.  *                 treated as the third case.
  50.  *        30 Apr 1985, broke 'dircmd_doit' from 'dircmd_read'.
  51.  *        27 Apr 1985, corrected repeated-command test (in 'edtcmd').
  52.  *        25 Apr 1985, re-use 'edtcmd' with BROWSE by adding delimiter-arg.
  53.  *        18 Apr 1985, chopped out 'edtcmd' code
  54.  *        13 Apr 1985, added call on 'flist_log'
  55.  *        11 Apr 1985, added call to 'gotraw' to make typeahead run faster.
  56.  *        30 Mar 1985, 'didbeep()' is a superset of 'didwarn' test.
  57.  *                 Added '?MEMORY'.
  58.  *        22 Mar 1985, added "/SIDENTIFIER", "/SLENGTH".
  59.  *        14 Mar 1985, renamed 'more' to 'browse'
  60.  *        05 Mar 1985, had stepped-on repeated-error latch.
  61.  *        23 Feb 1985, added magic-intercept for ^D
  62.  *        05 Jan 1985, added "NEXT" keyword.  Use 'read_dft' for FIND
  63.  *                 and NFIND defaults.
  64.  *        29 Dec 1984, added "/SBACKUP", "/SCREATED", "/SREVISED", and
  65.  *                 relative (e.g., "12-") numeric scrolling.  Show
  66.  *                 SELECT-state (via 'dds_line').
  67.  *                 Put BROWSE on key-9.
  68.  *        24 Dec 1984, added "/DSHORT", "/DLONG"
  69.  *        23 Dec 1984, added "/CLEFT", "/CRIGHT".
  70.  *        22 Dec 1984, added "NFIND", changed record-attributes to 'X'
  71.  *                 to provide for 'allocate', 'length'.  In command-
  72.  *                 edit, permit up/down arrows to traverse 'cmdstk'.
  73.  *        19 Dec 1984, use ^E as ==> (go to end of command), also moved
  74.  *                 'cmdstk' init calls to main program.
  75.  *        18 Dec 1984, treat ^Y as ^U if we ever see it.
  76.  *        15 Dec 1984, added 'cpy_dft' argument to 'dclarg'.
  77.  *        11 Dec 1984, added '?QUOTA', '/SFORMAT', '/SATTRIBUTE'.
  78.  *        17 Nov 1984, added 'INSPECT'
  79.  *        22 Oct 1984
  80.  *
  81.  * Function:    This module performs the actual command input for the "FLIST"
  82.  *        program.  Commands are of three types:
  83.  *
  84.  *        (a)    Set command-processor state (e.g., GOLD, FORWARD, and
  85.  *            BACKWARD keys).
  86.  *        (b)    Keypad commands, or
  87.  *        (c)    Visible commands, requiring multiple keystrokes.  All
  88.  *            visible-commands are terminated with ENTER/RETURN.
  89.  *            This mode of operation is assumed whenever the user
  90.  *            types a printing character (instead of an escape
  91.  *            sequence or control character).  Visible commands
  92.  *            which correspond to keypad commands are translated
  93.  *            and returned to the main program.  Those which do not
  94.  *            are executed under control of this module.
  95.  */
  96.  
  97. #define    DEBUG
  98. #include    <stdlib.h>
  99. #include    <stdio.h>
  100. #include    <ctype.h>
  101. #include    <string.h>
  102.  
  103. #include    <rms.h>
  104.  
  105. #include    "cmdstk.h"
  106. #include    "flist.h"
  107. #include    "getpad.h"
  108.  
  109. #include    "acpcopy.h"
  110. #include    "dclarg.h"
  111. #include    "dds.h"
  112. #include    "freelist.h"
  113. #include    "dircmd.h"
  114. #include    "edtcmd.h"
  115.  
  116. #include    "strutils.h"
  117.  
  118. static    void    dircmd_doit (int *curfile_, char *cmdbfr, int history);
  119. static    int    dircmd_getc (int *curfile_);
  120. static    void    dircmd_kcmd (int *curfile_, int command);
  121. static    void    dircmd_keydefs (int code, int flags, char *string);
  122. static    void    dircmd_read (int *curfile_, int command, char *original);
  123.  
  124. /*
  125.  * Special command-processing routines are called:
  126.  *    (tocall)(&curfile, xcmd_, xdcl_);
  127.  *
  128.  * where:
  129.  *    curfile - index in 'filelist[]' to current (working) file.  The address
  130.  *          is passed to support search/scrolling commands.
  131.  *    xcmd_    => lowercased-string, equal to substituted tokens & logicals.
  132.  *    xdcl_    => DCLARG-list (filespecs are uppercased).
  133.  */
  134.  
  135. import(filelist);
  136.  
  137. /*
  138.  * Local (static) data:
  139.  */
  140. #define    DO_NEXT    0        /* value if 'command' completed, do next*/
  141.  
  142. #define    RUBOUT    '\177'
  143.  
  144. /*
  145.  * 'dir_flg' is used locally to control the interpretation of the keypad keys
  146.  *    which control scrolling/searching.
  147.  * 'selected' is used in the 'dirsrt.c' module to determine the resulting
  148.  *    index into 'dirent[]' at which the cursor will be placed after a sort.
  149.  *    This variable supports the notion of a fixed-point sort.  (If negative,
  150.  *    it is inactive.)
  151.  * 'read_dft' is used as the default name-string for READ, EDIT (with multiple-
  152.  *    files), and is toggled by the FLIST option "VERSION, NOVERSION".
  153.  */
  154. int    multi_quit;            /* Nonzero if multi-quit    */
  155.  
  156. static    int    dir_flg    = TRUE;        /* TRUE if "forward"        */
  157. static    int    selected;        /* index to "selected" file    */
  158.  
  159. static    char    read_dft[]    = "*.*;*";
  160.  
  161. typedef    struct    {
  162.     unsigned char flags;        /* nonzero iff we must edit it    */
  163.     char    *string;
  164.     } KEYDEFS;
  165.  
  166. static    KEYDEFS    *keydefs    = 0;
  167.  
  168. /*
  169.  * Symbol table to relate "visible" commands to actual controls.  The
  170.  * actual-text may not be printing-ASCII, because this is trapped by the
  171.  * visible-command-detection loop.  Commands which are also control characters
  172.  * are mapped into these control characters.  (Those having no "actual" code
  173.  * are decoded on the basis of the "func" component, which always overrides.)
  174.  *
  175.  * patch: This table could be re-structured to be initialized in 'dircmd_init'
  176.  *    to accept a profile-file (a la FLIST), relating all visible-commands
  177.  *    to control keys or escape sequences.
  178.  */
  179. #define    OZ(flag)    (v_nonDCL | flag),0
  180. static
  181. VCMD2    vcmd2[]    = {
  182.     "show",        3, not_impl,    OZ(0),    /* "?"-prefix      */
  183.     "set",        3, not_impl,    OZ(0),    /* "/"-prefix      */
  184.                         /* Status+display */
  185.     "?help",    1, flshow,    OZ(v_ARGS),
  186.     "?columns",    2, flshow,    OZ(0),
  187.     "?date",    2, flshow,    OZ(0),
  188.     "?daytime",    2, flshow,    OZ(0),
  189.     "?find",    2, flshow,     OZ(0),
  190.     "?level",    2, flshow,    OZ(0),
  191.     "?memory",    2, flshow,    OZ(0),
  192.     "?owner",    2, flshow,    OZ(0),
  193.     "?quota",    2, flshow,    OZ(0),
  194.     "?read",    2, flshow,    OZ(0),
  195.     "?size",    2, flshow,    OZ(0),
  196.     "?times",    2, flshow,    OZ(0),
  197.     "?version",    2, flshow,    OZ(0),
  198.                         /* Help-display    */
  199.     "/help",    4, flshow,    OZ(v_ARGS),
  200.     "/hlp",        4, flshow,    OZ(v_ARGS),
  201.     "help",        1, flshow,    OZ(v_ARGS),
  202.                         /* Commands    */
  203.     "quit",     1, flquit,    OZ(v_ARGS),
  204.                         /* Trap messages*/
  205.     "/hold",    4, flset_hold,    OZ(0),
  206.     "/nohold",    4, flset_hold,    OZ(0),
  207.                         /* Selection    */
  208.     "/mark",    4, flset_mark,    OZ(v_NAME),
  209.     "/nomark",    4, flset_mark,    OZ(0),
  210.                         /* Scrolling    */
  211.     "/top",        4, flpage,    OZ(0),
  212.     "/end",     4, flpage,    OZ(0),
  213.     "/page",    2, flpage,    OZ(v_ARGS),
  214.     "/backward",    2, flpage,    OZ(v_ARGS),
  215.     "/home",    2, flpage,    OZ(0),
  216.     "/middle",    2, flpage,    OZ(0),
  217.     "/low",        2, flpage,    OZ(0),
  218.     "/forward",    2, flpage,    OZ(v_ARGS),
  219.                         /* Display form */
  220.     "/columns",    2, flcols,    OZ(v_ARGS),
  221.     "/cleft",    3, flcols_left,    OZ(0),
  222.     "/cright",    3, flcols_right,OZ(0),
  223.     "/cwidth",    3, flcols_width,OZ(v_ARGS),
  224.     "/times",    3, flshow,    OZ(0),
  225.     "/width",    2, flcols_132,    OZ(v_ARGS),
  226.                         /* Date-display    */
  227.     "/dcreated",    2, flset_date,    OZ(0),    /* (default) */
  228.     "/dbackup",    3, flset_date,    OZ(0),
  229.     "/drevised",    3, flset_date,    OZ(0),
  230.     "/dexpired",    3, flset_date,    OZ(0),
  231.     "/dshort",    3, flset_date,    OZ(0),
  232.     "/dlong",    3, flset_date,    OZ(0),
  233.                         /* Normal-sort    */
  234.     "/salloc",    3, flsort,    OZ(0),
  235.     "/sbackup",    3, flsort,    OZ(0),
  236.     "/screated",    3, flsort,    OZ(0),
  237.     "/sdate",    3, flsort,    OZ(0),
  238.     "/sexpired",    3, flsort,    OZ(0),
  239.     "/sformat",    3, flsort,    OZ(0),
  240.     "/shour",    3, flsort,    OZ(0),
  241.     "/sidentifier",    3, flsort,    OZ(0),
  242.     "/slength",    3, flsort,    OZ(0),
  243.     "/smask",    3, flsort,    OZ(0),
  244.     "/sname",    2, flsort,    OZ(0),    /* (default)    */
  245.     "/sowner",    3, flsort,    OZ(0),
  246.     "/spath",    3, flsort,    OZ(0),
  247.     "/srevised",    3, flsort,    OZ(0),
  248.     "/ssize",    3, flsort,    OZ(0),
  249.     "/stype",    3, flsort,    OZ(0),
  250.     "/suser",    3, flsort,    OZ(0),
  251.     "/svers",    3, flsort,    OZ(0),
  252.     "/sweek",    3, flsort,    OZ(0),
  253.     "/sxab",    3, flsort,    OZ(0),
  254.                         /* Reverse-sort    */
  255.     "/ralloc",    3, flsort,    OZ(0),
  256.     "/rbackup",    3, flsort,    OZ(0),
  257.     "/rcreated",    3, flsort,    OZ(0),
  258.     "/rdate",    3, flsort,    OZ(0),
  259.     "/rexpired",    3, flsort,    OZ(0),
  260.     "/rformat",    3, flsort,    OZ(0),
  261.     "/rhour",    3, flsort,    OZ(0),
  262.     "/ridentifier",    3, flsort,    OZ(0),
  263.     "/rlength",    3, flsort,    OZ(0),
  264.     "/rmask",    3, flsort,    OZ(0),
  265.     "/rname",    2, flsort,    OZ(0),    /* (default)    */
  266.     "/rowner",    3, flsort,    OZ(0),
  267.     "/rpath",    3, flsort,    OZ(0),
  268.     "/rrevised",    3, flsort,    OZ(0),
  269.     "/rsize",    3, flsort,    OZ(0),
  270.     "/rtype",    3, flsort,    OZ(0),
  271.     "/ruser",    3, flsort,    OZ(0),
  272.     "/rvers",    3, flsort,    OZ(0),
  273.     "/rweek",    3, flsort,    OZ(0),
  274.     "/rxab",    3, flsort,    OZ(0),
  275.  
  276. /*
  277.  * Symbol table for commands which (may) require DCL arguments or options.
  278.  * The command parser performs some checking, to ensure that the command
  279.  * looks something like it is supposed to.
  280.  */
  281.     "append",    2, flcopy,    v_M_1,        0,
  282.     "browse",    1, flmore,    v_1,        0,
  283.     "copy",        2, flcopy,    v_M_1,        0,
  284.     "create",    2, flcrea,    v_1d,        0,
  285.     "delete",    3, fldlet,    v_M0,        0,
  286. #ifdef    DEBUG
  287.     "dump",        2, fldump,    v_OMIT,        0,
  288. #endif
  289.     "edit",        1, fledit,    v_M,        read_dft,
  290.     "find",        1, flfind,    v_1a,        read_dft,
  291.     "inspect",    1, flscan,    v_1c,        read_dft,
  292.     "lsedit",    1, fledit,    v_M,        read_dft,
  293.     "next",        1, flfind,    v_OMIT,        0,
  294.     "nfind",    2, flfind,    v_1a,        read_dft,
  295.     "print",    2, flnoid,    v_M,        ".LIS",
  296.     "/protection",    3, flprot,    v_1b,        0,
  297.     "protect",    3, flprot,    v_1b,        0,
  298.     "purge",    3, fldlet,    v_M0,        0,
  299.     "read",        1, flread,    v_1c,        read_dft,
  300.     "rename",    3, flrnam,    v_1_1,        0,
  301.     "shell",    2, flescp,    v_OMIT,        0,
  302.     "spawn",    2, flescp,    v_OMIT,        0,
  303.     "submit",    2, flnoid,    v_1,        ".COM",
  304.     "update",    1, flread,    v_1c,        read_dft,
  305.     "verify",    2, flscan,    v_1c,        read_dft,
  306.     "view",        1, fledit,    v_M,        read_dft
  307.     };
  308.  
  309. /* <dircmd>:
  310.  * Loop, reading characters and executing commands until we either delete the
  311.  * last file in the list, or we receive a QUIT-command.
  312.  */
  313. void    dircmd (void)
  314. {
  315.     int    command,
  316.         curfile    = 0;
  317.  
  318.     while (! dds_last (&curfile))
  319.     {
  320.         command = dircmd_getc (&curfile);
  321.  
  322.         if (    (command == RETRIEVE)
  323.         ||    (isascii(command) && isprint(command)) )
  324.             dircmd_read (&curfile, command, "");
  325.         else if (command != DO_NEXT)
  326.             dircmd_kcmd (&curfile, command);
  327.     }
  328. }
  329.  
  330. /* <dircmd_kcmd>:
  331.  * Given that a legal keypad or control code was input, complete the processing:
  332.  */
  333. static
  334. void    dircmd_kcmd (int *curfile_, int command)
  335. {
  336.     register int    j;
  337.     register int    gold    = (command == GOLDKEY);
  338.     register char    *s_;
  339.     char    cmdbfr[CRT_COLS];
  340.  
  341.     if (gold)
  342.     {
  343.         while (command == GOLDKEY)
  344.             command = dircmd_getc (curfile_);
  345.     }
  346.  
  347.     /*
  348.      * Check for a GOLD followed by a non-keypad/non-control key:
  349.      */
  350.     if (! (is_PAD(command) || (command < ' ')))
  351.         sound_alarm();        /* ...if so, ignore the key    */
  352.  
  353.     j = toascii(command) + (gold ? 128 : 0);
  354.     if (s_ = keydefs[j].string)
  355.     {
  356.         if (keydefs[j].flags & 2)
  357.             dircmd_read (curfile_, EOS, s_);
  358.         else
  359.         {
  360.             strcpy (cmdbfr, s_);
  361.             dircmd_doit (curfile_, cmdbfr, FALSE);
  362.         }
  363.     }
  364.     else
  365.     {
  366.         set_beep ();    /* Set flag indicating error    */
  367.         sound_alarm ();
  368.     }
  369.     if (multi_quit <= 0)    dds_index (*curfile_);
  370. }
  371.  
  372. /*
  373.  * Set/Query the selected-file index.  (A "-2" will not alter the value.)
  374.  * We use 'dds_line' to alter the display to show the selected/deselected file.
  375.  */
  376. int    dircmd_select (int val)
  377. {
  378.     if (val >= -1)
  379.     {
  380.     int    was_sel     = selected;
  381.         selected = val;
  382.         if (was_sel != selected)
  383.         {
  384.             if (was_sel  >= 0)    dds_line (was_sel);
  385.             if (selected >= 0)    dds_line (selected);
  386.         }
  387.     }
  388.     return (selected);
  389. }
  390.  
  391. /* <dircmd_init>:
  392.  * Initialize this module
  393.  */
  394. void    dircmd_init (void)
  395. {
  396.     edtcmd_init();
  397.     dircmd_dirflg (TRUE);        /* forward-direction    */
  398.     selected  = -1;            /* Index of fixed-point    */
  399.     multi_quit= 0;            /* No "quit" in progress*/
  400.  
  401.     keydefs      = calloc (256, sizeof(KEYDEFS));
  402.     dircmd_keydefs (CTL('B'),    0,    "/backward");
  403.     dircmd_keydefs (CTL('E'),    0,    "/end");
  404.     dircmd_keydefs (CTL('F'),    0,    "/forward");
  405.     dircmd_keydefs (CTL('G'),     0,    "/width");
  406.     dircmd_keydefs (CTL('H'),    0,    "1-");
  407.     dircmd_keydefs (CTL('M'),    0,    "1+");
  408.     dircmd_keydefs (CTL('N'),    0,    "next");
  409.     dircmd_keydefs (CTL('P'),    0,    "protect");
  410.     dircmd_keydefs (CTL('R'),    0,    "update /n./t;/v");
  411.     dircmd_keydefs (CTL('T'),    0,    "/top");
  412.     dircmd_keydefs (CTL('V'),    0,    "verify");
  413.     dircmd_keydefs (CTL('Z'),    0,    "quit");
  414.  
  415.     dircmd_keydefs (padUP,        0,    "1-");
  416.     dircmd_keydefs (padUP,        1,    "/backward 1");
  417.     dircmd_keydefs (padDOWN,    0,    "1+");
  418.     dircmd_keydefs (padDOWN,    1,    "/forward 1");
  419.  
  420.     dircmd_keydefs (HELPKEY,    0,    "?help");
  421.     dircmd_keydefs (HELPKEY,    1,    "?help");
  422.     dircmd_keydefs (padPF3,     0,    "next");
  423.     dircmd_keydefs (padPF3,     1+2,    "find ");
  424.     dircmd_keydefs (padPF4,     0,    "/cleft");
  425.     dircmd_keydefs (padPF4,     1,    "/cright");
  426.     dircmd_keydefs (pad0,        0,    "/sname");
  427.     dircmd_keydefs (pad0,        1,    "/rname");
  428.     dircmd_keydefs (pad1,        0,    "/stype");
  429.     dircmd_keydefs (pad1,        1,    "/rtype");
  430.     dircmd_keydefs (pad2,        0,    "/sdate");
  431.     dircmd_keydefs (pad2,        1,    "/rdate");
  432.     dircmd_keydefs (pad3,        0,    "/ssize");
  433.     dircmd_keydefs (pad3,        1,    "/rsize");
  434.     dircmd_keydefs (pad4,        0,    "/forward 0");
  435.     dircmd_keydefs (pad4,        1,    "/end");
  436.     dircmd_keydefs (pad5,        0,    "/backward 0");
  437.     dircmd_keydefs (pad5,        1,    "/top");
  438.     dircmd_keydefs (pad6,        0,    "?time");
  439.     dircmd_keydefs (pad6,        1,    "/time");
  440.     dircmd_keydefs (pad7,        0,    "edit");
  441.     dircmd_keydefs (pad7,        1,    "view");
  442.     dircmd_keydefs (pad8,        0,    "/page");
  443.     dircmd_keydefs (pad9,        0,    "browse");
  444.     dircmd_keydefs (pad9,        1,    "browse/mark/over:3");
  445.     dircmd_keydefs (padMINUS,    0+2,    "-");
  446.     dircmd_keydefs (padMINUS,    1+2,    "-");
  447.     dircmd_keydefs (padCOMMA,    0,    "?memory");
  448.     dircmd_keydefs (padDOT,        0,    "/mark");
  449.     dircmd_keydefs (padDOT,        1,    "/nomark");
  450.     dircmd_keydefs (padENTER,    0,    "1+");
  451.     dircmd_keydefs (padENTER,    1,    "1-");
  452.  
  453.     strcpy (read_dft, dirent_dft());
  454. }
  455.  
  456. /* <dircmd_keydefs>:
  457.  * Copy a new key-definition into the 'keydefs[]' table.  We map the control
  458.  * characters to themselves, and the keypad codes down to ASCII.  Use the
  459.  * gold-key flag to drive a shift into 128-255.
  460.  */
  461. static
  462. void    dircmd_keydefs (int code, int flags, char *string)
  463. {
  464.     register int c = toascii(code) + ((flags & 1) ? 128 : 0);
  465.     keydefs[c].flags = flags & ~1;
  466.     keydefs[c].string = string;
  467. }
  468.  
  469. /* <dircmd_getc>:
  470.  * Read a single command (keystroke-level), suppressing characters such
  471.  * as control/S and control/Q which may be passed back by 'getpad()',
  472.  * which are not used as single-key commands by "FLIST".
  473.  *
  474.  * In particular, absorb all incoming nulls, since this code is used (DO_NEXT)
  475.  * to tell the higher-level routines to continue reading command-input.
  476.  */
  477. static
  478. int    dircmd_getc (int *curfile_)
  479. {
  480.     int    command;
  481.  
  482.     for (;;)
  483.     {
  484.         switch (command = edtcmd_get())
  485.         {
  486.         case CTL('U'):
  487.         case CTL('X'):
  488.         case CTL('C'):            /* Equate ^C, ^Y to ^U    */
  489.         case CTL('Y'):
  490.         case ' ':
  491.         case '\t':
  492.         case '\n':
  493.         case RUBOUT:
  494.         case padLEFT:
  495.         case padRIGHT:
  496.             sound_alarm ();        /* Illegal context    */
  497.         case CTL('Q'):
  498.         case CTL('S'):
  499.         case 0:                /* == DO_NEXT        */
  500.             break;
  501.         case '-':            /* Gives 1 level w/o keypad */
  502.             command = RETRIEVE;
  503.         default:
  504.             goto got_command;
  505.         }
  506.     }
  507. got_command:
  508.     /*
  509.      * If a message was pending, wipe it off with the first character
  510.      * of a new command, except:
  511.      *    a) if we had an error message, and the current character is
  512.      *       a repeat of the offending one, or
  513.      *    b) if we had an informational message (triggered by a keypad
  514.      *       or control-key) and it is repeated.
  515.      *
  516.      * patch: should suppress wipeoff if the key is GOLD.
  517.      */
  518.     if ((command == RETRIEVE) || didbeep() || didwarn())
  519.     {
  520.         register
  521.         int    repeated = edtcmd_last(command) &&
  522.                     (iscntrl(command) ||
  523.                     !isascii(command) ),
  524. /********/
  525.             isel    = dircmd_select(-2);
  526.  
  527.         if (repeated
  528.         &&  (isel >= 0)
  529.         &&  (isel != *curfile_)
  530.         &&  (command == CTL('D'))) /* PATCH !! */
  531.         {
  532.             char    iname[MAX_PATH],
  533.                 oname[MAX_PATH];
  534.             dirent_glue (iname, FK_(isel));
  535.             dirent_glue (oname, FK_(*curfile_));
  536.             acpcopy (3, iname, oname);
  537.             dirent_chk2 (*curfile_); /* Re-read this entry */
  538.             command = DO_NEXT;
  539.         }
  540.         else
  541. /********/
  542.         if (!repeated)
  543.         {
  544.             clrwarn();        /* ...clear it off screen */
  545.             dds_index (*curfile_);
  546.         }
  547.     }
  548.     return (command);
  549. }
  550.  
  551. /* <dircmd_read>:
  552.  * Read/edit a "visible" command.  After editing it, execute it:
  553.  */
  554. static
  555. void    dircmd_read (int *curfile_, int command, char *original)
  556. {
  557.     int    line    = *curfile_ - crt_top();
  558.  
  559.     clrwarn();
  560.     dds_index (*curfile_);        /* clear out any prior messages */
  561.  
  562.     if (command == '-')    command = RETRIEVE;
  563.     dircmd_doit (
  564.         curfile_,
  565.         edtcmd (command,    /* Initial command-char        */
  566.             nullC,        /* No special delimiter-list    */
  567.             7,        /* Highlight+lowercase+trim    */
  568.             line,        /* ...on which to receive    */
  569.             dirent_ccol(),    /* beginning command-column    */
  570.             "FLIST",    /* patch:'whoami': help-entry    */
  571.             original,
  572.             crtvec[line]),
  573.         TRUE);            /* Save resulting command    */
  574. }
  575.  
  576. /* <dircmd_doit>:
  577.  * Execute a command string.  Return a continuation command-code.
  578.  */
  579. static
  580. void    dircmd_doit (int *curfile_, char *cmdbfr, int history)
  581. {
  582. DCLARG    *xdcl_    = nullS(DCLARG);    /* 'dirarg()' parsed list    */
  583. tDIRCMD((*DO_func)) = 0;        /* external function to execute    */
  584. int    cmdlen    = 0,            /* length of parsed keyword    */
  585.     cmdnum    = EXTRN_CMD,        /* index to 'vcmd2', if used    */
  586.     j,
  587.     prefix    = 0,            /* nonzero iff prefix operator    */
  588.     k1st    = 0,            /* != 'prefix' if SET/SHOW    */
  589.     omit    = FALSE,        /* TRUE iff "/o" prefix used    */
  590.     non_DCL    = FALSE,        /* TRUE iff non-DCL arguments    */
  591.     temp_fix= FALSE,        /* TRUE iff '//sort'        */
  592.     sort_cmd= FALSE,        /* '/' prefix only on sort-cmd    */
  593.     known_cmd = FALSE;
  594. char    *fullname = "",
  595.     *xcmd_    = nullC,        /* 'dirarg()' substituted string*/
  596.     tmp_bfr    [MAX_PATH],        /* temporary buffer        */
  597.     err_msg    [MAX_PATH];
  598.  
  599.     clrwarn();            /* Permit current command to continue */
  600.     flist_log ("$ %.80s", cmdbfr);
  601.  
  602.     if (!*cmdbfr)
  603.         return;        /* Ignore ^U, etc.    */
  604.  
  605.     /*
  606.      * Translate & execute the command.
  607.      *
  608.      * The first "token" on the line is the command keyword.  It may
  609.      * contain a leading "/" for punctuation, but otherwise must be a
  610.      * legal VMS filespec (i.e., the most general form of a command).
  611.      * (This rule is used to find the beginning of the argument
  612.      * substitution list).
  613.      *
  614.      * A "/" before a sort command (e.g., "//sn") will cause a flag to
  615.      * be set selecting a fixed-point sort for that command only.  This
  616.      * is an extension provided only for sort-commands.
  617.      *
  618.      * A "/o" before any non-sorting command sets a flag which disables
  619.      * the normal practice of using the current file-entry as an implicit
  620.      * argument.
  621.      */
  622.     cmdlen    = strtrim (cmdbfr);
  623.     prefix    = 0;
  624.     omit    = FALSE;
  625.     if (cmdbfr[0] == '/')
  626.     {
  627.         if (cmdbfr[1] == '/')
  628.             prefix++;        /* Allow "//sort"    */
  629.         else if (isdigit(cmdbfr[1]) || isspace(cmdbfr[1]))
  630.             prefix++;        /* Allow "/ number"    */
  631.         else if (cmdbfr[1] == 'o' && !isalpha(cmdbfr[2]))
  632.         {
  633.             prefix    += 2;
  634.             omit    = TRUE;
  635.         }
  636.         if (prefix)    /* Allow blanks after prefix-text    */
  637.             prefix += strskps(&cmdbfr[prefix]) - &cmdbfr[prefix];
  638.     }
  639.  
  640.     k1st    = prefix;
  641.     if (strchr ("/@?", cmdbfr[k1st]))        k1st++;
  642.     j    = (dclarg_spec (&cmdbfr[k1st], nullC) - &cmdbfr[k1st]) + k1st;
  643.     cmdlen    = j - prefix;
  644.  
  645.     /*
  646.      * Lookup the command-verb.
  647.      */
  648.     strncpy (tmp_bfr, &cmdbfr[prefix], cmdlen);
  649.     tmp_bfr[cmdlen] = EOS;
  650.     err_msg[0] = EOS;
  651.  
  652.     if (xcmd_ = dirarg (&xdcl_, *curfile_,
  653.             &cmdbfr[prefix + cmdlen], tmp_bfr, omit) )
  654.     {
  655.         /*
  656.          * Check 'xcmd_', since it is lowercased, with the complete
  657.          * command-verb.  We must get an index of at least 2, to skip
  658.          * over the SET/SHOW verbs.
  659.          */
  660.         j = strlen(xdcl_->dcl_text);
  661.         if (strchr ("/?", *xcmd_))    j++;
  662.         cmdnum = debrief (err_msg, vcmd2, sizeof(VCMD2), SIZEOF(vcmd2),
  663.                 xcmd_, j);
  664.         if (cmdnum >= 2)
  665.         {
  666.             if (!(DO_func = vcmd2[cmdnum].v_func))
  667.                 DO_func = not_impl;
  668.             fullname  = vcmd2[cmdnum].v_full;
  669.             non_DCL      = vcmd2[cmdnum].v_mode & v_nonDCL;
  670.             sort_cmd  = (*fullname == '/')
  671.                  && strchr("rs", fullname[1]);
  672.             if ((sort_cmd && prefix) || (vcmd2[cmdnum].v_mode & v_NAME))
  673.             {
  674.                 dirent_glue (tmp_bfr, FK_(*curfile_));
  675.                 flist_log ("! %.80s", tmp_bfr);
  676.             }
  677.             if (dirchk (xcmd_, xdcl_, vcmd2[cmdnum].v_mode, TRUE))
  678.                 known_cmd = TRUE;
  679.             else
  680.                 cmdnum    = ERROR_CMD;
  681.         }
  682.         else
  683.             cmdnum    = EXTRN_CMD;
  684.     }
  685.  
  686.     cmdlen    += prefix;    /* count the first '/' as part of cmd    */
  687.     if (prefix && !omit)    /* Did I have a leading '/'?        */
  688.     {
  689.         if (non_DCL && sort_cmd)
  690.             temp_fix = TRUE;
  691.         else if (!isdigit(cmdbfr[prefix]))
  692.         {
  693.             warn ("'/'-prefix is legal only on sort-command");
  694.             cmdbfr[0] = EOS;
  695.         }
  696.     }
  697.  
  698.     /*
  699.      * Common exit point for all completed command-input:
  700.      */
  701.     dds_line (*curfile_);    /* refresh the screen after receipt    */
  702.  
  703.     /*
  704.      * A number directs "FLIST" to move the cursor to the specified
  705.      * file-index a la FLIST.  We permit a prefix '/' (actually ignore
  706.      * all prefixes), and a trailing sign, for relative movement.
  707.      */
  708.     if (isdigit(cmdbfr[prefix]))
  709.     {
  710.     register char    *d_ = &cmdbfr[cmdlen];
  711.     register int    sign = 0;
  712.     int    inx = dds_inx1 (*curfile_),
  713.         val;
  714.  
  715.         if ((cmdlen >= 1) && (d_[-1] == '-')) {
  716.             d_--;
  717.             cmdlen--;
  718.         } else
  719.             d_ = strskps(d_);
  720.         if (*d_)
  721.         {
  722.             if (! strcmp (d_, "+"))        sign = 1;
  723.             else if (! strcmp (d_, "-"))    sign = -1;
  724.             else    warn ("<number> uses no arguments: %s", d_);
  725.             cmdbfr[cmdlen] = EOS;
  726.         }
  727.         if (! didwarn ())
  728.         {
  729.             if (scanint(&cmdbfr[prefix], &val) == &cmdbfr[cmdlen])
  730.             {
  731.                 if (val == 1 && sign)
  732.                     flist_move (curfile_, *curfile_,
  733.                         sign > 0 ? DDS_D_1 : DDS_U_1);
  734.                 else
  735.                 {
  736.                     if (sign)    inx += (sign * val);
  737.                     else        inx = val;
  738.                     *curfile_ = dds_inx2 (inx);
  739.                 }
  740.             }
  741.             else
  742.                 warn ("Illegal number: %s\n", &cmdbfr[prefix]);
  743.         }
  744.         cmdbfr[0] = EOS;    /* Don't save for retrieval */
  745.         cmdlen      = 0;
  746.     }
  747.     else if (!strcmp(cmdbfr, "/"))    /* Force current entry to top-of-screen */
  748.     {
  749.         cmdbfr[0] = EOS;
  750.         dds_scroll (crt_end() + (*curfile_ - crt_top()));
  751.     }
  752.     if (history) cmdstk_put (cmdbfr);
  753.  
  754.     /*
  755.      * If 'known_cmd', then we found the command name in one of the tables.
  756.      */
  757.     if (known_cmd && !didwarn())
  758.     {
  759.         if (cmdnum >= 2)
  760.             (*DO_func)(curfile_, xcmd_, xdcl_, temp_fix, history);
  761.     }
  762.     /* patch:
  763.      * If not found in symbol table, simply make a nice error message.
  764.      * Later, should consider trying to spawn an appropriate process to
  765.      * execute non-screenable commands.
  766.      */
  767.     else if (cmdbfr[0] && !didwarn())
  768.     {
  769.         if (*err_msg)
  770.             warn ("%s", err_msg);
  771.         else if (cmdlen)
  772.         {
  773.             cmdbfr[cmdlen] = EOS;
  774.             warn ("Unknown command '%.30s'.  Type '/help'.",
  775.                 (cmdbfr[0] == '/' ? &cmdbfr[prefix]
  776.                           : cmdbfr) );
  777.         }
  778.         else
  779.             warn ("Illegal command: '%.30s'", cmdbfr);
  780.     }
  781.  
  782.     dds_done();    /* clear the "Working..." message, if any */
  783.  
  784.     if (xdcl_)    freelist (xdcl_);
  785.     if (xcmd_)    cfree (xcmd_);
  786. }
  787.  
  788. /* <dircmd_ask>:
  789.  * This procedure may be called by a visible-command to verify an action.
  790.  * Prompt for:
  791.  *    G - (2) go, selecting Y (if loop) for all successive prompts
  792.  *    Y - (1) yes
  793.  *    N - (0) disallow this particular selection
  794.  *    Q - (-1) same as N, but exit loop, if any
  795.  */
  796. int    dircmd_ask (int curfile, char *msg_)
  797. {
  798.     int    reply    = 256,
  799.         rline    = curfile - crt_top();
  800.     char    *s_,
  801.         tell    [80];
  802.     static    char    ok[]    = "QNYG";
  803.  
  804.     sprintf (tell, "%.60s (G,Y/N,Q): ", msg_);
  805.     edtcmd_crt (tell, crtvec[rline], TRUE, dirent_ccol(), rline, strlen(tell)-1);
  806.     for (;;)
  807.     {
  808.         for (reply = 256; (!isascii(reply) || !isprint(reply));)
  809.             reply = edtcmd_get ();
  810.         if (s_ = strchr (ok, _toupper(reply)))    break;
  811.         sound_alarm();        /* warn if incorrect reply    */
  812.     }
  813.  
  814.     dds_line (curfile);        /* refresh display */
  815.  
  816.     return ((s_-ok)-1);
  817. }
  818.  
  819. /* <dircmd_vcmd2>:
  820.  * Do table lookup to find FLIST's full-name for a "visible" command.  This
  821.  * lookup is used only for the VCMD2-entries (which can specify arguments,
  822.  * hence must be parsed).  Because the command name may be found via lookup
  823.  * in the logical-symbol table, this procedure may be called more than once
  824.  * to interpret a command.
  825.  *
  826.  * If the name is not found in FLIST's table, assume it is the name of an
  827.  * external command.
  828.  */
  829. int    dircmd_vcmd2 (char *cmd_, int len)
  830. {
  831.     int    j;
  832.  
  833.     for (j = 0; j < SIZEOF(vcmd2); j++)
  834.     {
  835.         if ((len >= vcmd2[j].v_len)
  836.         &&  !strncmp (cmd_, vcmd2[j].v_full, len))
  837.             return (j);
  838.     }
  839.     return (EXTRN_CMD);    /* not found, return an illegal index    */
  840. }
  841.  
  842. /* <dircmd_full>:
  843.  * Return a pointer to a specified component of 'vcmd2[]'.  This is needed
  844.  * in 'dirarg', which does a lookup into 'vcmd2[]' before testing for a
  845.  * logical-symbol.
  846.  */
  847. VCMD2*    dircmd_full (int cmdnum)
  848. {
  849.     return (&vcmd2[cmdnum]);    /* patch: limits on 'cmdnum' ?    */
  850. }
  851.  
  852. /* <dircmd_dirflg>:
  853.  * Return the direction-flag to make it public:
  854.  */
  855. int    dircmd_dirflg (int flag)
  856. {
  857.     if (flag > 0)        dir_flg = TRUE;
  858.     else if (flag == 0)    dir_flg = FALSE;
  859.     return (dir_flg);
  860. }
  861.  
  862. /* <not_impl>:
  863.  * Print an appropriate error message for unimplemented routines:
  864.  */
  865. tDIRCMD(not_impl)
  866. {
  867.     warn ("?NOT implemented: %.60s", xcmd_ ? xcmd_ : xdcl_->dcl_text);
  868. }
  869.