|
|
/***
*wild.c - wildcard expander * * Copyright (c) 1985-2001, Microsoft Corporation. All rights reserved. * *Purpose: * expands wildcards in argv * * handles '*' (none or more of any char) and '?' (exactly one char) * *Revision History: * 05-21-84 RN initial version * 06-07-85 TDC since dos accepts forward slash, added * code to accept forward slash in a manner consistent * with reverse slash. * 09-20-86 SKS Modified for OS/2 * All argument strings to this function have a * leading flag character. If the flag is a quote, * that argument string was quoted on the command * line and should have not wildcard expansion. In all * cases the leading flag character is removed from * the string. * 11-11-86 JMB Added Kanji support under KANJI switch. * 09-21-88 WAJ initial 386 version * 04-09-90 GJF Added #include <cruntime.h> and removed #include * <register.h>. Made calling types explicit (_CALLTYPE1 * or _CALLTYPE4). Also, fixed the copyright. * 04-10-90 GJF Added #include <internal.h> and fixed compiler warnings * (-W3). * 07-03-90 SBM Compiles cleanly with -W3 under KANJI, removed * redundant includes, removed #include <internal.h> * to keep wild.c free of private stuff, should we * decide to release it * 09-07-90 SBM put #include <internal.h> back in, reason for * removing it discovered to be horribly bogus * 10-08-90 GJF New-style function declarators. * 01-18-91 GJF ANSI naming. * 04-06-93 SKS Replace _CRTAPI* with __cdecl * Remove explicit declarations of __argc & __argv. * They are declared in <stdlib.h> * 05-05-93 SKS Filename sorting should be case-insensitive * 06-09-93 KRS Update _MBCS support. * 10-20-93 GJF Merged in NT version. * 11-23-93 CFW Wide char enable, grab _find from stdargv.c. * 12-07-93 CFW Change _TCHAR to _TSCHAR. * 04-22-94 GJF Made defintions of arghead, argend, _WildFindHandle * and findbuf conditional on DLL_FOR_WIN32S. * 01-10-95 CFW Debug CRT allocs. * 01-18-95 GJF Must replace _tcsdup with _malloc_crt/_tcscpy for * _DEBUG build. * 02-04-98 GJF Changes for Win64: use intptr_t and ptrdiff_t casts * where appropriate. * 02-19-01 GB added check for return value of malloc in find. * *******************************************************************************/
#include <cruntime.h>
#include <oscalls.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <msdos.h>
#include <internal.h>
#include <tchar.h>
#ifdef _MBCS
#include <mbdata.h>
#include <mbstring.h>
#endif
#include <dbgint.h>
/*
** these are the data structures ** ** __argv ** ------- ------ ** | |---->| |---->"arg0" ** ------- ------ ** | |---->"arg1" ** ------ ** .... ** ------ ** | |---->"argn" ** ------ ** |NULL| ** ------ ** argend ** ------- ** ------- | | ** | | __argc ------- ** ------- | ** | ** arghead V ** ------ --------- ---------- ** | |---->| | |----> .... ---->| |NULL| ** ------ --------- ---------- ** | | ** V V ** "narg0" "nargn" */
#define ERRORHANDLE ((HANDLE)(intptr_t)(-1))
/* local function tchars */ #ifdef WPRFLAG
#define tmatch wmatch
#define tadd wadd
#define tsort wsort
#define tfind wfind
#else
#define tmatch match
#define tadd add
#define tsort sort
#define tfind find
#endif
#define SLASHCHAR _T('\\')
#define FWDSLASHCHAR _T('/')
#define COLONCHAR _T(':')
#define QUOTECHAR _T('"')
#define SLASH _T("\\")
#define FWDSLASH _T("/")
#define STAR _T("*.*")
#define DOT _T(".")
#define DOTDOT _T("..")
#define WILDSTRING _T("*?")
struct argnode { _TSCHAR *argptr; struct argnode *nextnode; };
static struct argnode *arghead; static struct argnode *argend;
#ifdef WPRFLAG
static int __cdecl wmatch(wchar_t *, wchar_t *); static int __cdecl wadd(wchar_t *); static void __cdecl wsort(struct argnode *); static wchar_t * __cdecl wfind (wchar_t *pattern); #else
static int __cdecl match(char *, char *); static int __cdecl add(char *); static void __cdecl sort(struct argnode *); static char * __cdecl find (char *pattern); #endif
/***
*int _cwild() - wildcard expander * *Purpose: * expands wildcard in file specs in argv * * handles '*' (none or more of any char), '?' (exactly one char), and * '[string]' (chars which match string chars or between n1 and n2 * if 'n1-n2' in string inclusive) * *Entry: * *Exit: * returns 0 if successful, -1 if any malloc() calls fail * if problems with malloc, the old argc and argv are not touched * *Exceptions: * *******************************************************************************/
#ifdef WPRFLAG
int __cdecl _wcwild ( #else
int __cdecl _cwild ( #endif
void ) { #ifdef WPRFLAG
REG1 wchar_t **argv = __wargv; #else
REG1 char **argv = __argv; #endif
REG2 struct argnode *nodeptr; REG3 int argc; REG4 _TSCHAR **tmp; _TSCHAR *wchar;
arghead = argend = NULL;
#ifdef WPRFLAG
for (argv = __wargv; *argv; argv++) /* for each arg... */ #else
for (argv = __argv; *argv; argv++) /* for each arg... */ #endif
if ( *(*argv)++ == QUOTECHAR ) /* strip leading quote from quoted arg */ { if (tadd(*argv)) return(-1); } else if (wchar = _tcspbrk( *argv, WILDSTRING )) { /* attempt to expand arg with wildcard */ if (tmatch( *argv, wchar )) return(-1); } else if (tadd( *argv )) /* normal arg, just add */ return(-1);
/* count the args */ for (argc = 0, nodeptr = arghead; nodeptr; nodeptr = nodeptr->nextnode, argc++) ;
/* try to get new arg vector */ if (!(tmp = (_TSCHAR **)_malloc_crt(sizeof(_TSCHAR *)*(argc+1)))) return(-1);
/* the new arg vector... */ #ifdef WPRFLAG
__wargv = tmp; #else
__argv = tmp; #endif
/* the new arg count... */ __argc = argc;
/* install the new args */ for (nodeptr = arghead; nodeptr; nodeptr = nodeptr->nextnode) *tmp++ = nodeptr->argptr;
/* the terminal NULL */ *tmp = NULL;
/* free up local data */ for (nodeptr = arghead; nodeptr; nodeptr = arghead) { arghead = arghead->nextnode; _free_crt(nodeptr); }
/* return success */ return(0); }
/***
*match(arg, ptr) - [STATIC] * *Purpose: * *Entry: * *Exit: * *Exceptions: * *******************************************************************************/
#ifdef WPRFLAG
static int __cdecl wmatch ( #else
static int __cdecl match ( #endif
REG4 _TSCHAR *arg, REG1 _TSCHAR *ptr ) { REG2 _TSCHAR *new; REG3 int length = 0; _TSCHAR *all; REG5 struct argnode *first; REG6 int gotone = 0;
while (ptr != arg && *ptr != SLASHCHAR && *ptr != FWDSLASHCHAR && *ptr != COLONCHAR) { /* find first slash or ':' before wildcard */ #ifdef _MBCS
if (--ptr > arg) ptr = _mbsdec(arg,ptr+1); #else
ptr--; #endif
}
if (*ptr == COLONCHAR && ptr != arg+1) /* weird name, just add it as is */ return(tadd(arg));
if (*ptr == SLASHCHAR || *ptr == FWDSLASHCHAR || *ptr == COLONCHAR) /* pathname */ length = (int)(ptrdiff_t)(ptr - arg + 1); /* length of dir prefix */
if (new = tfind(arg)) { /* get the first file name */ first = argend;
do { /* got a file name */ if (_tcscmp(new, DOT) && _tcscmp(new, DOTDOT)) { if (*ptr != SLASHCHAR && *ptr != COLONCHAR && *ptr != FWDSLASHCHAR ) { /* current directory; don't need path */ #ifdef _DEBUG
if (!(arg=_malloc_crt((_tcslen(new)+1)*sizeof(_TSCHAR))) || tadd(_tcscpy(arg,new))) #else /* ndef _DEBUG */
if (!(arg = _tcsdup(new)) || tadd(arg)) #endif /* _DEBUG */
return(-1); } else /* add full pathname */ if (!(all=_malloc_crt((length+_tcslen(new)+1)*sizeof(_TSCHAR))) || tadd(_tcscpy(_tcsncpy(all,arg,length)+length,new) - length)) return(-1);
gotone++; }
} while (new = tfind(NULL)); /* get following files */
if (gotone) { tsort(first ? first->nextnode : arghead); return(0); } }
return(tadd(arg)); /* no match */ }
/***
*add(arg) - [STATIC] * *Purpose: * *Entry: * *Exit: * *Exceptions: * *******************************************************************************/
#ifdef WPRFLAG
static int __cdecl wadd ( #else
static int __cdecl add ( #endif
_TSCHAR *arg ) { REG1 struct argnode *nodeptr;
if (!(nodeptr = (struct argnode *)_malloc_crt(sizeof(struct argnode)))) return(-1);
nodeptr->argptr = arg; nodeptr->nextnode = NULL;
if (arghead) argend->nextnode = nodeptr; else arghead = nodeptr;
argend = nodeptr; return(0); }
/***
*sort(first) - [STATIC] * *Purpose: * *Entry: * *Exit: * *Exceptions: * *******************************************************************************/
#ifdef WPRFLAG
static void __cdecl wsort ( #else
static void __cdecl sort ( #endif
REG2 struct argnode *first ) { REG1 struct argnode *nodeptr; REG3 _TSCHAR *temp;
if (first) /* something to sort */ while (nodeptr = first->nextnode) { do { #ifdef _POSIX_
if (_tcscmp(nodeptr->argptr, first->argptr) < 0) { #else
if (_tcsicmp(nodeptr->argptr, first->argptr) < 0) { #endif /* _POSIX_ */
temp = first->argptr; first->argptr = nodeptr->argptr; nodeptr->argptr = temp; } } while (nodeptr = nodeptr->nextnode);
first = first->nextnode; } }
/***
*find(pattern) - find matching filename * *Purpose: * if argument is non-null, do a DOSFINDFIRST on that pattern * otherwise do a DOSFINDNEXT call. Return matching filename * or NULL if no more matches. * *Entry: * pattern = pointer to pattern or NULL * (NULL means find next matching filename) * *Exit: * returns pointer to matching file name * or NULL if no more matches. * *Exceptions: * *******************************************************************************/
#ifdef WPRFLAG
static wchar_t * __cdecl wfind ( #else
static char * __cdecl find ( #endif /* WPRFLAG */
_TSCHAR *pattern ) { _TSCHAR *retval;
static HANDLE _WildFindHandle; static LPWIN32_FIND_DATA findbuf;
if (pattern) { if (findbuf == NULL) if ((findbuf = (LPWIN32_FIND_DATA)_malloc_crt(MAX_PATH + sizeof(*findbuf))) == NULL) return NULL;
if (_WildFindHandle != NULL) { (void)FindClose( _WildFindHandle ); _WildFindHandle = NULL; }
_WildFindHandle = FindFirstFile( (LPTSTR)pattern, findbuf ); if (_WildFindHandle == ERRORHANDLE) return NULL; } else if (!FindNextFile( _WildFindHandle, findbuf )) { (void)FindClose( _WildFindHandle ); _WildFindHandle = NULL; return NULL; }
retval = findbuf->cFileName;
return retval; }
|