static char *RCSid = "$Header: arcdir.c,v 1.2 86/07/15 07:52:56 turner Exp $"; /* * $Log: arcdir.c,v $ * Hack-attack 1.3 86/12/20 01:23:45 wilhite@usceast.uucp * Bludgeoned into submission for VAX 11/780 BSD4.2 * (ugly code, but fewer core dumps) * * Revision 1.2 86/07/15 07:52:56 turner * * * Revision 1.1 86/06/26 15:00:12 turner * initial version * * */ /* ARC - Archive utility - ARCDIR */ #include #include "arc.h" #if MSDOS #include #endif #ifndef VAXC #if BSD #include #include #endif #else #include "dir.h" #endif char *pattern; /* global so that fmatch can use them */ INT filemode; extern char *dir(filename,mode,NameList) /* get files, one by one */ char *filename; /* template, or NULL */ INT mode; /* search mode bits */ char *(*NameList[]); { /* struct direct *(*namelist[]); */ static struct direct *(**namelist), *np; #ifdef BSD INT alphasort(); INT scandir(); #endif BSD INT fmatch(); static INT Nnum = 0,ii; char *result; pattern = filename; filemode = mode; /* set up globals for fmatch */ if(Nnum == 0) { /* first call */ /* cmb */ namelist = (char **)malloc(sizeof(char **)); Nnum = scandir(".", namelist, fmatch, alphasort); *NameList = (char **)malloc(Nnum*sizeof(char *)); for (ii=0; iid_namlen+1); * strcpy((*NameList)[ii],(*namelist)[ii]->d_name); */ (*NameList)[ii] = (char *)malloc((*namelist)[ii]->d_namlen+1); strcpy((*NameList)[ii],(*namelist)[ii]->d_name); } ii = 0; } if(ii >= Nnum) { /* all out of files */ if(Nnum) { /* there were some files found */ freedir(namelist); } Nnum = 0; return(NULL); } else { return((*NameList)[ii++]); } } #define ASTERISK '*' /* The '*' metacharacter */ #define QUESTION '?' /* The '?' metacharacter */ #define LEFT_BRACKET '[' /* The '[' metacharacter */ #define RIGHT_BRACKET ']' /* The ']' metacharacter */ #define IS_OCTAL(ch) (ch >= '0' && ch <= '7') typedef INT BOOLEAN; #define VOID short #define TRUE 1 #define FALSE 0 #define EOS '\000' static BOOLEAN do_list (); static char nextch (); static VOID list_parse (); /* * FUNCTION * * match test string for wildcard match * * SYNOPSIS * * BOOLEAN match (string, pattern) * register char *string; * register char *pattern; * * DESCRIPTION * * Test string for match using pattern. The pattern may * contain the normal shell metacharacters for pattern * matching. The '*' character matches any string, * including the null string. The '?' character matches * any single character. A list of characters enclosed * in '[' and ']' matches any character in the list. * If the first character following the beginning '[' * is a '!' then any character not in the list is matched. * */ /* * PSEUDO CODE * * Begin match * Switch on type of pattern character * Case ASTERISK: * Attempt to match asterisk * Break * Case QUESTION MARK: * Attempt to match question mark * Break * Case EOS: * Match is result of EOS on string test * Break * Case default: * If explicit match then * Match is result of submatch * Else * Match is FALSE * End if * Break * End switch * Return result of match test * End match * */ static BOOLEAN match (string, pattern) register char *string; register char *pattern; { register BOOLEAN ismatch; ismatch = FALSE; switch (*pattern) { case ASTERISK: pattern++; do { ismatch = match (string, pattern); } while (!ismatch && *string++ != EOS); break; case QUESTION: if (*string != EOS) { ismatch = match (++string, ++pattern); } break; case EOS: if (*string == EOS) { ismatch = TRUE; } break; case LEFT_BRACKET: if (*string != EOS) { ismatch = do_list (string, pattern); } break; default: if (tolower(*string) == tolower(*pattern)) { string++; pattern++; ismatch = match (string, pattern); } else { ismatch = FALSE; } break; } return (ismatch); } /* * FUNCTION * * do_list process a list and following substring * * SYNOPSIS * * static BOOLEAN do_list (string, pattern) * register char *string; * register char *pattern; * * DESCRIPTION * * Called when a list is found in the pattern. Returns * TRUE if the current character matches the list and * the remaining substring matches the remaining pattern. * * Returns FALSE if either the current character fails to * match the list or the list matches but the remaining * substring and subpattern's don't. * * RESTRICTIONS * * The mechanism used to match characters in an inclusive * pair (I.E. [a-d]) may not be portable to machines * in which the native character set is not ASCII. * * The rules implemented here are: * * (1) The backslash character may be * used to quote any special character. * I.E. "\]" and "\-" anywhere in list, * or "\!" at start of list. * * (2) The sequence \nnn becomes the character * given by nnn (in octal). * * (3) Any non-escaped ']' marks the end of list. * * (4) A list beginning with the special character * '!' matches any character NOT in list. * The '!' character is only special if it * is the first character in the list. * */ /* * PSEUDO CODE * * Begin do_list * Default result is no match * Skip over the opening left bracket * If the next pattern character is a '!' then * List match gives FALSE * Skip over the '!' character * Else * List match gives TRUE * End if * While not at closing bracket or EOS * Get lower and upper bounds * If character in bounds then * Result is same as sense flag. * Skip over rest of list * End if * End while * If match found then * If not at end of pattern then * Call match with rest of pattern * End if * End if * Return match result * End do_list * */ static BOOLEAN do_list (string, pattern) register char *string; char *pattern; { register BOOLEAN ismatch; register BOOLEAN if_found; register BOOLEAN if_not_found; auto char lower; auto char upper; pattern++; if (*pattern == '!') { if_found = FALSE; if_not_found = TRUE; pattern++; } else { if_found = TRUE; if_not_found = FALSE; } ismatch = if_not_found; while (*pattern != ']' && *pattern != EOS) { list_parse (&pattern, &lower, &upper); if (*string >= lower && *string <= upper) { ismatch = if_found; while (*pattern != ']' && *pattern != EOS) {pattern++;} } } if (*pattern++ != ']') { fprintf (stderr, "warning - character class error\n"); } else { if (ismatch) { ismatch = match (++string, pattern); } } return (ismatch); } /* * FUNCTION * * list_parse parse part of list into lower and upper bounds * * SYNOPSIS * * static VOID list_parse (patp, lowp, highp) * char **patp; * char *lowp; * char *highp; * * DESCRIPTION * * Given pointer to a pattern pointer (patp), pointer to * a place to store lower bound (lowp), and pointer to a * place to store upper bound (highp), parses part of * the list, updating the pattern pointer in the process. * * For list characters which are not part of a range, * the lower and upper bounds are set to that character. * */ static VOID list_parse (patp, lowp, highp) char **patp; char *lowp; char *highp; { *lowp = nextch (patp); if (**patp == '-') { (*patp)++; *highp = nextch (patp); } else { *highp = *lowp; } } /* * FUNCTION * * nextch determine next character in a pattern * * SYNOPSIS * * static char nextch (patp) * char **patp; * * DESCRIPTION * * Given pointer to a pointer to a pattern, uses the pattern * pointer to determine the next character in the pattern, * subject to translation of backslash-char and backslash-octal * sequences. * * The character pointer is updated to point at the next pattern * character to be processed. * */ static char nextch (patp) char **patp; { register char ch; register char chsum; register INT count; ch = *(*patp)++; if (ch == '\\') { ch = *(*patp)++; if (IS_OCTAL (ch)) { chsum = 0; for (count = 0; count < 3 && IS_OCTAL (ch); count++) { chsum *= 8; chsum += ch - '0'; ch = *(*patp)++; } (*patp)--; ch = chsum; } } return (ch); } /* * Filename match - here, *.* matches everything */ BOOLEAN fmatch (direntry) struct direct *direntry; { char *ptr,*string; string = direntry->d_name; if(!strcmp(pattern, "") || !strcmp(pattern, "*.*")) return(1); return(match(string, pattern)); }