home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 8 Other / 08-Other.zip / ms_sh23b.zip / src / glob.c < prev    next >
C/C++ Source or Header  |  1994-08-26  |  19KB  |  855 lines

  1. /* MS-DOS GLOB (3C) FUNCTION
  2.  *
  3.  * MS-DOS GLOB FUNCTION - Copyright (c) 1990,4 Data Logic Limited.
  4.  *
  5.  * This code is subject to the following copyright restrictions:
  6.  *
  7.  * 1.  Redistribution and use in source and binary forms are permitted
  8.  *     provided that the above copyright notice is duplicated in the
  9.  *     source form.
  10.  *
  11.  *    $Header: /usr/users/istewart/shell/sh2.3/Release/RCS/glob.c,v 2.3 1994/08/25 20:49:11 istewart Exp $
  12.  *
  13.  *    $Log: glob.c,v $
  14.  * Revision 2.3  1994/08/25  20:49:11  istewart
  15.  * MS Shell 2.3 Release
  16.  *
  17.  * Revision 2.2  1994/02/01  10:25:20  istewart
  18.  * Release 2.3 Beta 2, including first NT port
  19.  *
  20.  * Revision 2.1  1993/06/14  10:59:32  istewart
  21.  * More changes for 223 beta
  22.  *
  23.  * Revision 2.0  1992/04/13  17:39:09  Ian_Stewartson
  24.  * MS-Shell 2.0 Baseline release
  25.  *
  26.  */
  27.  
  28. #include <sys/types.h>            /* MS-DOS type definitions      */
  29. #include <sys/stat.h>            /* File status definitions    */
  30. #include <stdio.h>            /* Standard I/O delarations     */
  31. #include <stdlib.h>            /* Standard library functions   */
  32. #include <string.h>            /* String library functions     */
  33. #include <limits.h>            /* String library functions     */
  34. #include <dirent.h>            /* Direction I/O functions    */
  35. #include <ctype.h>            /* Character types function    */
  36. #include <unistd.h>            /* Other functions        */
  37.  
  38.  
  39. #ifdef __TURBOC__
  40. #  include <alloc.h>            /* Malloc functions        */
  41. #  include <dir.h>            /* Dos directory functions    */
  42. #else
  43. #  include <malloc.h>            /* Malloc functions        */
  44. #endif
  45.  
  46. #include <glob.h>
  47.  
  48. #if defined (MSDOS) || defined (__OS2__) || defined (__TURBOC__) || defined (WIN32)
  49. #  if defined (OS2) || defined (__OS2__)
  50.  
  51. #    define INCL_DOSDEVICES
  52. #    define INCL_DOSMISC
  53. #    include <os2.h>            /* OS2 functions declarations       */
  54.  
  55. #    if defined (__OS2__)
  56. #      define DISABLE_HARD_ERRORS    DosError (FERR_DISABLEHARDERR)
  57. #      define ENABLE_HARD_ERRORS    DosError (FERR_ENABLEHARDERR)
  58. #    else
  59. #      define DISABLE_HARD_ERRORS    DosError (HARDERROR_DISABLE)
  60. #      define ENABLE_HARD_ERRORS    DosError (HARDERROR_ENABLE)
  61. #    endif
  62.  
  63. #  elif defined (WIN32)
  64. #  include <windows.h>
  65. #  define DISABLE_HARD_ERRORS    SetErrorMode (0)
  66. #  define ENABLE_HARD_ERRORS    SetErrorMode (SEM_FAILCRITICALERRORS | \
  67.                           SEM_NOOPENFILEERRORBOX);
  68.  
  69. #  else
  70. #    include <bios.h>            /* DOS BIOS functions        */
  71. #    include <dos.h>            /* DOS functions        */
  72. #    define DISABLE_HARD_ERRORS
  73. #    define ENABLE_HARD_ERRORS
  74. #  endif
  75. #endif
  76.  
  77. /*
  78.  * OS/2 2.x has these missing
  79.  */
  80.  
  81. #ifndef S_IFMT
  82. #  define    S_IFMT    0xf000    /* type of file                */
  83. #endif
  84.  
  85. #ifndef S_ISDIR
  86. #  define S_ISDIR(m)    ((((m) & S_IFMT) == S_IFDIR))
  87. #endif
  88.  
  89. /*
  90.  * Functions
  91.  */
  92.  
  93. static int    _GP_SortCompare        _PROTO ((char **, char **));
  94. static int    _GP_ExpandField        _PROTO ((char *, char *, glob_t *));
  95. static int    _GP_ExpandMetaCharacters _PROTO ((char *, glob_t *));
  96. static int    _GP_AddArgument        _PROTO ((char *, glob_t *));
  97. static bool    _GP_MatchPattern    _PROTO ((char *, char *));
  98. static bool    _GP_access        _PROTO ((char *, int));
  99. static bool    _GP_stat        _PROTO ((char *, struct stat *));
  100.  
  101. static char    *_GP_MetaChars = "?*[\\";
  102. static char    *_GP_NullString = "";
  103.  
  104. #if defined (MSDOS) || defined (__OS2__) || defined (__TURBOC__) || defined (WIN32)
  105. static    int    _GP_GetNumberofFloppyDrives (void);
  106.  
  107. #  if defined (OS2) || defined (__OS2__) || defined (__TURBOC__) || defined (WIN32)
  108. static void     _dos_setdrive (unsigned int, unsigned int *);
  109. static void     _dos_getdrive (unsigned int *);
  110. #  endif
  111.  
  112. static char    *_GP_CheckForMultipleDrives    _PROTO ((char *));
  113. #endif
  114.  
  115. /*
  116.  * There appears to be no alloca in TurboC
  117.  */
  118.  
  119. #ifdef __TURBOC__
  120. #  define alloca(x)        malloc (x)
  121. #  define alloca_free(x)    free (x)
  122. #else
  123. #  define alloca_free(x)
  124. #endif
  125.  
  126. /*
  127.  * Free up space
  128.  */
  129.  
  130. void    globfree (gp)
  131. glob_t    *gp;
  132. {
  133.     int        i = (gp->gl_flags & GLOB_DOOFFS) ? gp->gl_offs : 0;
  134.  
  135.     while (i < gp->gl_pathc)
  136.     free (gp->gl_pathv[i++]);
  137.  
  138.     free (gp->gl_pathv);
  139. }
  140.  
  141. /* Main search function */
  142.  
  143. int    glob (Pattern, flags, ErrorFunction, gp)
  144. char    *Pattern;
  145. int    flags;
  146. int    (*ErrorFunction) _PROTO ((char *, int));
  147. glob_t    *gp;
  148. {
  149.     int        ReturnValue;
  150.     char    *PatternCopy;
  151.     char    *cp;
  152.  
  153. /* If no append mode - initialise */
  154.  
  155.     if (!(flags & GLOB_APPEND))
  156.     {
  157.     gp->gl_pathc = 0;
  158.     gp->gl_pathv = (char **)NULL;
  159.     }
  160.  
  161.     gp->gl_flags = flags;
  162.     gp->gl_ef = ErrorFunction;
  163.  
  164.     if ((PatternCopy = alloca (strlen (Pattern) + 1)) == (char *)NULL)
  165.     return GLOB_NOSPACE;
  166.  
  167. /* Expand and kill environment */
  168.  
  169.     if (ReturnValue = _GP_ExpandMetaCharacters (strcpy (PatternCopy, Pattern),
  170.                         gp))
  171.     {
  172.     alloca_free (PatternCopy);
  173.     return ReturnValue;
  174.     }
  175.  
  176. /* Check for no finds.  If add value, strip out \ from the string */
  177.  
  178.     if ((gp->gl_pathc == 0) && (flags & GLOB_NOCHECK))
  179.     {
  180.     cp = strcpy (PatternCopy, Pattern);
  181.  
  182.     while ((cp = strpbrk (cp, "?*[")) != (char *)NULL)
  183.     {
  184.         if ((cp == PatternCopy) || (*(cp - 1) != '\\'))
  185.         cp++;
  186.  
  187.         else
  188.         memmove (cp - 1, cp, strlen (cp) + 1);
  189.     }
  190.  
  191.     if (ReturnValue = _GP_AddArgument (PatternCopy, gp))
  192.     {
  193.         alloca_free (PatternCopy);
  194.         return ReturnValue;
  195.     }
  196.     }
  197.  
  198. /* Terminate string */
  199.  
  200.     if ((gp->gl_pathc != 0) &&
  201.     (ReturnValue = _GP_AddArgument ((char *)NULL, gp)))
  202.     {
  203.     alloca_free (PatternCopy);
  204.     return ReturnValue;
  205.     }
  206.  
  207. /* Get the sort length */
  208.  
  209.     ReturnValue = (gp->gl_flags & GLOB_DOOFFS) ? gp->gl_offs : 0;
  210.  
  211.     if ((!(flags & GLOB_NOSORT)) && (gp->gl_pathc > 1))
  212.     qsort (&gp->gl_pathv[ReturnValue], gp->gl_pathc, sizeof (char *),
  213.            (int (*) (const void *, const void *)) _GP_SortCompare);
  214.  
  215.     alloca_free (PatternCopy);
  216.     return 0;
  217. }
  218.  
  219. /* Compare function for sort */
  220.  
  221. static int    _GP_SortCompare (a1, a2)
  222. char        **a1, **a2;
  223. {
  224.     return strcmp (*a1, *a2);
  225. }
  226.  
  227. /* Expand a field if it has metacharacters in it */
  228.  
  229. static int    _GP_ExpandField (CurrentDirectoryPattern, AppendString, gp)
  230. char        *CurrentDirectoryPattern;    /* Prefix field        */
  231. char        *AppendString;            /* Postfix field        */
  232. glob_t        *gp;
  233. {
  234.     int         i;
  235.     int            ReturnValue = 0;    /* Return Value        */
  236.     char        *FullFileName;        /* Search file name    */
  237.     char        *FileNameStart;
  238.     char        *MatchString;        /* Match string        */
  239.     DIR            *DirHandler;
  240.     struct dirent    *CurrentDirectoryEntry;
  241.  
  242. #if defined (MSDOS) || defined (__OS2__) || defined (__TURBOC__) || defined (WIN32)
  243.     unsigned int    CurrentDrive;        /* Current drive    */
  244.     unsigned int    MaxDrives;        /* Max drive        */
  245.     unsigned int    SelectedDrive;        /* Selected drive    */
  246.     unsigned int    x_drive, y_drive;    /* Dummies        */
  247.     char        *DriveCharacter;    /* Multi-drive flag    */
  248.     char        SDriveString[2];
  249.  
  250. /* Convert file name to lower case */
  251.  
  252. #  if defined (OS2) || defined (__OS2__) || (WIN32)
  253.     if (!IsHPFSFileSystem (CurrentDirectoryPattern))
  254.     strlwr (CurrentDirectoryPattern);
  255. #  else
  256.     strlwr (CurrentDirectoryPattern);
  257. #  endif
  258.  
  259. /* Search all drives ? */
  260.  
  261.     if ((DriveCharacter = _GP_CheckForMultipleDrives (CurrentDirectoryPattern))
  262.         != (char *)NULL)
  263.     {
  264.     _dos_getdrive (&CurrentDrive);    /* Get number of drives        */
  265.     _dos_setdrive (CurrentDrive, &MaxDrives);
  266.     SDriveString[1] = 0;
  267.  
  268.     for (SelectedDrive = 1; SelectedDrive <= MaxDrives; ++SelectedDrive)
  269.     {
  270.         _dos_setdrive (SelectedDrive, &x_drive);
  271.         _dos_getdrive (&y_drive);
  272.         _dos_setdrive (CurrentDrive, &x_drive);
  273.  
  274. /* Check to see if the second diskette drive is really there */
  275.  
  276.         if ((_GP_GetNumberofFloppyDrives () < 2) && (SelectedDrive == 2))
  277.         continue;
  278.  
  279. /* If the drive exists and is in our list - process it */
  280.  
  281.         *DriveCharacter = 0;
  282.         *SDriveString = (char)(SelectedDrive + 'a' - 1);
  283.         strlwr (CurrentDirectoryPattern);
  284.  
  285.         if ((y_drive == SelectedDrive) &&
  286.         _GP_MatchPattern (SDriveString, CurrentDirectoryPattern))
  287.         {
  288.         if ((FullFileName = alloca (strlen (DriveCharacter) + 3))
  289.                 == (char *)NULL)
  290.             return GLOB_NOSPACE;
  291.  
  292.         *DriveCharacter = ':';
  293.         *FullFileName = *SDriveString;
  294.         strcpy (FullFileName + 1, DriveCharacter);
  295.  
  296.         i = _GP_ExpandField (FullFileName, AppendString, gp);
  297.         alloca_free (FullFileName);
  298.  
  299.         if (i)
  300.             return i;
  301.         }
  302.  
  303.         *DriveCharacter = ':';
  304.     }
  305.  
  306.     return 0;
  307.     }
  308. #endif
  309.  
  310. /* Get the path length */
  311.  
  312.     MatchString = strrchr (CurrentDirectoryPattern, '/');
  313.  
  314. #if defined (MSDOS) || defined (__OS2__) || defined (__TURBOC__) || defined (WIN32)
  315.     if ((MatchString == (char *)NULL) &&
  316.     (*(CurrentDirectoryPattern + 1) == ':'))
  317.     MatchString = CurrentDirectoryPattern + 1;
  318. #endif
  319.  
  320. /* Set up file name for search */
  321.  
  322.     if ((MatchString == (char *)NULL) || (*MatchString == ':'))
  323.     {
  324.     if ((FullFileName = alloca (NAME_MAX + 7 +
  325.                     strlen (AppendString))) == (char *)NULL)
  326.         return GLOB_NOSPACE;
  327.  
  328.     if (MatchString != (char *)NULL)
  329.         *(strcpy (FullFileName, "x:.")) = *CurrentDirectoryPattern;
  330.  
  331.     else
  332.         strcpy (FullFileName, ".");
  333.  
  334.     FileNameStart = FullFileName +
  335.             (int)((MatchString != (char *)NULL) ? 2 : 0);
  336.     }
  337.  
  338. /* Case of /<directory>/... */
  339.  
  340.     else if ((FullFileName = alloca (NAME_MAX + 4 + strlen (AppendString) +
  341.                 (i = (int)(MatchString - CurrentDirectoryPattern))))
  342.             == (char *)NULL)
  343.         return GLOB_NOSPACE;
  344.  
  345.     else
  346.     {
  347.     strncpy (FullFileName, CurrentDirectoryPattern, i);
  348.     *((FileNameStart = FullFileName + i)) = 0;
  349.     strcpy (FileNameStart++, "/");
  350.     }
  351.  
  352.     MatchString = (MatchString == (char *)NULL) ? CurrentDirectoryPattern
  353.                         : MatchString + 1;
  354.  
  355. /* Search for file names */
  356.  
  357.     if ((DirHandler = opendir (FullFileName)) == (DIR *)NULL)
  358.     {
  359.     i = 0;
  360.  
  361.     if (((gp->gl_ef != NULL) && (*gp->gl_ef)(FullFileName, errno)) ||
  362.         (gp->gl_flags & GLOB_ERR))
  363.         i = GLOB_ABEND;
  364.  
  365.     alloca_free (FullFileName);
  366.     return i;
  367.     }
  368.  
  369. /* Are there any matches */
  370.  
  371.     while ((CurrentDirectoryEntry = readdir (DirHandler)) !=
  372.         (struct dirent *)NULL)
  373.     {
  374.     if ((*CurrentDirectoryEntry->d_name == '.') && (*MatchString != '.'))
  375.         continue;
  376.  
  377. /* Check for match */
  378.  
  379.     if (_GP_MatchPattern (CurrentDirectoryEntry->d_name, MatchString))
  380.     {
  381.         strcpy (FileNameStart, CurrentDirectoryEntry->d_name);
  382.  
  383. /* If the postfix is not null, this must be a directory */
  384.  
  385.         if (strlen (AppendString))
  386.         {
  387.         struct stat        statb;
  388.         char            *p;
  389.  
  390. /* If not a directory - go to the next file */
  391.  
  392.         if (!_GP_stat (FullFileName, &statb) ||
  393.             !S_ISDIR (statb.st_mode & S_IFMT))
  394.             continue;
  395.  
  396. /* Are there any metacharacters in the postfix? */
  397.  
  398.         if ((p = strpbrk (AppendString, _GP_MetaChars)) == (char *)NULL)
  399.         {
  400.  
  401. /* No - build the file name and check it exists */
  402.  
  403.             strcat (strcat (FileNameStart, "/"), AppendString);
  404.  
  405.             if (_GP_access (FullFileName, F_OK) &&
  406.             (ReturnValue = _GP_AddArgument (FullFileName, gp)))
  407.             break;
  408.         }
  409.  
  410. /* Yes - build the filename upto the start of the meta characters */
  411.  
  412.         else
  413.         {
  414.             if ((p = strchr (p, '/')) != (char *)NULL)
  415.             *(p++) = 0;
  416.  
  417.             else
  418.             p = _GP_NullString;
  419.  
  420. /* Build the new directory name and check it out */
  421.  
  422.             strcat (strcat (FileNameStart, "/"), AppendString);
  423.             ReturnValue = _GP_ExpandField (FullFileName, p, gp);
  424.  
  425.             if (p != _GP_NullString)
  426.                *(--p) = '/';
  427.  
  428. /* Check for errors */
  429.  
  430.             if (ReturnValue)
  431.             break;
  432.         }
  433.         }
  434.  
  435. /* Process this file.  If error - terminate */
  436.  
  437.         else if (_GP_access (FullFileName, F_OK) &&
  438.              (ReturnValue = _GP_AddArgument (FullFileName, gp)))
  439.         break;
  440.     }
  441.     }
  442.  
  443.     closedir (DirHandler);
  444.     alloca_free (FullFileName);
  445.     return ReturnValue;
  446. }
  447.  
  448. /* Find the location of meta-characters.  If no meta, add the argument and
  449.  * return.  If meta characters, expand directory containing meta characters.
  450.  */
  451.  
  452. static int    _GP_ExpandMetaCharacters (file, gp)
  453. char        *file;
  454. glob_t        *gp;
  455. {
  456.     char    *p;
  457.     int        ReturnValue;
  458.  
  459. /* No metas - add to string */
  460.  
  461.     if ((p = strpbrk (file, _GP_MetaChars)) == (char *)NULL)
  462.     {
  463.     if (!_GP_access (file, F_OK))
  464.         return 0;
  465.  
  466.     return _GP_AddArgument (file, gp);
  467.     }
  468.  
  469. /* Ok - metas, find the end of the start of the directory */
  470.  
  471.     else if ((p = strchr (p, '/')) != (char *)NULL)
  472.     *(p++) = 0;
  473.  
  474.     else
  475.     p = _GP_NullString;
  476.  
  477. /* Continue recusive match */
  478.  
  479.     ReturnValue = _GP_ExpandField (file, p, gp);
  480.  
  481. /* Restore if necessary */
  482.  
  483.     if (p != _GP_NullString)
  484.        *(--p) = '/';
  485.  
  486.     return ReturnValue;
  487. }
  488.  
  489. /* Add an argument to the stack - file is assumed to be a array big enough
  490.  * for the file name + 2
  491.  */
  492.  
  493. static int    _GP_AddArgument (file, gp)
  494. char        *file;
  495. glob_t        *gp;
  496. {
  497.     int        Offset;
  498.     char    **p1;
  499.     struct stat    FileStatus;
  500.  
  501.     Offset = gp->gl_pathc + ((gp->gl_flags & GLOB_DOOFFS) ? gp->gl_offs : 0);
  502.     p1  = gp->gl_pathv;
  503.  
  504. /* Malloc space if necessary */
  505.  
  506.     if (gp->gl_pathc == 0)
  507.     p1 = (char **)calloc (sizeof (char *), (50 + Offset));
  508.  
  509.     else if ((gp->gl_pathc % 50) == 0)
  510.     p1 = (char **)realloc (p1, (Offset + 50) * (sizeof (char *)));
  511.  
  512.     if (p1 == (char **)NULL)
  513.     return GLOB_NOSPACE;
  514.  
  515. /* OK got space */
  516.  
  517.     gp->gl_pathv = p1;
  518.  
  519. /* End of list ? */
  520.  
  521.     if (file == (char *)NULL)
  522.     p1[Offset] = (char *)NULL;
  523.  
  524.     else
  525.     {
  526.     if ((gp->gl_flags & GLOB_MARK) && (file[strlen (file) - 1] != '/') &&
  527.         _GP_stat (file, &FileStatus) && (S_ISDIR (FileStatus.st_mode)))
  528.         strcat (file, "/");
  529.  
  530.     if ((p1[Offset] = strdup (file)) == (char *)NULL)
  531.         return GLOB_NOSPACE;
  532.  
  533.     strcpy (p1[Offset], file);
  534.  
  535. /* Increment counter */
  536.  
  537.     ++(gp->gl_pathc);
  538.     }
  539.  
  540.     return 0;
  541. }
  542.  
  543. /* Check for multi_drive prefix */
  544.  
  545. #if defined (MSDOS) || defined (__OS2__) || defined (__TURBOC__) || defined (WIN32)
  546. static char    *_GP_CheckForMultipleDrives (prefix)
  547. char        *prefix;
  548. {
  549.     if (strlen (prefix) < 2)
  550.     return (char *)NULL;
  551.  
  552.     if (((*prefix == '*') || (*prefix == '?')) && (prefix[1] == ':'))
  553.     return prefix + 1;
  554.  
  555.     if (*prefix != '[')
  556.     return (char *)NULL;
  557.  
  558.     while (*prefix && (*prefix != ']'))
  559.     {
  560.     if ((*prefix == '\\') && (*(prefix + 1)))
  561.         ++prefix;
  562.  
  563.     ++prefix;
  564.     }
  565.  
  566.     return (*prefix && (*(prefix + 1) == ':')) ? prefix + 1 : (char *)NULL;
  567. }
  568.  
  569. /*
  570.  * Some Turboc Functions to emulate MSC functions
  571.  */
  572.  
  573. #  if defined (__TURBOC__)
  574. static void     _dos_getdrive (cdp)
  575. unsigned int    *cdp;
  576. {
  577.     *cdp = (unsigned int)getdisk () + 1;
  578. }
  579.  
  580. static void     _dos_setdrive (cdr, ndp)
  581. unsigned int    cdr;
  582. unsigned int    *ndp;
  583. {
  584.    *ndp = (unsigned int)setdisk (cdr - 1);
  585. }
  586. #  endif
  587.  
  588. /*
  589.  * Some OS/2 functions to emulate the DOS functions
  590.  */
  591.  
  592. #  if defined (OS2) || defined (__OS2__)
  593. static void     _dos_getdrive (cdp)
  594. unsigned int    *cdp;
  595. {
  596.     USHORT    cdr;
  597.     ULONG    ndr;
  598.  
  599.     DosQCurDisk((PUSHORT)&cdr, (PULONG) &ndr);
  600.     *cdp = (unsigned int)cdr;
  601. }
  602.  
  603. static void     _dos_setdrive (cdr, ndp)
  604. unsigned int    cdr;
  605. unsigned int    *ndp;
  606. {
  607.     ULONG        ulDrives;
  608.     USHORT        usDisk;
  609.     int            i;
  610.  
  611.     DosSelectDisk ((USHORT)cdr);
  612.  
  613. /* Get the current disk and check that to see the number of drives */
  614.  
  615.     DosQCurDisk (&usDisk, &ulDrives);        /* gets current drive        */
  616.  
  617.     for (i = 25; (!(ulDrives & (1L << i))) && (i >= 0); --i)
  618.     continue;
  619.  
  620.     *ndp = i + 1;
  621. }
  622.  
  623. #  elif defined (WIN32)
  624.  
  625. static void     _dos_getdrive (cdp)
  626. unsigned int    *cdp;
  627. {
  628.     char    szCurDir [MAX_PATH];
  629.  
  630.     GetCurrentDirectory (MAX_PATH, szCurDir);
  631.  
  632.     *cdp = (unsigned int)(szCurDir[0] - 'A' + 1);
  633. }
  634.  
  635. static void     _dos_setdrive (cdr, ndp)
  636. unsigned int    cdr;
  637. unsigned int    *ndp;
  638. {
  639.     char        szNewDrive[3];
  640.     DWORD        dwLogicalDrives;
  641.     unsigned int    i;
  642.  
  643.     szNewDrive[0] = cdr + 'A' - 1;
  644.     szNewDrive[1] = ':';
  645.     szNewDrive[2] = 0;
  646.     *ndp = 0;
  647.  
  648.     if (!SetCurrentDirectory (szNewDrive))
  649.     return;
  650.  
  651.     dwLogicalDrives = GetLogicalDrives ();
  652.  
  653.     for (i = 25; (!(dwLogicalDrives & (1L << i))) && i >= 0; --i)
  654.     continue;
  655.  
  656.     *ndp = i + 1;
  657. }
  658. #  endif
  659.  
  660. /* Return the number of floppy disks */
  661.  
  662. #  if defined (OS2) || defined (__OS2__)
  663. static    int    _GP_GetNumberofFloppyDrives ()
  664. {
  665.     BYTE    nflop = 1;
  666.  
  667.     DosDevConfig (&nflop, DEVINFO_FLOPPY, 0);
  668.  
  669.     return nflop;
  670. }
  671.  
  672. #  elif defined (WIN32)
  673. static    int    _GP_GetNumberofFloppyDrives ()
  674. {
  675.     char    szNewDrive[4];
  676.     DWORD    dwLogicalDrives = GetLogicalDrives();
  677.     int        LastTest = 0;
  678.     int        i;
  679.  
  680.     strcpy (szNewDrive, "x:\\");
  681.  
  682. /* Look at each drive until we find a non-floppy which exists */
  683.  
  684.     for (i = 0; i < 25; i++)
  685.     {
  686.     if (dwLogicalDrives & (1L << i))
  687.     {
  688.         szNewDrive[0] = i + 'A';
  689.  
  690.         if (GetDriveType (szNewDrive) != DRIVE_REMOVABLE)
  691.         break;
  692.  
  693.         LastTest = i + 1;
  694.     }
  695.     }
  696.  
  697.     return LastTest;
  698. }
  699.  
  700. #  elif defined (__TURBOC__)
  701. static    int    _GP_GetNumberofFloppyDrives ()
  702. {
  703.     return ((biosequip () & 0x00c0) >> 6) + 1;
  704. }
  705.  
  706. #  else
  707. static    int    _GP_GetNumberofFloppyDrives ()
  708. {
  709.     return ((_bios_equiplist () & 0x00c0) >> 6) + 1;
  710. }
  711. #  endif
  712. #endif
  713.  
  714. /*
  715.  * Pattern Matching function
  716.  */
  717.  
  718. static bool    _GP_MatchPattern (string, pattern)
  719. char        *string;        /* String to match                  */
  720. char        *pattern;        /* Pattern to match against         */
  721. {
  722.     register int    cur_s;        /* Current string character         */
  723.     register int    cur_p;        /* Current pattern character        */
  724.  
  725. /* Match string */
  726.  
  727.     while (cur_p = *(pattern++))
  728.     {
  729.     cur_s = *(string++);        /* Load current string character    */
  730.  
  731.         switch (cur_p)            /* Switch on pattern character      */
  732.         {
  733.             case '[':            /* Match class of characters        */
  734.             {
  735.                 while(1)
  736.                 {
  737.                     if (!(cur_p = *(pattern++)))
  738.             return 0;
  739.  
  740.                     if (cur_p == ']')
  741.             return FALSE;
  742.  
  743.                     if (cur_s != cur_p)
  744.                     {
  745.                         if (*pattern == '-')
  746.                         {
  747.                             if(cur_p > cur_s)
  748.                                 continue;
  749.  
  750.                             if (cur_s > *(++pattern))
  751.                                 continue;
  752.                         }
  753.                         else
  754.                             continue;
  755.                     }
  756.  
  757.                     break;
  758.                 }
  759.  
  760.                 while (*pattern)
  761.                 {
  762.                     if (*(pattern++) == ']')
  763.                         break;
  764.                 }
  765.  
  766.         break;
  767.             }
  768.  
  769.             case '?':            /* Match any character              */
  770.             {
  771.                 if (!cur_s)
  772.             return FALSE;
  773.  
  774.                 break;
  775.             }
  776.  
  777.             case '*':            /* Match any number of any character*/
  778.             {
  779.                 string--;
  780.  
  781.                 do
  782.                 {
  783.                     if (_GP_MatchPattern (string, pattern))
  784.             return TRUE;
  785.                 }
  786.                 while (*(string++));
  787.  
  788.         return FALSE;
  789.             }
  790.  
  791.             case '\\':            /* Next character is non-meta       */
  792.             {
  793.                 if (!(cur_p = *(pattern++)))
  794.             return FALSE;
  795.             }
  796.  
  797.             default:            /* Match against current pattern    */
  798.             {
  799.                 if (cur_p != cur_s)
  800.             return FALSE;
  801.  
  802.                 break;
  803.             }
  804.         }
  805.     }
  806.  
  807.     return (!*string) ? TRUE : FALSE;
  808. }
  809.  
  810. /*
  811.  * Local Stat function to do some additional checks
  812.  */
  813.  
  814. static bool _GP_stat (char *FileName, struct stat *Status)
  815. {
  816.     int        rc;
  817.  
  818.     DISABLE_HARD_ERRORS;
  819.     rc = stat (FileName, Status);
  820.     ENABLE_HARD_ERRORS;
  821.  
  822.     return rc ? FALSE : TRUE;
  823. }
  824.  
  825. /*
  826.  * Local access function to do some additional checks
  827.  */
  828.  
  829. static bool _GP_access (char *FileName, int mode)
  830. {
  831.     int        rc;
  832.  
  833.     DISABLE_HARD_ERRORS;
  834.     rc = access (FileName, mode);
  835.     ENABLE_HARD_ERRORS;
  836.  
  837.     return rc ? FALSE : TRUE;
  838. }
  839.  
  840. /*
  841.  * Test program
  842.  */
  843.  
  844. #ifdef TEST
  845. int main (int argc, char **argv)
  846. {
  847.     int        i;
  848.  
  849.     for (i = 0; i < argc; i++)
  850.     printf ("Arg %d = <%s>\n", i, argv[i]);
  851.     
  852.     return 0;
  853. }
  854. #endif
  855.