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

  1. #ifndef NO_IDENT
  2. static char *Id = "$Id: dirarg.c,v 1.8 1995/10/21 18:17:55 tom Exp $";
  3. #endif
  4.  
  5. /*
  6.  * Title:    dirarg.c
  7.  * Author:    T.E.Dickey
  8.  * Created:    23 Jun 1984
  9.  * Last update:
  10.  *        19 Feb 1995, prototypes
  11.  *        11 Oct 1988, corrected place where "/o" alone breaks code.
  12.  *        21 Sep 1985, translate SET/SHOW to '/', '?' prefix
  13.  *        18 Sep 1985, process non-DCL commands here also
  14.  *        09 Sep 1985, must trim trailing '.' from FNAME-field
  15.  *        05 Jul 1985, corrected release of dcl-list if error.
  16.  *        03 Jul 1985, cleanup of 'filelist' definition
  17.  *        14 May 1985, added log-file entry for implicit arguments
  18.  *        15 Dec 1984, added 'cpy_dft' argument to 'dclarg'.
  19.  *        17 Oct 1984, omit extra space after 0th token
  20.  *        25 Aug 1984, cleanup of buffer limits
  21.  *        03 Aug 1984, added call to 'sysgetsym'
  22.  *        25 Jul 1984, added 'cmd_arg' parameter to 'dclarg()'
  23.  *        15 Jul 1984, use PATHOF()
  24.  *        13 Jul 1984, protect 'warn' by "%s" format
  25.  *        04 Jul 1984
  26.  *
  27.  * Function:    This module performs syntax checking on the command text
  28.  *        which is received by 'dircmd' for FLIST.  The command-name
  29.  *        may be translated if it is a symbol (to permit FLIST to
  30.  *        associate it with one of its "known" commands).
  31.  *
  32.  *        The argument portion of the string is checked.  The prefix
  33.  *        "/o" and the command name are already parsed off, and leading
  34.  *        blanks removed.  This module is called before executing the
  35.  *        interpretation routines.
  36.  *
  37.  * Parameters:    dcl__ =>  pointer to load with linked-list address of parsed
  38.  *              DCL tokens.  The 0th entry of this list will be the
  39.  *              resulting command name.  Subsequent entries are the
  40.  *              options and filespecs, parsed by 'dclarg'.  All
  41.  *              '.dcl_text' items are uppercased by the parsed.
  42.  *              The '?' or '/' prefix is stripped from the command
  43.  *              verb (the first entry).
  44.  *        curfile    = index to nominal current file index in 'filelist[]'.
  45.  *              It is used directly when the "/" substitution is
  46.  *              performed.
  47.  *        argstr    = buffer containing the argument text.  It may be a
  48.  *              null pointer, in which case the string "" or "/"
  49.  *              is assumed, according to whether 'minarg' is 0 or 1.
  50.  *        command    = string defining full name of CLI command to execute.
  51.  *              Since it may be a logical symbol, this procedure
  52.  *              must first test that, then perform a substitution
  53.  *              and parse.  Because 'dclarg' only knows about
  54.  *              defaulting items in argument lists, the command
  55.  *              entry must be re-adjusted.
  56.  *        omit    = TRUE if user gave "/o" token.
  57.  *
  58.  * Returns:    A pointer to a character string representing the simple
  59.  *        ("/-token and logical symbol) substitution of the command
  60.  *        and argument string.  If a process must be spawned by the
  61.  *        command interpreter, this string is used as the actual
  62.  *        command string, rather than the concatenated DCLARG list
  63.  *        (due to the length, and to the level of substitution performed).
  64.  *
  65.  *        The command-verb is fully-substituted in this string.  The
  66.  *        string is in lowercase.  The SET/SHOW ('/', '?') prefix is
  67.  *        retained for use in error-checking.
  68.  *
  69.  *        The return value is NULL if an error condition was detected
  70.  *        (an appropriate message is emitted via 'warn').  This procedure
  71.  *        uses 'dclarg/dclchk' to check for syntax errors.  Further
  72.  *        tests must be made for proper number of arguments, etc.
  73.  *
  74.  *        If no error is detected, garbage collection should be done
  75.  *        on the returned string, and on the DCLARG list '*dcl__',
  76.  *        after use.  (If an error is detected here, they are already
  77.  *        released.)
  78.  */
  79.  
  80. #include    <stdlib.h>
  81. #include    <stdio.h>
  82. #include    <ctype.h>
  83. #include    <string.h>
  84.  
  85. #include    <rms.h>
  86.  
  87. #include    "flist.h"
  88. #include    "dclarg.h"
  89. #include    "dircmd.h"
  90. #include    "freelist.h"
  91.  
  92. #include    "strutils.h"
  93. #include    "sysutils.h"
  94.  
  95. import(filelist);
  96.  
  97. char    *dirarg (
  98.     DCLARG    **dcl__,
  99.     int    curfile,
  100.     char    *argstr,
  101.     char    *command,
  102.     int    omit)
  103. {
  104. FILENT    *z    = FK_(curfile);
  105. DCLARG    *dcl_;
  106. VCMD2    *vcmd_    = 0;
  107. int    cmdnum,            /* Index into 'vcmd2[]' table    */
  108.     cmdlen,            /* length of command-verb    */
  109.     cpy_dft    = FALSE,    /* Assume command is not COPY    */
  110.     non_DCL    = FALSE,    /* Assume command uses DCL-syntax */
  111.     len,
  112.     alias    = FALSE,    /* TRUE iff 'command' is symbol    */
  113.     subs    = FALSE,    /* TRUE iff '/' token found    */
  114.     havelen,        /* Current length of 'cmd[]'    */
  115.     twoparm    = FALSE,    /* TRUE if COPY, APPEND, etc.    */
  116.     used    = FALSE;    /* Used "/" current-file token    */
  117. char    filespec[MAX_PATH],
  118.     symbol1    [MAX_PATH],    /* expansion via 'sysgetsym()'    */
  119.     symbol2    [MAX_PATH],    /* command-part of expansion    */
  120.     symbol3    [MAX_PATH],    /* SET/SHOW translation        */
  121.     *dft_    = 0,
  122.     *cmd,
  123.     *i_,    *o_;
  124.  
  125.     /*
  126.      * Numbers are a special case: they are used solely for positioning.
  127.      * The '/' command is also used only for positioning.  These are
  128.      * parsed elsewhere.
  129.      */
  130.     if (isdigit(*command) || !strcmp(command, "/"))    return (nullC);
  131.  
  132.     dirent_glue (filespec, z);
  133.  
  134.     cmd    = calloc (1, havelen = MAX_PATH);
  135.  
  136.     /*
  137.      * If the given keyword is a FLIST-recognized command, or if the user
  138.      * has assigned a symbol which equates to it, set 'cmdnum' to the
  139.      * corresponding VCMD2-table index.  Otherwise, let the command fall-
  140.      * through to be treated as a non-FLIST command
  141.      */
  142. #define    MODE(m)    (vcmd_->v_mode & (m))
  143. #define    CMDNUM(t)  (cmdnum = dircmd_vcmd2 (t, strlen(t)))
  144.  
  145.     if (CMDNUM(command) < 0)
  146.     {
  147.         if (sysgetsym (symbol1, command, sizeof(symbol1)))
  148.         {
  149.             strlcpy (symbol1, nullC); /* lowercase for parse */
  150.             len = dclarg_spec (symbol1, "@") - symbol1;
  151.             strncpy (symbol2, symbol1, len);
  152.             symbol2[len] = EOS;
  153.             if (CMDNUM(symbol2) >= 0)
  154.             {
  155.                 alias    = TRUE;
  156.                 o_    = calloc (1, strlen(argstr)
  157.                            + strlen(symbol1));
  158.                 sprintf (o_, "%s%s", &symbol1[len], argstr);
  159.                 argstr    = o_;
  160.                 command    = symbol2;
  161.             }
  162.         }
  163.     }
  164.  
  165.     /*
  166.      * FLIST's '/' and '?' prefixes are analogous to VMS 'SET' and 'SHOW'
  167.      * commands.  Translate 'SET' and 'SHOW' verbs into FLIST-format.
  168.      */
  169.     if (cmdnum == 0 || cmdnum == 1)
  170.     {
  171.         strcpy (symbol3, (cmdnum ? "/" : "?"));
  172.         strcpy (&symbol3[1], strskps(argstr));
  173.         len = dclarg_spec (symbol3+1, "@") - symbol3;
  174.         if (!alias)    argstr = calloc(1, strlen(symbol3));
  175.         strcpy (argstr, &symbol3[len]);
  176.         alias = TRUE;
  177.         symbol3[len] = EOS;
  178.         command = symbol3;
  179.         CMDNUM(command);
  180.     }
  181.  
  182.     /*
  183.      * If the command-verb is recognizable, save its state:
  184.      */
  185.     if (cmdnum >= 0)
  186.     {
  187.         vcmd_    = dircmd_full (cmdnum);
  188.         command    = vcmd_->v_full;
  189.         omit    = omit || MODE(v_OMIT) || MODE(v_nonDCL);
  190.         twoparm    = !omit && MODE(v_1_OUT + v_M_OUT);
  191.         dft_    = vcmd_->v_dfts;
  192.     }
  193.     else
  194.         omit    = TRUE;
  195.  
  196.     strcpy (cmd, command);        /* Start with 0th entry */
  197.     i_    = argstr;
  198.     o_    = strnull (cmd);
  199.     cmdlen    = strlen (cmd);
  200.  
  201.     /*
  202.      * Substitute path,name,type,version tokens as required.
  203.      */
  204.     while (*i_)
  205.     {
  206. #define    C    i_[1]
  207.         subs    = FALSE;
  208.         if ((i_[0] == '/')
  209.         &&  isalnum(i_[1]) && !isalnum(i_[2]))
  210.         {
  211.             subs    = TRUE;
  212.             switch (C)
  213.             {
  214.             case 'p':    strcat (o_, zPATHOF(z));    break;
  215.             case 'n':    dirent_cat_n (o_, z);        break;
  216.             case 't':    strcat (o_, z->ftype);        break;
  217.             case 'v':    sprintf (o_, "%d", z->fvers);    break;
  218.             default:    subs    = FALSE;
  219.                     strcat (o_, "/");
  220.             }
  221.             i_++;
  222.             if (subs)    i_++;
  223.         }
  224.         /*
  225.          * Permit current-file substitution anywhere a '/' is found
  226.          * next to a character which would make it an error (or at
  227.          * least unlikely) for VMS syntax:
  228.          */
  229.         else if (*i_ == '/'
  230.         && (isspace(C) || C == ',' || C == ')' || C == '/' || !C))
  231.         {
  232.             subs    = TRUE;
  233.             i_++;
  234.             if (!used)
  235.             {
  236.                 strcpy (o_, filespec);
  237.                 used    = TRUE;
  238.             }
  239.         }
  240.         else
  241.         {
  242.             *o_++    = *i_++;
  243.             *o_    = EOS;
  244.         }
  245.  
  246.         /*
  247.          * Re-check the allocated length of the substituted string.
  248.          * It may be much longer than the input string.  Reallocate
  249.          * if necessary, so that the next substitution will have
  250.          * enough space for a full filename.
  251.          */
  252.         o_    = strnull (o_);
  253.         if (subs)
  254.         {
  255.             if ((strlen (i_) + strlen (cmd) + MAX_PATH) > havelen)
  256.             {
  257.                 cmd    = realloc (cmd, havelen += MAX_PATH);
  258.                 o_    = strnull (cmd);
  259.             }
  260.         }
  261.     }
  262.     *o_    = EOS;
  263.  
  264.     /*
  265.      * If the current entry hasn't been used, and the command mode implies
  266.      * its inclusion, put it on the end of the command string.  If this is
  267.      * a two-parameter command (e.g., COPY), at the same time trim the
  268.      * version number from the text so that the user will be able to run
  269.      * COPY in a natural manner (i.e., create a new version).
  270.      */
  271.     if (!omit)
  272.     {
  273.         if (! used)
  274.         {
  275.             if (twoparm)
  276.             {
  277.                 FILENT    ztmp    = *z;
  278.                 ztmp.fvers    = 0;
  279.                 dirent_glue (filespec, &ztmp);
  280.             }
  281.             sprintf (o_, " %s", filespec);
  282.         }
  283.         flist_log ("! %.80s", filespec);
  284.     }
  285.     else if (subs)
  286.         flist_log ("! %.80s", &cmd[cmdlen]);
  287.  
  288.     if (alias)    cfree (argstr);    /* release locally-acquired bfr    */
  289.  
  290.     /*
  291.      * All "normal" commands fall through this point, including things
  292.      * like COPY and APPEND (which do not propagate the pathname to the
  293.      * output specification).  Do a quick check to see if we have one
  294.      * of these special cases.
  295.      */
  296.     o_ = cmd;
  297.     if (*o_ == '/' || *o_ == '?')
  298.         o_++;
  299.  
  300.     if ((cmdnum = dircmd_vcmd2(cmd, dclarg_spec(o_, "@") - cmd)) >= 0)
  301.     {
  302.         vcmd_    = dircmd_full(cmdnum);
  303.         cpy_dft    = MODE(v_COPY);
  304.         non_DCL    = MODE(v_nonDCL);
  305.     }
  306.  
  307.     /*
  308.      * Parse the resulting command:
  309.      */
  310.     dcl_    = dclarg (o_, dft_, non_DCL ? strlen(o_) : 1, cpy_dft);
  311.     if (dclchk (dcl_, cmd))        /* 'cmd' is altered iff an error */
  312.     {
  313.         warn ("%s", cmd);
  314.         cfree (cmd);
  315.         freelist (dcl_);
  316.         return (nullC);        /* error was found    */
  317.     }
  318.  
  319.     /*
  320.      * Restore '?' (normally illegal-DCL), and set command-name in
  321.      * uppercase to ease later comparisons.
  322.      */
  323.     if (dcl_ && dcl_->dcl_text)
  324.         strucpy (dcl_->dcl_text, nullC);
  325.     else {
  326.         cfree (cmd);
  327.         return (nullC);
  328.     }
  329.     /*
  330.      * Return pointers to DCLARG-list, and to substituted commands:
  331.      */
  332.     *dcl__    = dcl_;
  333.     return (cmd);            /* No error found    */
  334. }