300 lines
6.5 KiB
C
300 lines
6.5 KiB
C
/***
|
|
*wild.c - wildcard expander
|
|
*
|
|
* Copyright (c) 1985-1990, Microsoft Corporation. All rights reserved.
|
|
*
|
|
*Purpose:
|
|
* expands wildcards 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)
|
|
*
|
|
*******************************************************************************/
|
|
|
|
#include <stdio.h>
|
|
#include <register.h>
|
|
#include <ctype.h>
|
|
#include <msdos.h>
|
|
|
|
|
|
/*
|
|
** these are the data structures
|
|
**
|
|
** __argv
|
|
** ------- ------
|
|
** | |---->| |---->"arg0"
|
|
** ------- ------
|
|
** | |---->"arg1"
|
|
** ------
|
|
** ....
|
|
** ------
|
|
** | |---->"argn"
|
|
** ------
|
|
** |NULL|
|
|
** ------
|
|
** argend
|
|
** -------
|
|
** ------- | |
|
|
** | | __argc -------
|
|
** ------- |
|
|
** |
|
|
** arghead V
|
|
** ------ --------- ----------
|
|
** | |---->| | |----> .... ---->| |NULL|
|
|
** ------ --------- ----------
|
|
** | |
|
|
** V V
|
|
** "narg0" "nargn"
|
|
*/
|
|
|
|
#define SLASHCHAR '\\'
|
|
#define FWDSLASHCHAR '/'
|
|
#define SLASH "\\"
|
|
#define FWDSLASH "/"
|
|
#define STAR "*.*"
|
|
|
|
#define WILDSTRING "*?"
|
|
|
|
char *strdup();
|
|
char *strpbrk();
|
|
char *strcpy();
|
|
char *strncpy();
|
|
char *strcat();
|
|
char *malloc();
|
|
char *_find();
|
|
|
|
static int match ();
|
|
static int add ();
|
|
static sort ();
|
|
|
|
extern int __argc;
|
|
extern char * * __argv;
|
|
|
|
struct argnode {
|
|
char *argptr;
|
|
struct argnode *nextnode;
|
|
};
|
|
|
|
static struct argnode *arghead;
|
|
static struct argnode *argend;
|
|
|
|
/***
|
|
*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:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
int
|
|
_cwild ()
|
|
{
|
|
REG1 char **argv = __argv;
|
|
REG2 struct argnode *nodeptr;
|
|
REG3 int argc;
|
|
REG4 char **tmp;
|
|
char *wchar;
|
|
int ptr, sptr, arglen;
|
|
|
|
arghead = argend = NULL;
|
|
|
|
for (argv = __argv; *argv; argv++) /* for each arg... */
|
|
if ( *(*argv)++ == '"' )
|
|
/* strip leading quote from quoted arg */
|
|
{
|
|
if (add(*argv))
|
|
return(-1);
|
|
}
|
|
else if (wchar = strpbrk( *argv, WILDSTRING )) {
|
|
/* attempt to expand arg with wildcard */
|
|
if (match( *argv, wchar ))
|
|
return(-1);
|
|
}
|
|
else if (add( *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 = (char **)malloc(sizeof(char *)*(argc+1))))
|
|
return(-1);
|
|
|
|
/* the new arg vector... */
|
|
__argv = tmp;
|
|
|
|
/* 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(nodeptr);
|
|
}
|
|
|
|
/* return success */
|
|
return(0);
|
|
}
|
|
|
|
|
|
/***
|
|
*match(arg, ptr) - [STATIC]
|
|
*
|
|
*Purpose:
|
|
*
|
|
*Entry:
|
|
*
|
|
*Exit:
|
|
*
|
|
*Exceptions:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
static int
|
|
match (arg, ptr)
|
|
REG4 char *arg;
|
|
REG1 char *ptr;
|
|
{
|
|
REG2 char *new;
|
|
REG3 int length;
|
|
char *all;
|
|
REG5 struct argnode *first;
|
|
REG6 int gotone = 0;
|
|
|
|
while (ptr != arg && *ptr != SLASHCHAR && *ptr != FWDSLASHCHAR
|
|
&& *ptr != ':') {
|
|
/* find first slash or ':' before wildcard */
|
|
ptr--;
|
|
}
|
|
|
|
if (*ptr == ':' && ptr != arg+1) /* weird name, just add it as is */
|
|
return(add(arg));
|
|
|
|
if (*ptr == SLASHCHAR || *ptr == FWDSLASHCHAR
|
|
|| *ptr == ':') /* pathname */
|
|
length = ptr - arg + 1; /* length of dir prefix */
|
|
|
|
if (new = _find(arg)) { /* get the first file name */
|
|
first = argend;
|
|
|
|
do { /* got a file name */
|
|
if (strcmp(new, ".") && strcmp(new, "..")) {
|
|
if (*ptr != SLASHCHAR && *ptr != ':'
|
|
&& *ptr != FWDSLASHCHAR ) {
|
|
/* current directory; don't need path */
|
|
if (!(arg = strdup(new)) || add(arg))
|
|
return(-1);
|
|
}
|
|
else /* add full pathname */
|
|
if (!(all=malloc(length+strlen(new)+1))
|
|
|| add(strcpy(strncpy(all,arg,length)+length,new)
|
|
- length))
|
|
return(-1);
|
|
|
|
gotone++;
|
|
}
|
|
|
|
}
|
|
while (new = _find(NULL)); /* get following files */
|
|
|
|
if (gotone) {
|
|
sort(first ? first->nextnode : arghead);
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
return(add(arg)); /* no match */
|
|
}
|
|
|
|
/***
|
|
*add(arg) - [STATIC]
|
|
*
|
|
*Purpose:
|
|
*
|
|
*Entry:
|
|
*
|
|
*Exit:
|
|
*
|
|
*Exceptions:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
static int
|
|
add (arg)
|
|
char *arg;
|
|
{
|
|
REG1 struct argnode *nodeptr;
|
|
|
|
if (!(nodeptr = (struct argnode *)malloc(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:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
static
|
|
sort (first)
|
|
REG2 struct argnode *first;
|
|
{
|
|
REG1 struct argnode *nodeptr;
|
|
REG3 char *temp;
|
|
|
|
if (first) /* something to sort */
|
|
while (nodeptr = first->nextnode) {
|
|
do {
|
|
if (strcmp(nodeptr->argptr, first->argptr) < 0) {
|
|
temp = first->argptr;
|
|
first->argptr = nodeptr->argptr;
|
|
nodeptr->argptr = temp;
|
|
}
|
|
}
|
|
while (nodeptr = nodeptr->nextnode);
|
|
|
|
first = first->nextnode;
|
|
}
|
|
}
|