Rev 227 | Blame | Compare with Previous | Last modification | View Log | RSS feed
/* MS-DOS GLOB (3C) FUNCTION** MS-DOS GLOB FUNCTION - Copyright (c) 1990,4 Data Logic Limited.** This code is subject to the following copyright restrictions:** 1. Redistribution and use in source and binary forms are permitted* provided that the above copyright notice is duplicated in the* source form.** $Header: /cvsroot/device/DEVL/UTILS/SH/GLOB.C,v 1.1 2002/08/02 06:49:31 adamy Exp $** $Log: GLOB.C,v $* Revision 1.1 2002/08/02 06:49:31 adamy* imported (reference only)** Revision 1.1 2001/07/20 05:55:41 ayoung* WIN32 support** Revision 1.1.1.1 1999/12/02 01:11:12 gordonh* UTIL** Revision 2.3 1994/08/25 20:49:11 istewart* MS Shell 2.3 Release** Revision 2.2 1994/02/01 10:25:20 istewart* Release 2.3 Beta 2, including first NT port** Revision 2.1 1993/06/14 10:59:32 istewart* More changes for 223 beta** Revision 2.0 1992/04/13 17:39:09 Ian_Stewartson* MS-Shell 2.0 Baseline release**/#include <sys/types.h> /* MS-DOS type definitions */#include <sys/stat.h> /* File status definitions */#include <stdio.h> /* Standard I/O delarations */#include <stdlib.h> /* Standard library functions */#include <string.h> /* String library functions */#include <limits.h> /* String library functions */#include <dirent.h> /* Direction I/O functions */#include <ctype.h> /* Character types function */#include <unistd.h> /* Other functions */#ifdef __TURBOC__# include <alloc.h> /* Malloc functions */# include <dir.h> /* Dos directory functions */#else# include <malloc.h> /* Malloc functions */#endif#include <glob.h>#if defined (MSDOS) || defined (__OS2__) || defined (__TURBOC__) || defined (WIN32)# if defined (OS2) || defined (__OS2__)# define INCL_DOSDEVICES# define INCL_DOSMISC# include <os2.h> /* OS2 functions declarations */# if defined (__OS2__)# define DISABLE_HARD_ERRORS DosError (FERR_DISABLEHARDERR)# define ENABLE_HARD_ERRORS DosError (FERR_ENABLEHARDERR)# else# define DISABLE_HARD_ERRORS DosError (HARDERROR_DISABLE)# define ENABLE_HARD_ERRORS DosError (HARDERROR_ENABLE)# endif# elif defined (WIN32)# include <windows.h># define DISABLE_HARD_ERRORS SetErrorMode (0)# define ENABLE_HARD_ERRORS SetErrorMode (SEM_FAILCRITICALERRORS | \SEM_NOOPENFILEERRORBOX);# else# include <bios.h> /* DOS BIOS functions */# include <dos.h> /* DOS functions */# define DISABLE_HARD_ERRORS# define ENABLE_HARD_ERRORS# endif#endif/** OS/2 2.x has these missing*/#ifndef S_IFMT# define S_IFMT 0xf000 /* type of file */#endif#ifndef S_ISDIR# define S_ISDIR(m) ((((m) & S_IFMT) == S_IFDIR))#endif/** Functions*/static int _GP_SortCompare _PROTO ((char **, char **));static int _GP_ExpandField _PROTO ((char *, char *, glob_t *));static int _GP_ExpandMetaCharacters _PROTO ((char *, glob_t *));static int _GP_AddArgument _PROTO ((char *, glob_t *));static bool _GP_MatchPattern _PROTO ((char *, char *));static bool _GP_access _PROTO ((char *, int));static bool _GP_stat _PROTO ((char *, struct stat *));static char *_GP_MetaChars = "?*[\\";static char *_GP_NullString = "";#if defined (MSDOS) || defined (__OS2__) || defined (__TURBOC__) || defined (WIN32)static int _GP_GetNumberofFloppyDrives (void);# if defined (OS2) || defined (__OS2__) || defined (__TURBOC__) || defined (WIN32)static void _dos_setdrive (unsigned int, unsigned int *);static void _dos_getdrive (unsigned int *);# endifstatic char *_GP_CheckForMultipleDrives _PROTO ((char *));#endif/** There appears to be no alloca in TurboC*/#if defined(__TURBOC__) || defined(WIN32)# define alloca(x) malloc (x)# define alloca_free(x) free (x)#else# define alloca_free(x)#endif/** Free up space*/void globfree (gp)glob_t *gp;{int i = (gp->gl_flags & GLOB_DOOFFS) ? gp->gl_offs : 0;while (i < gp->gl_pathc)free (gp->gl_pathv[i++]);free (gp->gl_pathv);}/* Main search function */int glob (Pattern, flags, ErrorFunction, gp)char *Pattern;int flags;int (*ErrorFunction) _PROTO ((char *, int));glob_t *gp;{int ReturnValue;char *PatternCopy;char *cp;/* If no append mode - initialise */if (!(flags & GLOB_APPEND)){gp->gl_pathc = 0;gp->gl_pathv = (char **)NULL;}gp->gl_flags = flags;gp->gl_ef = ErrorFunction;if ((PatternCopy = alloca (strlen (Pattern) + 1)) == (char *)NULL)return GLOB_NOSPACE;/* Expand and kill environment */if (ReturnValue = _GP_ExpandMetaCharacters (strcpy (PatternCopy, Pattern),gp)){alloca_free (PatternCopy);return ReturnValue;}/* Check for no finds. If add value, strip out \ from the string */if ((gp->gl_pathc == 0) && (flags & GLOB_NOCHECK)){cp = strcpy (PatternCopy, Pattern);while ((cp = strpbrk (cp, "?*[")) != (char *)NULL){if ((cp == PatternCopy) || (*(cp - 1) != '\\'))cp++;elsememmove (cp - 1, cp, strlen (cp) + 1);}if (ReturnValue = _GP_AddArgument (PatternCopy, gp)){alloca_free (PatternCopy);return ReturnValue;}}/* Terminate string */if ((gp->gl_pathc != 0) &&(ReturnValue = _GP_AddArgument ((char *)NULL, gp))){alloca_free (PatternCopy);return ReturnValue;}/* Get the sort length */ReturnValue = (gp->gl_flags & GLOB_DOOFFS) ? gp->gl_offs : 0;if ((!(flags & GLOB_NOSORT)) && (gp->gl_pathc > 1))qsort (&gp->gl_pathv[ReturnValue], gp->gl_pathc, sizeof (char *),(int (*) (const void *, const void *)) _GP_SortCompare);alloca_free (PatternCopy);return 0;}/* Compare function for sort */static int _GP_SortCompare (a1, a2)char **a1, **a2;{return strcmp (*a1, *a2);}/* Expand a field if it has metacharacters in it */static int _GP_ExpandField (CurrentDirectoryPattern, AppendString, gp)char *CurrentDirectoryPattern; /* Prefix field */char *AppendString; /* Postfix field */glob_t *gp;{int i;int ReturnValue = 0; /* Return Value */char *FullFileName; /* Search file name */char *FileNameStart;char *MatchString; /* Match string */DIR *DirHandler;struct dirent *CurrentDirectoryEntry;#if defined (MSDOS) || defined (__OS2__) || defined (__TURBOC__) || defined (WIN32)unsigned int CurrentDrive; /* Current drive */unsigned int MaxDrives; /* Max drive */unsigned int SelectedDrive; /* Selected drive */unsigned int x_drive, y_drive; /* Dummies */char *DriveCharacter; /* Multi-drive flag */char SDriveString[2];/* Convert file name to lower case */# if defined (OS2) || defined (__OS2__) || (WIN32)if (!IsHPFSFileSystem (CurrentDirectoryPattern))strlwr (CurrentDirectoryPattern);# elsestrlwr (CurrentDirectoryPattern);# endif/* Search all drives ? */if ((DriveCharacter = _GP_CheckForMultipleDrives (CurrentDirectoryPattern))!= (char *)NULL){_dos_getdrive (&CurrentDrive); /* Get number of drives */_dos_setdrive (CurrentDrive, &MaxDrives);SDriveString[1] = 0;for (SelectedDrive = 1; SelectedDrive <= MaxDrives; ++SelectedDrive){_dos_setdrive (SelectedDrive, &x_drive);_dos_getdrive (&y_drive);_dos_setdrive (CurrentDrive, &x_drive);/* Check to see if the second diskette drive is really there */if ((_GP_GetNumberofFloppyDrives () < 2) && (SelectedDrive == 2))continue;/* If the drive exists and is in our list - process it */*DriveCharacter = 0;*SDriveString = (char)(SelectedDrive + 'a' - 1);strlwr (CurrentDirectoryPattern);if ((y_drive == SelectedDrive) &&_GP_MatchPattern (SDriveString, CurrentDirectoryPattern)){if ((FullFileName = alloca (strlen (DriveCharacter) + 3))== (char *)NULL)return GLOB_NOSPACE;*DriveCharacter = ':';*FullFileName = *SDriveString;strcpy (FullFileName + 1, DriveCharacter);i = _GP_ExpandField (FullFileName, AppendString, gp);alloca_free (FullFileName);if (i)return i;}*DriveCharacter = ':';}return 0;}#endif/* Get the path length */MatchString = strrchr (CurrentDirectoryPattern, '/');#if defined (MSDOS) || defined (__OS2__) || defined (__TURBOC__) || defined (WIN32)if ((MatchString == (char *)NULL) &&(*(CurrentDirectoryPattern + 1) == ':'))MatchString = CurrentDirectoryPattern + 1;#endif/* Set up file name for search */if ((MatchString == (char *)NULL) || (*MatchString == ':')){if ((FullFileName = alloca (NAME_MAX + 7 +strlen (AppendString))) == (char *)NULL)return GLOB_NOSPACE;if (MatchString != (char *)NULL)*(strcpy (FullFileName, "x:.")) = *CurrentDirectoryPattern;elsestrcpy (FullFileName, ".");FileNameStart = FullFileName +(int)((MatchString != (char *)NULL) ? 2 : 0);}/* Case of /<directory>/... */else if ((FullFileName = alloca (NAME_MAX + 4 + strlen (AppendString) +(i = (int)(MatchString - CurrentDirectoryPattern))))== (char *)NULL)return GLOB_NOSPACE;else{strncpy (FullFileName, CurrentDirectoryPattern, i);*((FileNameStart = FullFileName + i)) = 0;strcpy (FileNameStart++, "/");}MatchString = (MatchString == (char *)NULL) ? CurrentDirectoryPattern: MatchString + 1;/* Search for file names */if ((DirHandler = opendir (FullFileName)) == (DIR *)NULL){i = 0;if (((gp->gl_ef != NULL) && (*gp->gl_ef)(FullFileName, errno)) ||(gp->gl_flags & GLOB_ERR))i = GLOB_ABEND;alloca_free (FullFileName);return i;}/* Are there any matches */while ((CurrentDirectoryEntry = readdir (DirHandler)) !=(struct dirent *)NULL){if ((*CurrentDirectoryEntry->d_name == '.') && (*MatchString != '.'))continue;/* Check for match */if (_GP_MatchPattern (CurrentDirectoryEntry->d_name, MatchString)){strcpy (FileNameStart, CurrentDirectoryEntry->d_name);/* If the postfix is not null, this must be a directory */if (strlen (AppendString)){struct stat statb;char *p;/* If not a directory - go to the next file */if (!_GP_stat (FullFileName, &statb) ||!S_ISDIR (statb.st_mode & S_IFMT))continue;/* Are there any metacharacters in the postfix? */if ((p = strpbrk (AppendString, _GP_MetaChars)) == (char *)NULL){/* No - build the file name and check it exists */strcat (strcat (FileNameStart, "/"), AppendString);if (_GP_access (FullFileName, F_OK) &&(ReturnValue = _GP_AddArgument (FullFileName, gp)))break;}/* Yes - build the filename upto the start of the meta characters */else{if ((p = strchr (p, '/')) != (char *)NULL)*(p++) = 0;elsep = _GP_NullString;/* Build the new directory name and check it out */strcat (strcat (FileNameStart, "/"), AppendString);ReturnValue = _GP_ExpandField (FullFileName, p, gp);if (p != _GP_NullString)*(--p) = '/';/* Check for errors */if (ReturnValue)break;}}/* Process this file. If error - terminate */else if (_GP_access (FullFileName, F_OK) &&(ReturnValue = _GP_AddArgument (FullFileName, gp)))break;}}closedir (DirHandler);alloca_free (FullFileName);return ReturnValue;}/* Find the location of meta-characters. If no meta, add the argument and* return. If meta characters, expand directory containing meta characters.*/static int _GP_ExpandMetaCharacters (file, gp)char *file;glob_t *gp;{char *p;int ReturnValue;/* No metas - add to string */if ((p = strpbrk (file, _GP_MetaChars)) == (char *)NULL){if (!_GP_access (file, F_OK))return 0;return _GP_AddArgument (file, gp);}/* Ok - metas, find the end of the start of the directory */else if ((p = strchr (p, '/')) != (char *)NULL)*(p++) = 0;elsep = _GP_NullString;/* Continue recusive match */ReturnValue = _GP_ExpandField (file, p, gp);/* Restore if necessary */if (p != _GP_NullString)*(--p) = '/';return ReturnValue;}/* Add an argument to the stack - file is assumed to be a array big enough* for the file name + 2*/static int _GP_AddArgument (file, gp)char *file;glob_t *gp;{int Offset;char **p1;struct stat FileStatus;Offset = gp->gl_pathc + ((gp->gl_flags & GLOB_DOOFFS) ? gp->gl_offs : 0);p1 = gp->gl_pathv;/* Malloc space if necessary */if (gp->gl_pathc == 0)p1 = (char **)calloc (sizeof (char *), (50 + Offset));else if ((gp->gl_pathc % 50) == 0)p1 = (char **)localRealloc (p1, (Offset + 50) * (sizeof (char *)));if (p1 == (char **)NULL)return GLOB_NOSPACE;/* OK got space */gp->gl_pathv = p1;/* End of list ? */if (file == (char *)NULL)p1[Offset] = (char *)NULL;else{if ((gp->gl_flags & GLOB_MARK) && (file[strlen (file) - 1] != '/') &&_GP_stat (file, &FileStatus) && (S_ISDIR (FileStatus.st_mode)))strcat (file, "/");if ((p1[Offset] = strdup (file)) == (char *)NULL)return GLOB_NOSPACE;strcpy (p1[Offset], file);/* Increment counter */++(gp->gl_pathc);}return 0;}/* Check for multi_drive prefix */#if defined (MSDOS) || defined (__OS2__) || defined (__TURBOC__) || defined (WIN32)static char *_GP_CheckForMultipleDrives (prefix)char *prefix;{if (strlen (prefix) < 2)return (char *)NULL;if (((*prefix == '*') || (*prefix == '?')) && (prefix[1] == ':'))return prefix + 1;if (*prefix != '[')return (char *)NULL;while (*prefix && (*prefix != ']')){if ((*prefix == '\\') && (*(prefix + 1)))++prefix;++prefix;}return (*prefix && (*(prefix + 1) == ':')) ? prefix + 1 : (char *)NULL;}/** Some Turboc Functions to emulate MSC functions*/# if defined (__TURBOC__)static void _dos_getdrive (cdp)unsigned int *cdp;{*cdp = (unsigned int)getdisk () + 1;}static void _dos_setdrive (cdr, ndp)unsigned int cdr;unsigned int *ndp;{*ndp = (unsigned int)setdisk (cdr - 1);}# endif/** Some OS/2 functions to emulate the DOS functions*/# if defined (OS2) || defined (__OS2__)static void _dos_getdrive (cdp)unsigned int *cdp;{USHORT cdr;ULONG ndr;DosQCurDisk((PUSHORT)&cdr, (PULONG) &ndr);*cdp = (unsigned int)cdr;}static void _dos_setdrive (cdr, ndp)unsigned int cdr;unsigned int *ndp;{ULONG ulDrives;USHORT usDisk;int i;DosSelectDisk ((USHORT)cdr);/* Get the current disk and check that to see the number of drives */DosQCurDisk (&usDisk, &ulDrives); /* gets current drive */for (i = 25; (!(ulDrives & (1L << i))) && (i >= 0); --i)continue;*ndp = i + 1;}# elif defined (WIN32)static void _dos_getdrive (cdp)unsigned int *cdp;{char szCurDir [MAX_PATH];GetCurrentDirectory (MAX_PATH, szCurDir);*cdp = (unsigned int)(szCurDir[0] - 'A' + 1);}static void _dos_setdrive (cdr, ndp)unsigned int cdr;unsigned int *ndp;{char szNewDrive[3];DWORD dwLogicalDrives;unsigned int i;szNewDrive[0] = cdr + 'A' - 1;szNewDrive[1] = ':';szNewDrive[2] = 0;*ndp = 0;if (!SetCurrentDirectory (szNewDrive))return;dwLogicalDrives = GetLogicalDrives ();for (i = 25; (!(dwLogicalDrives & (1L << i))) && i >= 0; --i)continue;*ndp = i + 1;}# endif/* Return the number of floppy disks */# if defined (OS2) || defined (__OS2__)static int _GP_GetNumberofFloppyDrives (){BYTE nflop = 1;DosDevConfig (&nflop, DEVINFO_FLOPPY, 0);return nflop;}# elif defined (WIN32)static int _GP_GetNumberofFloppyDrives (){char szNewDrive[4];DWORD dwLogicalDrives = GetLogicalDrives();int LastTest = 0;int i;strcpy (szNewDrive, "x:\\");/* Look at each drive until we find a non-floppy which exists */for (i = 0; i < 25; i++){if (dwLogicalDrives & (1L << i)){szNewDrive[0] = i + 'A';if (GetDriveType (szNewDrive) != DRIVE_REMOVABLE)break;LastTest = i + 1;}}return LastTest;}# elif defined (__TURBOC__)static int _GP_GetNumberofFloppyDrives (){return ((biosequip () & 0x00c0) >> 6) + 1;}# elsestatic int _GP_GetNumberofFloppyDrives (){return ((_bios_equiplist () & 0x00c0) >> 6) + 1;}# endif#endif/** Pattern Matching function*/static bool _GP_MatchPattern (string, pattern)char *string; /* String to match */char *pattern; /* Pattern to match against */{register int cur_s; /* Current string character */register int cur_p; /* Current pattern character *//* Match string */while (cur_p = *(pattern++)){cur_s = *(string++); /* Load current string character */switch (cur_p) /* Switch on pattern character */{case '[': /* Match class of characters */{while(1){if (!(cur_p = *(pattern++)))return 0;if (cur_p == ']')return FALSE;if (cur_s != cur_p){if (*pattern == '-'){if(cur_p > cur_s)continue;if (cur_s > *(++pattern))continue;}elsecontinue;}break;}while (*pattern){if (*(pattern++) == ']')break;}break;}case '?': /* Match any character */{if (!cur_s)return FALSE;break;}case '*': /* Match any number of any character*/{string--;do{if (_GP_MatchPattern (string, pattern))return TRUE;}while (*(string++));return FALSE;}case '\\': /* Next character is non-meta */{if (!(cur_p = *(pattern++)))return FALSE;}default: /* Match against current pattern */{if (cur_p != cur_s)return FALSE;break;}}}return (!*string) ? TRUE : FALSE;}/** Local Stat function to do some additional checks*/static bool _GP_stat (char *FileName, struct stat *Status){int rc;DISABLE_HARD_ERRORS;rc = stat (FileName, Status);ENABLE_HARD_ERRORS;return rc ? FALSE : TRUE;}/** Local access function to do some additional checks*/static bool _GP_access (char *FileName, int mode){int rc;DISABLE_HARD_ERRORS;rc = access (FileName, mode);ENABLE_HARD_ERRORS;return rc ? FALSE : TRUE;}/** Test program*/#ifdef TESTint main (int argc, char **argv){int i;for (i = 0; i < argc; i++)printf ("Arg %d = <%s>\n", i, argv[i]);return 0;}#endif