home *** CD-ROM | disk | FTP | other *** search
- /* MS-DOS GLOB (3C) FUNCTION
- *
- * MS-DOS GLOB FUNCTION - Copyright (c) 1990,1,2 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: c:/usr/src/shell/rcs/glob.c 2.0 1992/04/13 17:39:09 Ian_Stewartson Exp $
- *
- * $Log: glob.c $
- * 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 */
- #include <malloc.h> /* Malloc functions */
- #include <glob.h>
- #ifdef MSDOS
- #ifdef OS2
- #define INCL_DOSDEVICES
- #include <os2.h> /* OS2 functions declarations */
- #else
- #include <bios.h> /* DOS BIOS functions */
- #include <dos.h> /* DOS functions */
- #endif
- #endif
-
- 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 char *_GP_MetaChars = "?*[\\";
- static char *_GP_NullString = "";
-
- #ifdef MSDOS
- static int _GP_GetNumberofFloppyDrives (void);
-
- #ifdef OS2
- static void _dos_setdrive (unsigned int, unsigned int *);
- static void _dos_getdrive (unsigned int *);
- #endif
-
- static char *_GP_CheckForMultipleDrives _PROTO ((char *));
- #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))
- 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++;
-
- else
- memmove (cp - 1, cp, strlen (cp) + 1);
- }
-
- if (ReturnValue = _GP_AddArgument (PatternCopy, gp))
- return ReturnValue;
- }
-
- /* Terminate string */
-
- if ((gp->gl_pathc != 0) && (ReturnValue = _GP_AddArgument ((char *)NULL, gp)))
- 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 *),
- _GP_SortCompare);
-
- 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;
- #ifdef MSDOS
- 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 */
-
- #ifndef OS2
- strlwr (CurrentDirectoryPattern);
- #else
- if (!IsHPFSFileSystem (CurrentDirectoryPattern))
- strlwr (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);
-
- if (i = _GP_ExpandField (FullFileName, AppendString, gp))
- return i;
- }
-
- *DriveCharacter = ':';
- }
-
- return 0;
- }
- #endif
-
- /* Get the path length */
-
- MatchString = strrchr (CurrentDirectoryPattern, '/');
- #ifdef MSDOS
- 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;
-
- else
- strcpy (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;
-
- 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 (stat (FullFileName, &statb) < 0 ||
- !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 ((access (FullFileName, F_OK) == 0) &&
- (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;
-
- else
- p = _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 ((access (FullFileName, F_OK) == 0) &&
- (ReturnValue = _GP_AddArgument (FullFileName, gp)))
- break;
- }
- }
-
- closedir (DirHandler);
- 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 (access (file, F_OK) < 0)
- 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;
-
- else
- p = _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 **)realloc (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] != '/') &&
- (stat (file, &FileStatus) == 0) && (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;
- }
-
- #ifdef MSDOS
- /* Check for multi_drive prefix */
-
- 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 OS/2 functions to emulate the DOS functions */
-
- #ifdef 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 = (unsigned int)(i + 1);
- }
- #endif
-
- /* Return the number of floppy disks */
-
- static int _GP_GetNumberofFloppyDrives ()
- {
- #ifdef OS2
- BYTE nflop = 1;
- DosDevConfig (&nflop, DEVINFO_FLOPPY, 0);
- return nflop;
- #else
- 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;
- }
- else
- continue;
- }
-
- 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;
- }
-
- /*
- * Test program
- */
-
- #ifdef TEST
- main (int argc, char **argv)
- {
- int i;
-
- for (i = 0; i < argc; i++)
- printf ("Arg %d = <%s>\n", i, argv[i]);
- }
- #endif
-