home *** CD-ROM | disk | FTP | other *** search
/ The Developer Connection…ice Driver Kit for OS/2 3 / DEV3-D1.ISO / source / util2src / speclist.c32 < prev    next >
Encoding:
Text File  |  1992-09-21  |  51.7 KB  |  1,177 lines

  1. /*============================================================================*
  2.  * module: speclist.c - File specification list processing.   OS/2 Version
  3.  *
  4.  * (C)Copyright IBM Corporation, 1991, 1992               Brian E. Yoder
  5.  *
  6.  * A file specification is composed of '[d:][path]name'.  The first part
  7.  * (drive and path) is optional and is known as the path.  The second part
  8.  * is a file name.  This name can contain pattern-matching characters like
  9.  * those that are supported by the AIX shell.
  10.  *
  11.  * This module contains subroutines to give a calling program a findfirst/
  12.  * findnext-like capability with some major enhancements: support pattern-
  13.  * matching characters as the AIX shell does, support more than one file
  14.  * specification, and allow a program to traverse a single directory only
  15.  * once no matter how many file specifications there are.
  16.  *
  17.  * The slmake() subroutine builds a "specification list" data structure
  18.  * based on the file specification(s) given.  The slrewind() subroutine
  19.  * gets your program ready to look for files that match the file
  20.  * specifications.  The slmatch() subroutine works like an enhanced version
  21.  * of DosFindNext() -- it gets the next file that matches the file
  22.  * specifications stored in the specification list.  It is called repeatedly
  23.  * to get all matching files.
  24.  *
  25.  * Once slmatch() has been used to find all matching filenames, slnotfound()
  26.  * can be called to display on stderr a list of all file specifications that
  27.  * did not match any files.
  28.  *
  29.  * Programs that use these subroutines should be linked with a module
  30.  * definition file that contains a NEWFILES statement if they want to
  31.  * match files on "non 8.3" file systems, such as HPFS.
  32.  *
  33.  * The FINFO label is #defined as FILEFINDBUF and is a shorter name to type.
  34.  *
  35.  * 04/05/91 - Created.
  36.  * 04/19/91 - Initial version.
  37.  * 04/30/91 - Ported to OS/2, using <os2.h> instead of <doscalls.h>.  I needed
  38.  *            to make slmatch()'s 'attrib' var USHORT instead of char.  I also
  39.  *            did not set the _A_VOLID bit, since OS/2 doesn't support it.
  40.  * 05/06/91 - Added support for recursive directory descent by slmatch().
  41.  * 05/09/91 - Added support for directory name expansion by slmake().
  42.  * 04/13/92 - Set SLPATH's hpfs flag to TRUE for HPFS filesystems.
  43.  * 07/22/92 - Convert function definitions to the new style.
  44.  * 09/19/92 - Added support for the bpathlen field of SLPATH.
  45.  *============================================================================*/
  46.  
  47. #include <stdio.h>
  48. #include <stdlib.h>
  49. #include <string.h>
  50. #include <malloc.h>
  51. #include <sys/types.h>
  52.  
  53. #include "util.h"                   /* Also includes <os2.h> */
  54.  
  55. #define  MAX_CPY 1024               /* Max length of strings, during strcpy() */
  56. #define  MAX_LEN 2048               /* Max buffer lengths */
  57.  
  58. #define ELEN     1024               /* Length of expression buffers */
  59.  
  60. /*============================================================================*
  61.  * Static data used by slmake()
  62.  *============================================================================*/
  63.  
  64. static PATH_NAME *pn = NULL;        /* Pointer to path/name structure */
  65.  
  66. static char fullname[MAX_LEN+1];    /* Full d:path\name string */
  67. static char path[MAX_LEN+1];        /* The d:path portion of a full filename */
  68. static char name[MAX_LEN+1];        /* The name portion of a full filename */
  69. static char ntmp[MAX_LEN+1];        /* A temp storage area for names */
  70.  
  71. /*----------------------------------------------------------------------------*
  72.  * Variable set by slmake and used by findpath().  If set to TRUE, then we
  73.  * want to create an SLPATH structure in the spec list only for each unique
  74.  * path.  If FALSE, we want to create one for each path regardless.
  75.  *----------------------------------------------------------------------------*/
  76.  
  77. static int  unique = TRUE;
  78.  
  79. /*----------------------------------------------------------------------------*
  80.  * Static pointer to file spec error: set by slmake()
  81.  *----------------------------------------------------------------------------*/
  82.  
  83. static char *error_spec = "";       /* Initialize to zero-length string */
  84.  
  85. /*----------------------------------------------------------------------------*
  86.  * Data used to expand patterns and compile regular expressions
  87.  *----------------------------------------------------------------------------*/
  88.  
  89. static char  eexpr[ELEN];           /* Full regular (expanded) expression */
  90. static char  cexpr[ELEN];           /* Compiled expression */
  91.  
  92. /*----------------------------------------------------------------------------*
  93.  * Pointers used by slmake() and the subroutines it calls.  They define the
  94.  * beginning and end of the current singly-linked list of SLPATH structures.
  95.  *----------------------------------------------------------------------------*/
  96.  
  97. static SLPATH *firstpath = NULL;    /* First/last paths in the singly-linked */
  98. static SLPATH *lastpath = NULL;     /* list of SLPATH structures */
  99.  
  100. /*============================================================================*
  101.  * Data used by slrewind() and slmatch() only!  The slmatch() subroutine
  102.  * contains a state machine, and this data preserves state information
  103.  * between calls.  No other programs should modify this information!
  104.  *============================================================================*/
  105.  
  106. enum MATCH_STATES {
  107.  
  108.         MDone,                      /* Done: All filespecs have been checked */
  109.         MFindFirst,                 /* Issue a DOS findfirst on current path */
  110.         MFindNext,                  /* Issue a DOS findnext on current path */
  111.         MCheckMatch                 /* Check current directory entry for match */
  112.  
  113. };
  114.  
  115. static int     MatchState = MDone;  /* Initial state is 'done', for safety */
  116. static SLPATH *nextpath = NULL;     /* Pointer updated only by slmatch() */
  117. static ushort  slflags;             /* Flags used to restrict slmatch() */
  118. static ushort  sl_recurse = FALSE;  /* Recursively descend directories? */
  119. static HDIR    findh = HDIR_CREATE; /* Handle returned by DosFindFirst() */
  120. static FINFO   finfo;               /* File information structure */
  121.  
  122. /*============================================================================*
  123.  * Prototypes for static functions used only within this module
  124.  *============================================================================*/
  125.  
  126. static SLPATH    *addlist      ( char *, char *, char *, int );
  127. static SLPATH    *addpath      ( char * );
  128. static SLPATH    *insertpath   ( SLPATH *, char * );
  129. static SLNAME    *addname      ( SLPATH *, char *, char *, int );
  130. static SLPATH    *findpath     ( char * );
  131.  
  132. static void       dumppath     ( SLPATH * );
  133. static void       dumpname     ( SLNAME * );
  134.  
  135. static int        matchit      ( FINFO *, ushort );
  136.  
  137. //===========================================================================*
  138. //
  139. // From: <bsedos.h> in 2.0 toolkit
  140. //
  141. //  APIRET APIENTRY  DosFindFirst(
  142. //          PSZ    pszFileSpec,
  143. //          PHDIR  phdir,
  144. //          ULONG  flAttribute,
  145. //          PVOID  pfindbuf,
  146. //          ULONG  cbBuf,
  147. //          PULONG pcFileNames,
  148. //          ULONG  ulInfoLevel);   /* FIL_STANDARD */
  149. //
  150. //  APIRET APIENTRY  DosFindNext(
  151. //          HDIR   hDir,
  152. //          PVOID  pfindbuf,
  153. //          ULONG  cbfindbuf,
  154. //          PULONG pcFilenames);
  155. //
  156. //  APIRET APIENTRY  DosFindClose(HDIR hDir);
  157. //
  158. // From: <bsedos.h> in 1.3 toolkit
  159. //
  160. //  USHORT APIENTRY DosFindFirst(
  161. //          PSZ pszFSpec,          /* path name of files to be found              */
  162. //          PHDIR phdir,           /* directory handle                            */
  163. //          USHORT usAttr,         /* attribute used to search for the files      */
  164. //          PFILEFINDBUF pffb,     /* result buffer                               */
  165. //          USHORT cbBuf,          /* length of result buffer                     */
  166. //          PUSHORT pcSearch,      /* number of matching entries in result buffer */
  167. //          ULONG ulReserved);     /* reserved (must be 0)                        */
  168. //
  169. //  USHORT APIENTRY DosFindNext(
  170. //          HDIR hdir,                      /* directory handle          */
  171. //          PFILEFINDBUF pffb,              /* result buffer             */
  172. //          USHORT cbBuf,                   /* length of result buffer   */
  173. //          PUSHORT pcSearch);              /* number of entries to find */
  174. //
  175. //  USHORT APIENTRY DosFindClose(
  176. //          HDIR hdir);                     /* directory handle */
  177. //===========================================================================*
  178.  
  179. /*============================================================================*
  180.  * slmake() - Make specification list.
  181.  *
  182.  * REMARKS:
  183.  *   The slmake() subroutine is used to process a list of file specifications
  184.  *   and build a "specification list".
  185.  *
  186.  *   Once the specification list is built, you can use slrewind() and slmatch()
  187.  *   to find matching files.  These subroutines are analogous to the
  188.  *   dosfindfirst() and findnext() subroutines.  However, they work with the
  189.  *   specification list and allow you to use pattern-matching instead of the
  190.  *   "wildcard" metacharacters.
  191.  *
  192.  *   Point 'specv' to an array of file specification pointers and set 'specc'
  193.  *   to the number of pointers in this array (like 'argv' and 'argc').  Point
  194.  *   the 'pathnode' variable to a location in which a pointer to a
  195.  *   specification list pointer can be stored.
  196.  *
  197.  *   If 'uniq' is TRUE, then the specification list will contain only one
  198.  *   SLPATH structure for each unique path in the list of file specifications.
  199.  *   If 'uniq' is FALSE, then there will be one SLPATH structure for each
  200.  *   file specification.  This variable affects the order in which slmatch()
  201.  *   finds files.  It is used to support the -g flag of the 'ls' command.
  202.  *   See the ls.c file for more information.
  203.  *
  204.  *   If 'expand' is TRUE, then for each file specification that is the name
  205.  *   of an existing directory, this subroutine will concatenate a path
  206.  *   separator and a "*", so that slmatch() will match all files within that
  207.  *   directory.  If 'expand' is FALSE, then directory names are left as-is,
  208.  *   so slmatch() will match the only directory and not the files within it.
  209.  *   In this case, however, you will an "invalid filespec" error for file
  210.  *   specifications like "c:" and "\".
  211.  *
  212.  * NOTES ON FREEING MEMORY:
  213.  *   This subroutine builds a specification list for all file specifications
  214.  *   and stores them in a spec list.  The program uses malloc() to store the
  215.  *   information in the list.  To free the memory, you only need to free the
  216.  *   memory addresses by pointers to the SLNAME and SLPATH structures: the
  217.  *   character strings for a structure are stored just past the structure
  218.  *   (in the same malloc'd block as the structure).
  219.  *
  220.  *   Note that if an SLPATH structure has its 'inserted' member as TRUE, you
  221.  *   should only free the storage associated with the SLPATH structure itself.
  222.  *   Any SLNAME structures it points to are shared by an SLPATH structure
  223.  *   whose 'inserted' member is FALSE.  See the insertpath() subroutine.
  224.  *
  225.  * RETURNS:
  226.  *   0    : successful.  A pointer to the start of the specification list is
  227.  *          copied to the location pointed to by *speclist.
  228.  *
  229.  *   Other: Cannot compile a name specification.  Use slerrspec() to get a
  230.  *          pointer to the name specification that could not be compiled.
  231.  *          The error code is one returned by either rexpand() or rcompile().
  232.  *
  233.  * FORMAT OF A SPECIFICATION LIST:
  234.  *   The slmake() subroutine combines all file specifications in a "spec
  235.  *   list".  This consists of a singly-linked list of SLPATH structures.
  236.  *   Each SLPATH structure defines a 'd:path' and also points to a singly-
  237.  *   linked list of SLNAME structures for that path.
  238.  *
  239.  *   For example, assume the following list of file specifications.  Note that
  240.  *   the 'd:path' part of the first two specifications is a null string:
  241.  *
  242.  *       *.c   *.h   \lib\*.lib   \lib\*.obj   \include\*.h
  243.  *
  244.  *   There are 3 unique 'd:path' strings: "" (null), "\lib\", and "\include\".
  245.  *   Therefore, our specification list would look conceptually like this
  246.  *   (if 'uniq' is TRUE):
  247.  *
  248.  *       "" (null) ----------------------------------> "*.c"
  249.  *           |                                           |
  250.  *       "\lib" --------------------> ".lib"           "*.h"
  251.  *           |                           |
  252.  *       "\include" ---> "*.h"        "*.obj"
  253.  *
  254.  *   The slmake() subroutine can be used to build this list.  For this
  255.  *   example, it stores the 3 'd:path' strings in a list of SLPATH structures.
  256.  *   It stores the lists of name specifications in 3 lists of SLNAME structures.
  257.  *
  258.  *   Each SLNAME structure contains a pointer to the name string (i.e. "*.c").
  259.  *   The slmake() subroutine also expands the name string into a regular
  260.  *   expression using rexpand() and compiles it using rcompile().  It stores
  261.  *   the compiled expression in the SLNAME structure -- you can use rmatch()
  262.  *   to compare it with a filename.
  263.  *
  264.  *   Each SLNAME structure also contains a count field.  Your program can use
  265.  *   this field to see how many files matched a given '[d:path]name'.
  266.  *============================================================================*/
  267.  
  268. int slmake(
  269.  
  270. SLPATH **speclist ,                 /* Pointer to spec list pointer */
  271. int   uniq        ,                 /* Build an SLPATH only for unique path? */
  272. int   expand      ,                 /* Expand directory names? */
  273. int   specc       ,                 /* No. of file specifications */
  274. char **specv      )                 /* Pointer to array of file specifications */
  275.  
  276. {
  277.   int rc;                           /* Storage for return codes */
  278.  
  279.   SLPATH *slp;                      /* Pointer to path info */
  280.   SLNAME *sln;                      /* Pointer to name info */
  281.  
  282.   char *next_eexpr;                 /* Pointer to next expanded expression */
  283.   char *next_cexpr;                 /* Pointer to next compiled expression */
  284.   int   cexpr_len;                  /* Length of compiled expression */
  285.  
  286.   firstpath = NULL;                 /* Initialize linked list to 'empty' */
  287.   lastpath = NULL;
  288.  
  289.   unique = uniq;                    /* Set the static 'unique' variable */
  290.  
  291.  /*---------------------------------------------------------------------------*
  292.   * Loop for each file specification
  293.   *---------------------------------------------------------------------------*/
  294.  
  295.   while (specc != 0)                /* For each filespec: */
  296.   {
  297.     /*-----------------------------------------------------*
  298.      * Decopmose each filespec into path and name portions
  299.      *-----------------------------------------------------*/
  300.  
  301.      strncpy(fullname, *specv, MAX_CPY); /* Copy filespec into buffer */
  302.      if (isdir(fullname) == TRUE)        /* If fullname is a directory: */
  303.         if (expand)                           /* If we're supposed to expand it: */
  304.            pathcat(fullname, "*");                 /* Append "*" to it */
  305.  
  306.      pn = decompose(fullname);           /* Now: decompose the fullname */
  307.  
  308.      memcpy(path, pn->path,              /* Store path portion and terminate it */
  309.                   pn->pathlen);
  310.      *(path+pn->pathlen) = '\0';
  311.  
  312.      memcpy(name, pn->name,              /* Store name portion and terminate it */
  313.                   pn->namelen);
  314.      *(name+pn->namelen) = '\0';
  315.  
  316.     /*-----------------------------------------------------*
  317.      * Expand name portion into a regular expression and
  318.      * store in 'exxpr[]'
  319.      *-----------------------------------------------------*/
  320.  
  321.      rc = rexpand(name, eexpr, &eexpr[ELEN+1], &next_eexpr);
  322.      if (rc != 0)                        /* If error: store pointer to */
  323.      {                                   /* original file spec and return */
  324.         error_spec = *specv;
  325.        *speclist = firstpath;                 /* Also: copy pointer to list */
  326.         return(rc);
  327.      }
  328.  
  329.     /*-----------------------------------------------------*
  330.      * Compile 'eexpr' and store in 'cexpr[]'
  331.      *-----------------------------------------------------*/
  332.  
  333.      strupr(eexpr);                      /* Convert expanded expr to uppercase */
  334.  
  335.      rc = rcompile(eexpr, cexpr, &cexpr[ELEN+1], '\0', &next_cexpr);
  336.      if (rc != 0)                        /* If error: store pointer to */
  337.      {                                   /* original file spec and return */
  338.         error_spec = *specv;
  339.        *speclist = firstpath;                 /* Also: copy pointer to list */
  340.         return(rc);
  341.      }
  342.  
  343.      cexpr_len = next_cexpr - cexpr;     /* Store length */
  344.  
  345.     /*-----------------------------------------------------*
  346.      * Add path/name to the specification list
  347.      *-----------------------------------------------------*/
  348.  
  349.      slp = addlist(path, name, cexpr, cexpr_len);
  350.      if (slp == NULL)
  351.         return(REGX_MEMORY);
  352.  
  353.      specc--;                            /* Decrement array counter, and */
  354.      specv++;                            /* Point to next filespec pointer */
  355.   }
  356.  
  357.   *speclist = firstpath;            /* Copy pointer to start of list */
  358.   return(0);                        /* Return */
  359. }
  360.  
  361. /*============================================================================*
  362.  * slerrspec() - Get error file specification.
  363.  *
  364.  * REMARKS:
  365.  *   Returns a pointer to the original file specification that caused the
  366.  *   last error (if any) encountered by a call to mklist().
  367.  *
  368.  * RETURNS:
  369.  *   A pointer to the file specification.
  370.  *============================================================================*/
  371.  
  372. char *slerrspec()
  373. {
  374.   return(error_spec);               /* Return pointer */
  375. }
  376.  
  377. /*============================================================================*
  378.  * sldump() - Dumps a specification list.
  379.  *
  380.  * REMARKS:
  381.  *   You should pass to this subroutine a pointer to the first SLPATH structure
  382.  *   in the specification linked list.  This pointer is the one that is copied
  383.  *   to your program by the slmake() subroutine.
  384.  *
  385.  *   This subroutine dumps each data structure in the specification list on
  386.  *   stdout.
  387.  *
  388.  * RETURNS:
  389.  *   Nothing.
  390.  *============================================================================*/
  391.  
  392. void  sldump(
  393.  
  394. SLPATH *pdata )                     /* Pointer to specification list */
  395.  
  396. {
  397.   SLNAME *ndata;                    /* Pointer to a name data structure */
  398.  
  399.   while (pdata != NULL)             /* For each path structure: */
  400.   {
  401.      dumppath(pdata);                    /* Dump the path structure */
  402.      ndata = pdata->firstname;           /* Point to first name structure */
  403.      while (ndata != NULL)               /* And for each name structure: */
  404.      {
  405.         dumpname(ndata);                      /* Dump it */
  406.         ndata = ndata->next;                  /* Go to next name structure */
  407.      }                                   /* Done with path's name structures */
  408.      pdata = pdata->next;                /* Go to next path structure */
  409.   }                                 /* Done with path structures */
  410.  
  411.   return;
  412. }
  413.  
  414. /*============================================================================*
  415.  * slrewind() - Goes to beginning of specification list.
  416.  *
  417.  * REMARKS:
  418.  *   This subroutine initializes the data structures and state information used
  419.  *   by the slmatch() subroutine.  You should pass to this subroutine the
  420.  *   pointer returned by the slmake() subroutine.
  421.  *
  422.  *   The 'mflags' restrict the names that slmatch() will attempt to match.
  423.  *   Each bit represents a set of files (normal, hidden, system, directory,
  424.  *   etc.) that slmatch() will process.  See the SL_ #defines in util.h for
  425.  *   a list of possible flags.  You may inclusive OR as many of these flags
  426.  *   as desired.
  427.  *
  428.  *   The 'recurse' flag tells slmatch() whether or not to recursively descend
  429.  *   subdirectories while attempting to match a file specification.
  430.  *
  431.  *   After calling this subroutine, you can make repeated calls to slmatch()
  432.  *   to find all files that match each path and name combination within the
  433.  *   specification list.
  434.  *
  435.  * RETURNS:
  436.  *   Nothing.
  437.  *============================================================================*/
  438.  
  439. void  slrewind(
  440.  
  441. SLPATH *pdata   ,                   /* Pointer to specification list */
  442. ushort  mflags  ,                   /* Flags used to restrict matches */
  443. ushort  recurse )                   /* Should slmatch() recursively descend directories? */
  444.  
  445. {
  446.   nextpath = pdata;                 /* Store pointer */
  447.   MatchState = MFindFirst;          /* Initialize state machine */
  448.   slflags = mflags;                 /* Store flags */
  449.   sl_recurse = recurse;             /* Store recurse indication */
  450.  
  451.   if (findh != HDIR_CREATE)         /* If a DosFindFirst handle exists: */
  452.   {
  453.      DosFindClose(findh);                /* Close it */
  454.      findh = HDIR_CREATE;                /* And reset it */
  455.   }
  456.  
  457.   return;
  458. }
  459.  
  460. /*============================================================================*
  461.  * slmatch() - Gets next matching directory entry.
  462.  *
  463.  * REMARKS:
  464.  *   This subroutine finds the next directory entry that matches the file
  465.  *   specifications in the specification list.
  466.  *
  467.  *   A program normally will call slmake() to build a specification list.
  468.  *   If there are no errors, it calls slrewind().  Then it makes repeated
  469.  *   calls to slmatch() to find all directory entries that match the file
  470.  *   specs in the specification list.
  471.  *
  472.  * RETURNS:
  473.  *   NULL, if there are no more matching directory entries.
  474.  *
  475.  *   Otherwise, this subroutine returns a pointer to a static FINFO
  476.  *   structure that describes the matching directory entry.  It
  477.  *   also copies to your program two pointers to static data structures:
  478.  *   one to the SLPATH data structure and one to the SLNAME data structure
  479.  *   for the entry.
  480.  *
  481.  * NOTES:
  482.  *   The full pathname of the file can be found by concatenating the
  483.  *   pathname found in the SLPATH structure with the filename found
  484.  *   in the FINFO structure.  Use the pathcat() subroutine to do this,
  485.  *   since it adds a path separator when necessary.
  486.  *
  487.  *   The FINFO, SLPATH, and SLNAME structures are for your reference only:
  488.  *   Do not modify these structures for any reason, or this subroutine may
  489.  *   not perform as expected.
  490.  *
  491.  * INTERNAL NOTES:
  492.  *   If we told slrewind() that we want to recursively descend directories
  493.  *   to look for names, then:  When slmatch() finds a subdirectory, it
  494.  *   builds a new SLPATH structure for it and inserts it just after the
  495.  *   current directory's SLPATH structure.  It also points the new SLPATH
  496.  *   to the list of SLNAMES for the current SLPATH.  This not only saves
  497.  *   some memory, but helps out the slpnotfound() subroutine:  If we don't
  498.  *   find a matching name in the current directory but find it sometime
  499.  *   during the directory decent (while processing the new SLPATH), then
  500.  *   we will mark the increment the SLNAME's fcount, indicating that we
  501.  *   indeed matched the filespec somewhere in the directory tree.
  502.  *============================================================================*/
  503.  
  504. FINFO *slmatch(
  505.  
  506. SLPATH  **pathdata ,                /* Ptrs to where to to copy ptrs to the */
  507. SLNAME  **namedata )                /* path and name data structures */
  508.  
  509. {
  510.   int     rc;                       /* Return code storage */
  511.   int     found_match;              /* Did we find a match? */
  512.  
  513.   ULONG   scnt;                     /* Count (was USHORT for 1.3) */
  514.  
  515.   FTM     ftm;                      /* File time structure */
  516.   ULONG   attrib;                   /* Attribute (was USHOT for 1.3) */
  517.   SLNAME *pname;                    /* Pointer to name data structure */
  518.   SLNAME *fndname;                  /* Pointer to another name data structure */
  519.   SLPATH *p_slpath;                 /* Pointer to path info structure */
  520.  
  521.   *pathdata = NULL;                 /* Initially: copy NULL pointers back */
  522.   *namedata = NULL;                 /* to the calling program */
  523.  
  524.   attrib = 0L;                      /* Set attribute to zero, then: */
  525.   attrib = _A_NORMAL  |             /* Set up attribute for findfirst */
  526.            _A_RDONLY  |             /* These labels are from <dos.h> */
  527.            _A_HIDDEN  |
  528.            _A_SYSTEM  |
  529.         /* _A_VOLID   |  */               /* OS/2 doesn't support _A_VOLID */
  530.            _A_SUBDIR  |
  531.            _A_ARCH;
  532.  
  533.   if (nextpath == NULL)             /* For safety: If we have a NULL current */
  534.      return(NULL);                  /* path pointer: Don't bother! */
  535.  
  536.  /*---------------------------------------------------------------------------*
  537.   * This state machine loops until it either finds a matching file or comes
  538.   * to the end (and can find no more matching files).  When either of these
  539.   * events occur, the state machine issues a return() from the subroutine.
  540.   *---------------------------------------------------------------------------*/
  541.  
  542.   for (;;)                          /* State machine loop */
  543.   {
  544.      switch (MatchState)
  545.      {
  546.        /*-----------------------------------------------*
  547.         * STATE: Done: All filespecs have been checked
  548.         *-----------------------------------------------*/
  549.         case MDone:
  550.            if (findh != HDIR_CREATE) /* If a DosFindFirst handle exists: */
  551.            {
  552.               DosFindClose(findh);       /* Close it */
  553.               findh = HDIR_CREATE;       /* And reset it */
  554.            }
  555.            return(NULL);            /* Return, and stay in same state */
  556.            break;
  557.  
  558.        /*-----------------------------------------------*
  559.         * STATE: Issue a DOS findfirst on current path
  560.         *-----------------------------------------------*/
  561.         case MFindFirst:
  562.            if (nextpath == NULL)    /* If current path pointer is NULL: */
  563.            {
  564.               MatchState = MDone;        /* Then we're done */
  565.               return(NULL);              /* Return */
  566.            }
  567.  
  568.            strncpy(fullname,        /* Build "path\*.*" string in fullname[] */
  569.                    nextpath->path,  /* For the DOS findfirst command */
  570.                    MAX_CPY);
  571.            pathcat(fullname, "*.*");
  572.  
  573. //.............................................................................
  574. //         rc = findfirst(fullname, /* Find first DOS directory entry for path */
  575. //                        attrib, &finfo);
  576. //.............................................................................
  577.  
  578.            if (findh != HDIR_CREATE) /* If a DosFindFirst handle exists: */
  579.            {
  580.               DosFindClose(findh);       /* Close it */
  581.               findh = HDIR_CREATE;       /* And reset it */
  582.            }
  583.            scnt = 1;                /* Find one at a time */
  584.            rc = DosFindFirst(fullname,
  585.                    &findh, attrib,
  586.                    &finfo, sizeof(FINFO),
  587.                    &scnt,
  588.                    (ULONG)FIL_STANDARD);  /* Was 0L for 1.3 */
  589.  
  590.            if ((rc != 0) || (scnt == 0)) /* If findfirst failed: */
  591.            {
  592.               nextpath = nextpath->next; /* Go to next path in list */
  593.               MatchState = MFindFirst;   /* And repeat the findfirst state */
  594.            }
  595.            else                     /* If findfirst was successful: */
  596.            {
  597.               MatchState = MCheckMatch;  /* Check to see if we have a match */
  598.            }
  599.            break;
  600.  
  601.        /*-----------------------------------------------*
  602.         * STATE: Issue a DOS findnext on current path
  603.         *-----------------------------------------------*/
  604.         case MFindNext:
  605. //.............................................................................
  606. //         rc = findnext(&finfo);   /* Find next DOS directory entry for path */
  607. //.............................................................................
  608.  
  609.            scnt = 1;                /* Find one at a time */
  610.            rc = DosFindNext(findh,
  611.                    &finfo, sizeof(FINFO),
  612.                    &scnt);
  613.  
  614.            if ((rc != 0) || (scnt == 0)) /* If findnext failed: */
  615.            {
  616.               nextpath = nextpath->next; /* Go to next path in list */
  617.               MatchState = MFindFirst;   /* And repeat the findfirst state */
  618.            }
  619.            else                     /* If findnext was successful: */
  620.            {
  621.               MatchState = MCheckMatch;  /* Check to see if we have a match */
  622.            }
  623.            break;
  624.  
  625.        /*-----------------------------------------------*
  626.         * STATE: Check current directory entry for match
  627.         *-----------------------------------------------*
  628.         * We compare every SLNAME that is linked to the
  629.         * current path.  Therefore, when we're done with
  630.         * the spec list, we will know exactly which
  631.         * name specs matched no files.
  632.         *-----------------------------------------------*/
  633.         case MCheckMatch:
  634.            found_match = FALSE;     /* We haven't found a match yet */
  635.  
  636.            if (sl_recurse)          /* If we're to recursively search subdirs: */
  637.            {
  638.               if ( ((finfo.attrFile      /* If this entry is a subdirectory, */
  639.                     & _A_SUBDIR) != 0) &&     /* But not . or .. : */
  640.                     (strcmp(finfo.achName, ".")  != 0) &&
  641.                     (strcmp(finfo.achName, "..") != 0))
  642.               {
  643.                  strncpy(ntmp,                /* Build path + name of subdir */
  644.                          nextpath->path,      /* by copying path string and */
  645.                          MAX_CPY);            /* adding the subdir name */
  646.                  pathcat(ntmp, finfo.achName);
  647.                  p_slpath = insertpath(       /* Insert subdir's new path */
  648.                          nextpath, ntmp);     /* structure in list */
  649.  
  650.                  if (p_slpath != NULL)        /* If we inserted the path ok: */
  651.                  {                            /* Then set its list of names */
  652.                     p_slpath->firstname = nextpath->firstname; /* to those of */
  653.                     p_slpath->lastname = nextpath->lastname;   /* the current path */
  654.                  }
  655.                  else
  656.                  {
  657.                     /* For now: ignore malloc error from inserting new path */
  658.                     /* Just keep returning as many matching names as we can */
  659.                  }
  660.               }                          /* End of block to process directory */
  661.            }                        /* End of block to support recursive descent */
  662.  
  663.            if (matchit(&finfo, slflags))
  664.            {                        /* If we want to try and match the file: */
  665.               fndname = NULL;          /* Set up loop, then: */
  666.               pname = nextpath->firstname;
  667.               while (pname != NULL)    /* Loop to check each name spec for path: */
  668.               {
  669.                  strncpy(ntmp,              /* Copy name into temp buffer, and */
  670.                          finfo.achName,     /* convert name to uppercase (for */
  671.                          MAX_CPY);          /* case-insensitive comparison) */
  672.                  strupr(ntmp);
  673.  
  674.                  rc = rmatch(pname->ecname, /* Compare reg expression with name */
  675.                              ntmp);         /* in directory entry */
  676.                  if (rc == RMATCH)          /* If we have a match: */
  677.                  {
  678.                     found_match = TRUE;          /* Remember that we found match */
  679.                     pname->fcount++;             /* Bump match counter for the name */
  680.                     if (fndname == NULL)         /* Store only the first SLNAME */
  681.                        fndname = pname;          /* structure that matched */
  682.                  }
  683.                  pname = pname->next;       /* No match: try next name spec */
  684.               } /* end of while loop to check each name spec */
  685.            } /* end of if (matchit) */
  686.  
  687.            MatchState = MFindNext;      /* Set next state */
  688.            if (found_match == TRUE)     /* If we found a match: */
  689.            {
  690.               *pathdata = nextpath;        /* Copy path and name pointers */
  691.               *namedata = fndname;         /* to calling program */
  692.               return(&finfo);              /* Return to caller */
  693.            }
  694.  
  695.            break;
  696.  
  697.        /*-----------------------------------------------*
  698.         * STATE: Unknown.  Return as if done!
  699.         *-----------------------------------------------*/
  700.         default:
  701.            return(NULL);
  702.            break;
  703.      }
  704.   } /* end of for loop for the state machine */
  705.  
  706.   return(NULL);                     /* We'll never get here! */
  707. }
  708.  
  709. /*============================================================================*
  710.  * slnotfound() - Prints fspecs that were not found.
  711.  *
  712.  * REMARKS:
  713.  *   You should pass to this subroutine a pointer to the first SLPATH structure
  714.  *   in the specification linked list.  This pointer is the one that is copied
  715.  *   back by the slmake() subroutine.
  716.  *
  717.  *   This subroutine should be called after the slmatch() subroutine has found
  718.  *   every file that matches those described by the specification list.
  719.  *
  720.  *   This subroutine displays on stderr each path and name that wasn't found
  721.  *   by the slmatch() subroutine
  722.  *
  723.  * RETURNS:
  724.  *   The number of names that were not found.
  725.  *============================================================================*/
  726.  
  727. long slnotfound(
  728.  
  729. SLPATH *pdata )                     /* Pointer to specification list */
  730.  
  731. {
  732.   SLNAME *ndata;                    /* Pointer to a name data structure */
  733.   long    cnt;                      /* Counter */
  734.  
  735.   cnt = 0L;                         /* Initialize counter */
  736.  
  737.   while (pdata != NULL)             /* For each path structure: */
  738.   {
  739.      if (pdata->inserted == FALSE)       /* If this entry wasn't inserted by */
  740.      {                                   /* a recursive directory descent: */
  741.         ndata = pdata->firstname;             /* Point to first name structure */
  742.         while (ndata != NULL)                 /* And for each name structure: */
  743.         {
  744.            if (ndata->fcount == 0L)                /* If name's match count is zero: */
  745.            {
  746.               strcpy(ntmp, pdata->path);              /* No files matched: display */
  747.               pathcat(ntmp, ndata->name);             /* path and name that didn't */
  748.               fprintf(stderr, "%s not found\n", ntmp);   /* match */
  749.               cnt++;                                  /* And bump the counter */
  750.            }
  751.            ndata = ndata->next;                    /* Go to next name structure */
  752.         }                                   /* Done with path's name structures */
  753.      }
  754.      pdata = pdata->next;                /* Go to next path structure */
  755.   }                                 /* Done with path structures */
  756.  
  757.   return(cnt);                      /* Return count of names not found */
  758. }
  759.  
  760. /*============================================================================*
  761.  * addlist() - Add a path and name to the specification list.
  762.  *
  763.  * REMARKS:
  764.  *   If an SLPATH structure already exists for the specified 'newpath', then
  765.  *   the 'newname' is added to the existing structure.  Otherwise, a new
  766.  *   SLPATH structure is created for the new path and the new name is added
  767.  *   to it.
  768.  *
  769.  *   If the static 'unique' variable is FALSE, then a new SLPATH structure
  770.  *   is created anyway!
  771.  *
  772.  * RETURNS:
  773.  *   A pointer to the SLPATH structure for the path.  If we run out of
  774.  *   memory, a NULL pointer is returned.
  775.  *============================================================================*/
  776.  
  777. static SLPATH *addlist(
  778.  
  779. char   *newpath ,                   /* New path's string */
  780. char   *newname ,                   /* New path's name string */
  781. char   *newregx ,                   /* Pointer to (and length of) the */
  782. int     newlen  )                   /* compiled regular expression for name */
  783.  
  784. {
  785.   SLPATH *p_slpath;                 /* Pointer to path info structure */
  786.   SLNAME *p_slname;                 /* Pointer to name info structure */
  787.  
  788.   p_slpath = findpath(newpath);     /* See if path entry already exists */
  789.   if (p_slpath == NULL)             /* If path doesn't exist: */
  790.   {
  791.      p_slpath = addpath(newpath);        /* Add new path structure */
  792.      if (p_slpath == NULL)               /* If we ran out of memory: */
  793.         return(NULL);                         /* Return */
  794.   }
  795.   p_slname = addname(p_slpath,      /* Add name to list of names for this path */
  796.                      newname,
  797.                      newregx, newlen);
  798.  
  799.   if (p_slname == NULL)             /* If we ran out of memory: */
  800.      return(NULL);                       /* Return w/error indication */
  801.  
  802.   return(p_slpath);                 /* Return pointer */
  803. }
  804.  
  805. /*============================================================================*
  806.  * addpath() - Adds a new path data structure.
  807.  *
  808.  * REMARKS:
  809.  *   This subroutine adds a new SLPATH structure to the end of the current
  810.  *   linked list of such structures.  It allocates a block of memory large
  811.  *   enough to hold both the path structure and the path string.
  812.  *
  813.  * RETURNS:
  814.  *   A pointer to the new path structure, or NULL if there isn't enough memory.
  815.  *============================================================================*/
  816.  
  817. static SLPATH *addpath(
  818.  
  819. char   *newpath )                   /* New path's name */
  820.  
  821. {
  822.   int     totallen;                 /* Total length needed for memory block */
  823.   char   *memblock;                 /* Pointer to allocated memory */
  824.  
  825.   SLPATH *p_slpath;                 /* Pointer to path info structure */
  826.   char   *p_path;                   /* Pointers to strings */
  827.  
  828.  /*---------------------------------------------------------------------------*
  829.   * Allocate a single block of memory for data structure and all strings
  830.   *---------------------------------------------------------------------------*/
  831.  
  832.   totallen = sizeof(SLPATH) +       /* Calculate total size of memory block */
  833.              strlen(newpath) + 1;   /* needed to hold structure and its strings */
  834.  
  835.   memblock = malloc(totallen);      /* Allocate the memory */
  836.   if (memblock == NULL)
  837.      return(NULL);
  838.  
  839.   p_slpath = (SLPATH *)memblock;    /* Store pointer to block and to where */
  840.   p_path = memblock + sizeof(SLPATH);    /* string will be put */
  841.  
  842.   strcpy(p_path, newpath);          /* Store string in the block */
  843.  
  844.   p_slpath->next = NULL;            /* Initialize structure */
  845.   p_slpath->firstname = NULL;
  846.   p_slpath->lastname = NULL;
  847.   p_slpath->path = p_path;
  848.   p_slpath->bpathlen = strlen(p_path);
  849.  
  850.   p_slpath->hpfs = ishpfs(p_path);  /* Set whether or not it's HPFS */
  851.  
  852.   p_slpath->inserted = FALSE;       /* Mark as having not been inserted */
  853.  
  854.  /*---------------------------------------------------------------------------*
  855.   * Add the new path structure to the linked list
  856.   *---------------------------------------------------------------------------*/
  857.  
  858.   if (firstpath == NULL)            /* If list is empty: */
  859.      firstpath = p_slpath;               /* New structure is now first on list */
  860.  
  861.   if (lastpath != NULL)             /* If end-of-list ptr is not NULL: */
  862.      lastpath->next = p_slpath;     /* Point old end structure to new one */
  863.  
  864.   lastpath = p_slpath;              /* New structure is now last on list */
  865.  
  866.   return(p_slpath);                 /* Return pointer to new structure */
  867. }
  868.  
  869. /*============================================================================*
  870.  * insertpath() - Inserts a new path data structure.
  871.  *
  872.  * REMARKS:
  873.  *   This subroutine inserts a new SLPATH structure after the current SLPATH
  874.  *   structure but before the next (if any) that is linked to it now.
  875.  *
  876.  *   The new path information structure is marked as having been inserted.
  877.  *   This will allow slpnotfound() to skip over paths that have been inserted
  878.  *   as a result of a recursive subdirectory search.
  879.  *
  880.  * RETURNS:
  881.  *   A pointer to the new path structure, or NULL if there isn't enough memory.
  882.  *============================================================================*/
  883.  
  884. static SLPATH *insertpath(
  885.  
  886. SLPATH *p_curpath ,                 /* Current path's SLPATH data */
  887. char   *newpath   )                 /* New path's name */
  888.  
  889. {
  890.   int     totallen;                 /* Total length needed for memory block */
  891.   char   *memblock;                 /* Pointer to allocated memory */
  892.  
  893.   SLPATH *p_slpath;                 /* Pointer to new path info structure */
  894.   char   *p_path;                   /* Pointers to strings */
  895.  
  896.   SLPATH *p_nextpath;               /* Pointer to current next path, if any */
  897.  
  898.  /*---------------------------------------------------------------------------*
  899.   * Allocate a single block of memory for data structure and all strings
  900.   *---------------------------------------------------------------------------*/
  901.  
  902.   totallen = sizeof(SLPATH) +       /* Calculate total size of memory block */
  903.              strlen(newpath) + 1;   /* needed to hold structure and its strings */
  904.  
  905.   memblock = malloc(totallen);      /* Allocate the memory */
  906.   if (memblock == NULL)
  907.      return(NULL);
  908.  
  909.   p_slpath = (SLPATH *)memblock;    /* Store pointer to block and to where */
  910.   p_path = memblock + sizeof(SLPATH);    /* string will be put */
  911.  
  912.   strcpy(p_path, newpath);          /* Store string in the block */
  913.  
  914.   p_slpath->next = NULL;            /* Initialize structure */
  915.   p_slpath->firstname = NULL;
  916.   p_slpath->lastname = NULL;
  917.   p_slpath->path = p_path;
  918.  
  919.   p_slpath->bpathlen = p_curpath->bpathlen;
  920.  
  921.   p_slpath->hpfs = ishpfs(p_path);  /* Set whether or not it's HPFS */
  922.  
  923.   p_slpath->inserted = TRUE;        /* Mark as having been inserted */
  924.  
  925.  /*---------------------------------------------------------------------------*
  926.   * Insert the new path structure between the current and next (if any).
  927.   *---------------------------------------------------------------------------*/
  928.  
  929.   if (p_curpath->next == NULL)      /* If the current path is the last: */
  930.   {
  931.      p_curpath->next = p_slpath;         /* Then link to current path, */
  932.      lastpath = p_slpath;                /* And point end-of-list to it */
  933.   }
  934.   else                              /* Else: current path is not at the end: */
  935.   {                                 /* Insert new path between current and next paths: */
  936.      p_slpath->next = p_curpath->next;   /* Link new path to the next path */
  937.      p_curpath->next = p_slpath;         /* Link current path to new path */
  938.   }
  939.  
  940.   return(p_slpath);                 /* Return pointer to new structure */
  941. }
  942.  
  943. /*============================================================================*
  944.  * addname() - Adds a new name data structure.
  945.  *
  946.  * REMARKS:
  947.  *   This subroutine adds a new SLNAME structure to the list of SLNAME
  948.  *   structures for the 'pdata' path structure.  It allocates a block of
  949.  *   memory large enough to hold both the name structure and its strings.
  950.  *
  951.  * RETURNS:
  952.  *   A pointer to the new name structure, or NULL if there isn't enough memory.
  953.  *============================================================================*/
  954.  
  955. static SLNAME *addname(
  956.  
  957. SLPATH *pdata    ,                  /* Pointer to path data structure */
  958. char   *newname  ,                  /* Pointer to name string */
  959. char   *newregx  ,                  /* Pointer to (and length of) the */
  960. int     newlen   )                  /* compiled regular expression for name */
  961.  
  962. {
  963.   int     totallen;                 /* Total length needed for memory block */
  964.   char   *memblock;                 /* Pointer to allocated memory */
  965.  
  966.   SLNAME *p_slname;                 /* Pointer to name info structure */
  967.   char   *p_name;                   /* Pointers to strings */
  968.   char   *p_regx;
  969.  
  970.  /*---------------------------------------------------------------------------*
  971.   * Allocate a single block of memory for data structure and all strings
  972.   *---------------------------------------------------------------------------*/
  973.  
  974.   totallen = sizeof(SLNAME) +       /* Calculate total size of memory block */
  975.              strlen(newname) + 1 +  /* needed to hold structure and its strings */
  976.              newlen;
  977.  
  978.   memblock = malloc(totallen);      /* Allocate the memory */
  979.   if (memblock == NULL)
  980.      return(NULL);
  981.  
  982.   p_slname = (SLNAME *)memblock;    /* Store pointer to block and to where */
  983.   p_name = memblock + sizeof(SLNAME);    /* strings will be put */
  984.   p_regx = p_name + strlen(newname) + 1;
  985.  
  986.   strcpy(p_name, newname);          /* Store strings in the block */
  987.   memcpy(p_regx, newregx, newlen);
  988.  
  989.   p_slname->next = NULL;            /* Initialize structure */
  990.   p_slname->name = p_name;
  991.   p_slname->ecname = p_regx;
  992.   p_slname->eclen = newlen;
  993.   p_slname->fcount = 0L;
  994.  
  995.  /*---------------------------------------------------------------------------*
  996.   * Add the new name structure to the linked list for the specified path
  997.   *---------------------------------------------------------------------------*/
  998.  
  999.   if (pdata->firstname == NULL)     /* If list is empty: */
  1000.      pdata->firstname = p_slname;        /* New structure is now first on list */
  1001.  
  1002.   if (pdata->lastname != NULL)      /* If end-of-list ptr is not NULL: */
  1003.      (pdata->lastname)->next = p_slname;   /* Point old end structure to new one */
  1004.  
  1005.   pdata->lastname = p_slname;       /* New structure is now last on list */
  1006.  
  1007.   return(p_slname);                 /* Return pointer */
  1008. }
  1009.  
  1010. /*============================================================================*
  1011.  * findpath() - Finds path structure.
  1012.  *
  1013.  * REMARKS:
  1014.  *   If the static 'unique' variable is FALSE, then a NULL pointer is returned
  1015.  *   always: in this case, we want to a new SLPATH structure for each path.
  1016.  *
  1017.  *   Otherwise, this subroutine looks through the list of SLPATH structures
  1018.  *   for a structure whose path name matches 'pathstr'.  It does a case-
  1019.  *   insensitive comparison on path strings.
  1020.  *
  1021.  * RETURNS:
  1022.  *   A pointer to the SLPATH structure, or NULL if there is none.
  1023.  *============================================================================*/
  1024.  
  1025. static SLPATH *findpath(
  1026.  
  1027. char *pathstr )                     /* Pointer to path string */
  1028.  
  1029. {
  1030.   SLPATH *pdata;                    /* Pointer to path data structure */
  1031.  
  1032.   if (unique == FALSE)              /* If we want to create new SLPATH for each */
  1033.      return(NULL);                  /* path, then always return 'not found' */
  1034.  
  1035.   pdata = firstpath;                /* Point to first structure in list */
  1036.   while (pdata != NULL)             /* Until we reach the end of the list: */
  1037.   {
  1038.      if (strcmpi(pdata->path,            /* Compare path strings: */
  1039.                 pathstr) == 0)           /* If we found one with same 'path': */
  1040.         return(pdata);                   /* Then return pointer to structure */
  1041.  
  1042.       pdata = pdata->next;               /* No match: go on to next structure */
  1043.   }
  1044.  
  1045.   return(NULL);                     /* We didn't find it */
  1046. }
  1047.  
  1048. /*============================================================================*
  1049.  * dumppath() - Dumps contents of an SLPATH structure.
  1050.  *============================================================================*/
  1051.  
  1052. static void dumppath(
  1053.  
  1054. SLPATH *pdata )                     /* Pointer to data structure to dump */
  1055.  
  1056. {
  1057.   printf("Path data structure at 0x%08lX:\n", (long)pdata);
  1058.   printf("   Next path structure is at:      0x%08lX\n", (long)(pdata->next));
  1059.   printf("   List of name structures: first: 0x%08lX\n", (long)(pdata->firstname));
  1060.   printf("   List of name structures: last:  0x%08lX\n", (long)(pdata->lastname));
  1061.   if (pdata->path != NULL)
  1062.      printf("   Path string:                    '%s'\n", pdata->path);
  1063.   else
  1064.      printf("   Path string:                    None.\n");
  1065.  
  1066.   return;
  1067. }
  1068.  
  1069. /*============================================================================*
  1070.  * dumpname() - Dumps contents of an SLNAME structure.
  1071.  *============================================================================*/
  1072.  
  1073. static void dumpname(
  1074.  
  1075. SLNAME *ndata )                     /* Pointer to data structure to dump */
  1076.  
  1077. {
  1078.   printf("     Name data structure at 0x%08lX:\n", (long)ndata);
  1079.   printf("        Next name structure is at:      0x%08lX\n", (long)(ndata->next));
  1080.   if (ndata->name != NULL)
  1081.      printf("        Name string:                    '%s'\n", ndata->name);
  1082.   else
  1083.      printf("        Name string:                    None.\n");
  1084.   printf("        Address of compiled expression: 0x%08lX\n", (long)(ndata->ecname));
  1085.   printf("        Length of compiled expression:  %d\n", ndata->eclen);
  1086.   printf("        No. of filename matches:        %ld\n", ndata->fcount);
  1087.  
  1088.   return;
  1089. }
  1090.  
  1091. /*============================================================================*
  1092.  * matchit() - Should we show the file?
  1093.  *
  1094.  * REMARKS:
  1095.  *   This subroutine checks the file entry's attribute with the flags
  1096.  *   and determines whether or not we should match this file entry.
  1097.  *
  1098.  *   The 'mflags' argument tells us what we're looking for.
  1099.  *
  1100.  * RETURNS:
  1101.  *   TRUE: Match the file, or
  1102.  *   FALSE: Don't match the file: just skip it.
  1103.  *
  1104.  * NOTES:
  1105.  *   The bits in the FINFO structure's attribute should be checked using
  1106.  *   the _A_ #defined labels from <dos.h>.
  1107.  *
  1108.  *   The bits in the mflags variable should be checked using the SL_
  1109.  *   labels from util.h.
  1110.  *
  1111.  *   Any confusion in this area will result in garbage output!
  1112.  *============================================================================*/
  1113.  
  1114. static int matchit(
  1115.  
  1116. FINFO   *fdata  ,                   /* Pointer to file entry information */
  1117. ushort   mflags )                   /* Match flags */
  1118.  
  1119. {
  1120.  /*---------------------------------------------------------------------------*
  1121.   * Check for normal file
  1122.   *---------------------------------------------------------------------------*/
  1123.  
  1124.   if ((mflags & SL_NORMAL) != 0)    /* If we're looking for a normal file: */
  1125.      if ((fdata->attrFile & (_A_HIDDEN |   /* If non of these attributes are set: */
  1126.                              _A_SYSTEM |
  1127.                              _A_SUBDIR |
  1128.                              _A_VOLID)) == 0)
  1129.         return(TRUE);                         /* Then we found a normal file */
  1130.  
  1131.  /*---------------------------------------------------------------------------*
  1132.   * Check for system, hidden, and volid entries
  1133.   *---------------------------------------------------------------------------*/
  1134.  
  1135.   if ((mflags & SL_SYSTEM) != 0)
  1136.      if ((fdata->attrFile & _A_SYSTEM) != 0)
  1137.         return(TRUE);
  1138.  
  1139.   if ((mflags & SL_HIDDEN) != 0)
  1140.      if ((fdata->attrFile & _A_HIDDEN) != 0)
  1141.         return(TRUE);
  1142.  
  1143.   if ((mflags & SL_VOLID) != 0)
  1144.      if ((fdata->attrFile & _A_VOLID) != 0)
  1145.         return(TRUE);
  1146.  
  1147.  /*---------------------------------------------------------------------------*
  1148.   * Check for directory entries
  1149.   *---------------------------------------------------------------------------*/
  1150.  
  1151.   if ((mflags & SL_DIR) != 0)       /* If we're looking for a directory: */
  1152.   {
  1153.      if ((fdata->attrFile & _A_SUBDIR) != 0)  /* And the file entry is a directory: */
  1154.      {
  1155.         if ((strcmp(fdata->achName, ".")  != 0) &&   /* And its name isn't . or .. */
  1156.             (strcmp(fdata->achName, "..") != 0))
  1157.         return(TRUE);                                       /* Ok */
  1158.      }
  1159.   }
  1160.  
  1161.   if ((mflags & SL_DOTDIR) != 0)    /* If we're looking for a dotted directory: */
  1162.   {
  1163.      if ((fdata->attrFile & _A_SUBDIR) != 0)  /* And the file entry is a directory: */
  1164.      {
  1165.         if ((strcmp(fdata->achName, ".")  == 0) ||    /* And its name is . or .. */
  1166.             (strcmp(fdata->achName, "..") == 0))
  1167.         return(TRUE);                                       /* Ok */
  1168.      }
  1169.   }
  1170.  
  1171.  /*---------------------------------------------------------------------------*
  1172.   * It doesn't pass any of our checks: Don't attempt to match the file
  1173.   *---------------------------------------------------------------------------*/
  1174.  
  1175.   return(FALSE);
  1176. }
  1177.