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

  1. #ifndef NO_IDENT
  2. static char *Id = "$Id: dirfind.c,v 1.8 1995/10/25 15:40:18 tom Exp $";
  3. #endif
  4.  
  5. /*
  6.  * Title:    dirfind.c
  7.  * Author:    Thomas E. Dickey
  8.  * Created:    28 Jul 1984 (broke off search code from 'flfind.c')
  9.  * Last update:
  10.  *        25 Oct 1995, corrected missing check for deleted-files in
  11.  *                 'dirfind()'.
  12.  *        18 Mar 1995, prototypes
  13.  *        14 Sep 1985, enhanced 'strwcmp' to process "..." in pathname.
  14.  *                 Therefore, we need substitute a "*" into the
  15.  *                 pathname only for the case of non-explicit path.
  16.  *        09 Sep 1985, count trailing '.' in fname-field for VMS-collating
  17.  *        13 Aug 1985, added 'dirfind_chop' to make clean "?FIND" display.
  18.  *        03 Jul 1985, cleanup 'filelist' definition
  19.  *        23 Jun 1985, use 'scanver' to isolate version-scanning.
  20.  *        15 Jun 1985, eliminated unused 'j' argument from 'if_T'.
  21.  *                 Reference function-'each' as '(*each) to make
  22.  *                 CC2.0 happy.
  23.  *        02 May 1985, changed call on 'dircmd_dirflg'
  24.  *        10 Mar 1985, revised PATHNT structure.
  25.  *        08 Mar 1985, defined negative code for 'forward' argument.
  26.  *        05 Feb 1985, broke out 'dirfind_notexp' to permit reuse.
  27.  *        30 Jan 1985, re-code so that 'dirfind_tst' receives pointers to
  28.  *                 two FILENT-blocks (permitting re-use).
  29.  *        05 Jan 1985, use DCLARG-structure rather than string to
  30.  *                 represent search-spec, so that we needn't do
  31.  *                 another parse here on the default-spec to obtain
  32.  *                 wildcard information.
  33.  *        29 Dec 1984, do "working..." if 'dft_spec' uses wildcard,
  34.  *                 when 'each' is set.
  35.  *        24 Dec 1984, added 'unfind' argument so that this can support
  36.  *                 the "NFIND" command (search for mismatch).
  37.  *        14 Dec 1984, added nam-argument to 'dirent_chop'
  38.  *        10 Sep 1984, use "rmsinit"
  39.  *        26 Aug 1984, cleanup buffer sizes
  40.  *        16 Aug 1984, use '.fmisc' flag to hit entries once
  41.  *        13 Aug 1984, fixed use of 'must_find', permit quit from loop.
  42.  *                 Added (kludgy) relative version testing.
  43.  *        24 Jul 1984, re-coded test for wildcard pathname
  44.  *        15 Jul 1984, use PATHOF()
  45.  *        05 Jul 1984
  46.  *
  47.  * Function:    The 'dirfind' procedure performs in-list searches for FLIST.
  48.  *        This directly supports the FIND and NEXT commands, as well
  49.  *        as the VERIFY command (which must find specific wildcard lists
  50.  *        in 'filelist[]').
  51.  *
  52.  *        The FIND/NEXT commands require that the search be startable
  53.  *        from any point, in FLIST's sorted order rather than that known
  54.  *        to SYS$SEARCH.  Therefore I use my own wildcard compare.
  55.  *
  56.  *        If 'each' is set, we use a separate loop from the "once"
  57.  *        searches.  We use the actual search loop to find all files
  58.  *        to which the search applies before calling 'each'.  This is
  59.  *        needed to make DELETE (especially of current versions!) work
  60.  *        properly.
  61.  *
  62.  * Parameters:    curfile    - is the starting index in 'filelist[].
  63.  *        forward - defines direction of search:
  64.  *              (-1): Use default direction-flag to modify 'curfile'
  65.  *                so that the apparent search will begin at
  66.  *                'curfile' and loop around.
  67.  *              (0):    Search backward from 'curfile', with wraparound.
  68.  *              (1):    Search forward from 'curfile', with wraparound.
  69.  *        find_spec - is a DCLARG structure containing the parsed filespec
  70.  *            (containing wildcards) to use as the search pattern.
  71.  *        each - is a pointer to a function to execute on each entry
  72.  *            which matches.  If no function is given, assume that
  73.  *            we wish to find only the next occurrence.  If the
  74.  *            pointer isn't null, continue executing the search
  75.  *            loop until no more items are found.  If the function
  76.  *            returns FALSE, do a quit after executing.
  77.  *        must_find - is TRUE if failure to find any entry will cause
  78.  *            an error message.
  79.  *        unfind - TRUE if we are searching for a mismatch, rather than
  80.  *            a match.
  81.  *
  82.  * Returns:    If the filespec is found, return the index into 'filelist[]'
  83.  *        at which it was found, or a negative number if it was not.
  84.  *        (If 'each' is set, instead return the number of entries
  85.  *        which were found.)
  86.  *
  87.  * patch:    Should provide date-wise selection options to support DELETE,
  88.  *        PURGE, FIND.
  89.  */
  90.  
  91. #include    <string.h>
  92.  
  93. #include    <rms.h>
  94. #include    <stsdef.h>
  95.  
  96. #include    "flist.h"
  97. #include    "dirent.h"
  98. #include    "dclarg.h"
  99. #include    "dds.h"
  100. #include    "dircmd.h"
  101.  
  102. #include    "dirfind.h"
  103.  
  104. #include    "scanver.h"
  105. #include    "strutils.h"
  106.  
  107. import(filelist); import(numfiles);
  108.  
  109. int    dirfind (
  110.     int    curfile,
  111.     int    forward,
  112.     DCLARG    *find_spec,
  113.     void    (*each)(int, int *),
  114.     int    must_find,
  115.     int    unfind)
  116. {
  117. #define    FIND_FNB    find_spec->dcl$l_fnb
  118. #define    FIND_TEXT    find_spec->dcl_text
  119.  
  120. PATHNT    pz;
  121. FILENT    fz;
  122.  
  123. int    flag    = TRUE,        /* continue-loop unless 'each' quits    */
  124.     found_any = 0;
  125. int    j, k, tst;
  126. char    Fpath[MAX_PATH],    Fname[MAX_NAME+1],    Ftype[MAX_TYPE+1];
  127.  
  128.     dirfind_chop (find_spec, &fz, &pz, Fpath, Fname, Ftype);
  129.  
  130.     /*
  131.      * If 'forward' is negative, obtain the proper value from the
  132.      * command decoder:
  133.      */
  134.     if (forward < 0)
  135.     {
  136.         forward = dircmd_dirflg(-1);
  137.         curfile    = dirfind_nxt (curfile, !forward);
  138.     }
  139.  
  140. #define    XOR(a,b) ((a && !b) || (!a && b))
  141. #define    if_T    tst = dirfind_tst(FK_(j), &fz, TRUE);\
  142.         if (XOR(tst,unfind))
  143. #define    LOOP    for (j = dirfind_nxt(curfile,forward), k = numfiles; k > 0;\
  144.             j = dirfind_nxt(j,forward), k--)
  145. #define    BIT_1    1        /* Use this bit via 'dirent_misc'    */
  146.  
  147.     if (each)        /* Multiple action ?    */
  148.     {
  149.         dirent_misc (-1, BIT_1);    /* Reset all '.fmisc'    */
  150.         if (strchr(FIND_TEXT,'*') || strchr(FIND_TEXT,'%')
  151.         ||  strchr(Fpath, '*'))
  152.             dds_while (nullC);
  153.  
  154.         for (j = 0; j < numfiles; j++)
  155.         {
  156.             if_T
  157.                 dirent_misc (j, BIT_1);
  158.         }
  159.         LOOP
  160.         {
  161.             if (DELETED(j))        continue;
  162.             dds_while(nullC);
  163.             if (FK(j).fmisc & BIT_1)
  164.             {
  165.                 (*each)(j, &flag);
  166.                 found_any++;
  167.                 if (!flag)        break;
  168.             }
  169.         }
  170.         dirent_misc (-1, BIT_1);    /* cleanup after use    */
  171.     }
  172.     else
  173.     {
  174.         LOOP
  175.         {
  176.             if (DELETED(j))        continue;
  177.             if_T            return (j);
  178.         }
  179.     }
  180.  
  181.     if (must_find && !found_any)
  182.     {
  183.         char    fullname[MAX_PATH];
  184.         warn ("Not found: %s", dirent_glue (fullname, &fz));
  185.     }
  186.  
  187.     if (found_any)    return (found_any);
  188.     else        return (-2);
  189. }
  190.  
  191. /*
  192.  * Split the given DCLARG-pattern into a FILENT-block, so that the pathname,
  193.  * filename, type and version will be readily accessible for use in the
  194.  * directory-search.  This routine is also used to partly-parse the search
  195.  * target when "?FIND" is executed.
  196.  */
  197. void    dirfind_chop (
  198.     DCLARG    *find_spec,
  199.     FILENT    *fz_,
  200.     PATHNT    *pz_,
  201.     char    *Fpath, char *Fname, char *Ftype)
  202. {
  203.     int    len    = 0,
  204.         j,
  205.         version;    /* value if version null or "*"        */
  206.  
  207. #define    CPY(to)    if (len > 0) strncpy(to, &FIND_TEXT[j], len);\
  208.         to[len] = EOS; j += len
  209.  
  210.     j    = 0;
  211.     len    = find_spec->dcl$b_node
  212.         + find_spec->dcl$b_dev
  213.         + find_spec->dcl$b_dir;            /* Directory-path*/
  214.     CPY(Fpath);
  215.  
  216.     len    = find_spec->dcl$b_name + NAME_DOT;    /* name with trailing '.' */
  217.     CPY(Fname);
  218.     j    -= NAME_DOT;        /* '.' is normally counted in type */
  219.  
  220.     len    = find_spec->dcl$b_type - 1;    j++;    /* Don't use "." */
  221.     CPY(Ftype);
  222.  
  223.     version    = scanver (&FIND_TEXT[j], find_spec->dcl$b_ver);
  224.  
  225.     /*
  226.      * If pathname was not explicitly given, make the entire path wild.
  227.      */
  228.     if (dirfind_notexp(find_spec))
  229.         strcpy (Fpath, "*");
  230.  
  231.     /*
  232.      * Set up structure so we can use 'dirfind_tst':
  233.      */
  234.     fz_->fpath_ = pz_;    pz_->path_text = Fpath;
  235.     fz_->fname  = Fname;
  236.     fz_->ftype  = Ftype;
  237.     fz_->fvers  = version;
  238. }
  239.  
  240. /*
  241.  * Make an index to the next item to test:
  242.  */
  243. int    dirfind_nxt (int j, int forward)
  244. {
  245.     if (forward)
  246.     {
  247.         if ((++j) >= numfiles)    j = 0;
  248.     }
  249.     else
  250.     {
  251.         if ((--j) <  0)        j = numfiles-1;
  252.     }
  253.     return (j);
  254. }
  255.  
  256. /*
  257.  * Return true iff the pathname of the indicated DCLARG-structure was
  258.  * not explicit.  Inexplicit pathnames within FLIST are treated as a special
  259.  * type of wildcard.
  260.  */
  261. int    dirfind_notexp (DCLARG *find_spec)
  262. {
  263.     return (!(FIND_FNB & (NAM$M_EXP_DIR + NAM$M_EXP_DEV)));
  264. }
  265.  
  266. /*
  267.  * Test the entry 'z' against the wildcard and exact matches in 'zref':
  268.  */
  269. int    dirfind_tst (
  270.     FILENT    *z,
  271.     FILENT    *zref,
  272.     int    lookup)    /* TRUE if we permit lookup for relative versions */
  273. {
  274.     FILENT    ztmp;
  275.     char    relnam[NAM$C_MAXRSS];
  276.     char    absnam[NAM$C_MAXRSS];
  277.  
  278.     if (strwcmp(zPATHOF(zref), zPATHOF(z)))    return (FALSE);
  279.     if (strwcmp(zref->fname,   z->fname))    return (FALSE);
  280.     if (strwcmp(zref->ftype,   z->ftype))    return (FALSE);
  281.  
  282.     /*
  283.      * If the reference version is a wild-card, or if there is an exact
  284.      * match (only possible for versions greater than zero), return
  285.      * true immediately.
  286.      */
  287.     if (zref->fvers == WILD_VER
  288.     ||  zref->fvers == z->fvers)
  289.         return (TRUE);
  290.     /*
  291.      * Otherwise, if the reference version is negative (i.e., relative),
  292.      * construct a temporary copy of the test-name, and see if the given
  293.      * relative version is identical with the test-name.  To permit re-use
  294.      * (e.g., for read-list pruning), we permit the argument 'lookup' to
  295.      * suppress this clause.
  296.      *
  297.      * patch: This is slow, but works !!
  298.      */
  299.     else if (zref->fvers <= 0 && lookup)
  300.     {
  301.         ztmp    = *z;
  302.         ztmp.fvers = zref->fvers;
  303.         dirent_glue (relnam, &ztmp);
  304.         if (! $VMS_STATUS_SUCCESS (dirent_look (absnam, relnam)))
  305.             return (FALSE);
  306.         dirent_chop (&ztmp, absnam, 0);
  307.         return (ztmp.fvers == z->fvers);
  308.     }
  309.     else
  310.         return (FALSE);
  311. }
  312.