home *** CD-ROM | disk | FTP | other *** search
- /* flist_unix.c 4/24/91
- *
- * Copyright 1991 Perry R. Ross
- *
- * Permission to use, copy, modify, and distribute this software and its
- * documentation without fee is hereby granted, subject to the restrictions
- * detailed in the README file, which is included here by reference.
- * Any other use requires written permission from the author. This software
- * is distributed "as is" without any warranty, including any implied
- * warranties of merchantability or fitness for a particular purpose.
- * The author shall not be liable for any damages resulting from the
- * use of this software. By using this software, the user agrees
- * to these terms.
- */
-
- /* This file uses the "regex-glob" routines, written by John Kercheval, and
- * posted to comp.sources.misc. The code appears at the end of this
- * file with all original comments.
- */
-
- #include "ldb.h"
-
-
- /*----------------------------------------------------------------------
- * filelist -- generate a list of all matching files.
- *
- * This function generates a list of all files that match a pattern.
- * Each file is stored in an instance of struct flist, which just
- * links the names in a linked list. A pointer to the beginning of
- * the list is returned. It is the callers responsibility to free
- * the list when it is no longer needed.
- *
- * This function will only recognize wildcards in file names, NOT
- * the directories leading up to them. For example, nuts/ldb*.txt is
- * fine, but *ts/ldb*.txt is not.
- *
- * This function uses the "new" directory routines (i.e. opendir,
- * readdir, et. al). If these are not on your system, you should
- * have defined NEED_READDIR in your Makefile.
- *----------------------------------------------------------------------
- */
-
- struct flist *filelist(ptn)
- char *ptn;
- {
- struct flist *head, *tail, *cur;
- DIR *dp;
- char *s;
- char *dn, *pn;
- struct direct *p;
-
- head = NULL;
- if (is_pattern(ptn) == 0) { /* no wildcards, just a file name */
- if ( (cur = (struct flist *) calloc(sizeof(struct flist),1)) == NULL)
- fatal("Out of memory!");
- head = cur;
- tail = cur;
- cur->name = save(ptn);
- return(cur);
- }
- if ( (s = strrchr(ptn,'/')) != NULL) { /* strip off directory name */
- *s = '\0';
- dn = save(ptn); /* dir = everything before last / */
- pn = save(s+1); /* pattern = everything after last / */
- *s = '/';
- }
- else {
- dn = save(".");
- pn = save(ptn);
- }
- if ( (dp = opendir(dn)) == NULL) {
- free(dn);
- free(pn);
- return(NULL);
- }
- while ( (p = readdir(dp)) != NULL) {
- if ( (strcmp(p->d_name,".") == 0) || (strcmp(p->d_name,"..") == 0) )
- continue;
- if (match(pn,p->d_name) == 0)
- continue;
- if ( (cur = (struct flist *) calloc(sizeof(struct flist),1)) == NULL)
- fatal("Out of memory!");
- if (head == NULL) {
- head = cur;
- tail = cur;
- }
- else {
- tail->next = cur;
- tail = cur;
- }
- if (strcmp(dn,".") == 0) /* file in current dir */
- cur->name = save(p->d_name); /* just save name */
- else { /* include directory name */
- cur->name = (char *) malloc(strlen(dn)+strlen(p->d_name)+2);
- if (cur->name == NULL)
- fatal("Out of memory!");
- sprintf(cur->name,"%s/%s",dn,p->d_name);
- }
- }
- closedir(dp);
- free(dn);
- free(pn);
- return(head);
- }
-
-
- /* regex-glob code follows: (de-ansified by P. Ross -- sorry) */
-
- /*
- EPSHeader
-
- File: match.c
- Author: J. Kercheval
- Created: Sat, 01/05/1991 22:21:49
- */
- /*
- EPSRevision History
-
- J. Kercheval Wed, 02/20/1991 22:29:01 Released to Public Domain
- */
-
- /*
- Wildcard Pattern Matching
- */
-
-
- /* #include "match.h" -- match.h included here for simplicity P. Ross */
-
- /*
- EPSHeader
-
- File: match.h
- Author: J. Kercheval
- Created: Sat, 01/05/1991 22:27:18
- */
- /*
- EPSRevision History
-
- J. Kercheval Wed, 02/20/1991 22:28:37 Released to Public Domain
- */
-
- /*
- Wildcard Pattern Matching
- */
-
- #ifndef BOOLEAN
- # define BOOLEAN int
- #undef TRUE
- #undef FALSE
- # define TRUE 1
- # define FALSE 0
- #endif
-
- /*----------------------------------------------------------------------------
- *
- * Match the pattern PATTERN against the string TEXT;
- * return TRUE if it matches, FALSE otherwise.
- *
- * A match means the entire string TEXT is used up in matching.
- *
- * In the pattern string:
- * `*' matches any sequence of characters
- * `?' matches any character
- * [SET] matches any character in the specified set,
- * [!SET] or [^SET] matches any character not in the specified set.
- *
- * Note: the standard regex character '+' (one or more) should by
- * simulated by using "?*" which is equivelant here.
- *
- * A set is composed of characters or ranges; a range looks like
- * character hyphen character (as in 0-9 or A-Z).
- * [0-9a-zA-Z_] is the set of characters allowed in C identifiers.
- * Any other character in the pattern must be matched exactly.
- *
- * To suppress the special syntactic significance of any of `[]*?!^-\',
- * and match the character exactly, precede it with a `\'.
- *
- ----------------------------------------------------------------------------*/
-
- BOOLEAN match ( /* char *pattern, char *text */ );
-
- /*----------------------------------------------------------------------------
- *
- * Return TRUE if PATTERN has any special wildcard characters
- *
- ----------------------------------------------------------------------------*/
-
- BOOLEAN is_pattern ( /* char *pattern */ );
-
- /* -- end of match.h P. Ross -- */
-
- #define ABORT 2 /* end of search indicator */
-
- BOOLEAN regex_match_after_star ( /* char *pattern, char *text */ );
-
- /*----------------------------------------------------------------------------
- *
- * Return TRUE if PATTERN has any special wildcard characters
- *
- ----------------------------------------------------------------------------*/
-
- BOOLEAN is_pattern (p)
- char *p;
- {
- while ( *p ) {
- switch ( *p++ ) {
- case '?':
- case '*':
- case '[':
- return TRUE;
- case '\\':
- if ( !*p++ ) return FALSE;
- }
- }
- return FALSE;
- }
-
-
- /*----------------------------------------------------------------------------
- *
- * Match the pattern PATTERN against the string TEXT;
- * return TRUE if it matches, FALSE otherwise.
- *
- * A match means the entire string TEXT is used up in matching.
- *
- * In the pattern string:
- * `*' matches any sequence of characters
- * `?' matches any character
- * [SET] matches any character in the specified set,
- * [!SET] or [^SET] matches any character not in the specified set.
- *
- * Note: the standard regex character '+' (one or more) should by
- * simulated by using "?*" which is equivelant here.
- *
- * A set is composed of characters or ranges; a range looks like
- * character hyphen character (as in 0-9 or A-Z).
- * [0-9a-zA-Z_] is the set of characters allowed in C identifiers.
- * Any other character in the pattern must be matched exactly.
- *
- * To suppress the special syntactic significance of any of `[]*?!^-\',
- * and match the character exactly, precede it with a `\'.
- *
- ----------------------------------------------------------------------------*/
-
- BOOLEAN regex_match (p, t)
- register char *p;
- register char *t;
- {
- register char range_start, range_end; /* start and end in range */
-
- BOOLEAN invert; /* is this [..] or [!..] */
- BOOLEAN member_match; /* have I matched the [..] construct? */
- BOOLEAN loop; /* should I terminate? */
-
- for ( ; *p; p++, t++ ) {
-
- /* if this is the end of the text then this is the end of the match */
- if (!*t) {
- return ( *p == '*' && *++p == '\0' ) ? TRUE : ABORT;
- }
-
- /* determine and react to pattern type */
- switch ( *p ) {
-
- /* single any character match */
- case '?':
- break;
-
- /* multiple any character match */
- case '*':
- return regex_match_after_star (p, t);
-
- /* [..] construct, single member/exclusion character match */
- case '[': {
-
- /* move to beginning of range */
- p++;
-
- /* check if this is a member match or exclusion match */
- invert = FALSE;
- if ( *p == '!' || *p == '^') {
- invert = TRUE;
- p++;
- }
-
- /* if closing bracket here or at range start then we have a
- malformed pattern */
- if ( *p == ']' ) {
- return ABORT;
- }
-
- member_match = FALSE;
- loop = TRUE;
-
- while ( loop ) {
-
- /* if end of construct then loop is done */
- if (*p == ']') {
- loop = FALSE;
- continue;
- }
-
- /* matching a '!', '^', '-', '\' or a ']' */
- if ( *p == '\\' ) {
- range_start = range_end = *++p;
- }
- else {
- range_start = range_end = *p;
- }
-
- /* if end of pattern then bad pattern (Missing ']') */
- if (!range_start)
- return ABORT;
-
- /* move to next pattern char */
- p++;
-
- /* check for range bar */
- if (*p == '-') {
-
- /* get the range end */
- range_end = *++p;
-
- /* special character range end */
- if (range_end == '\\')
- range_end = *++p;
-
- /* if end of pattern or construct then bad pattern */
- if (range_end == '\0' || range_end == ']')
- return ABORT;
- }
-
- /* if the text character is in range then match found.
- make sure the range letters have the proper
- relationship to one another before comparison */
- if ( range_start < range_end ) {
- if (*t >= range_start && *t <= range_end) {
- member_match = TRUE;
- loop = FALSE;
- }
- }
- else {
- if (*t >= range_end && *t <= range_start) {
- member_match = TRUE;
- loop = FALSE;
- }
- }
- }
-
- /* if there was a match in an exclusion set then no match */
- /* if there was no match in a member set then no match */
- if ((invert && member_match) ||
- !(invert || member_match))
- return FALSE;
-
- /* if this is not an exclusion then skip the rest of the [...]
- construct that already matched. */
- if (member_match) {
- while (*p != ']') {
-
- /* bad pattern (Missing ']') */
- if (!*p)
- return ABORT;
-
- /* skip exact match */
- if (*p == '\\') {
- p++;
- }
-
- /* move to next pattern char */
- p++;
- }
- }
-
- break;
- }
-
- /* next character is quoted and must match exactly */
- case '\\':
-
- /* move pattern pointer to quoted char and fall through */
- p++;
-
- /* must match this character exactly */
- default:
- if (*p != *t)
- return FALSE;
- }
- }
-
- /* if end of text not reached then the pattern fails */
- return !*t;
- }
-
-
- /*----------------------------------------------------------------------------
- *
- * recursively call regex_match with final segment of PATTERN and of TEXT.
- *
- ----------------------------------------------------------------------------*/
-
- BOOLEAN regex_match_after_star (p, t)
- register char *p;
- register char *t;
- {
- register BOOLEAN match;
- register nextp;
-
- /* pass over existing ? and * in pattern */
- while ( *p == '?' || *p == '*' ) {
-
- /* take one char for each ? */
- if ( *p == '?' ) {
-
- /* if end of text then no match */
- if ( !*t++ ) {
- return ABORT;
- }
- }
-
- /* move to next char in pattern */
- p++;
- }
-
- /* if end of pattern we have matched regardless of text left */
- if ( !*p ) {
- return TRUE;
- }
-
- /* get the next character to match which must be a literal or '[' */
- nextp = *p;
- if ( nextp == '\\' )
- nextp = p[1];
-
- /* Continue until we run out of text or definite result seen */
- match = FALSE;
- while ( match == FALSE ) {
-
- /* a precondition for matching is that the next character
- in the pattern match the next character in the text or that
- the next pattern is the beginning of a range. Increment text
- pointer as we go here */
- if ( *p == *t || nextp == '[' ) {
- match = regex_match(p, t);
- }
-
- /* if the end of text is reached then no match */
- if ( !*t++ ) match = ABORT;
- }
-
- /* return result */
- return match;
- }
-
- /*----------------------------------------------------------------------------
- *
- * This is a shell to regex_match to return only a true BOOLEAN value
- *
- ----------------------------------------------------------------------------*/
-
- BOOLEAN match(p, t)
- char *p;
- char *t;
- {
- return ( regex_match(p,t) == TRUE ) ? TRUE : FALSE;
- }
-