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