[comp.sources.amiga] v91i108: sregexp.library 9.4 - a library for regular expressions, Part02/02

amiga-request@ab20.larc.nasa.gov (Amiga Sources/Binaries Moderator) (05/18/91)

Submitted-by: "J. Spencer" <bhgs@utcs.utoronto.ca>
Posting-number: Volume 91, Issue 108
Archive-name: libraries/sregexp-9.4/part02

#!/bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 2 (of 2)."
# Contents:  sregexp.c sregexp.doc
# Wrapped by tadguy@ab20 on Fri May 17 21:56:59 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'sregexp.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'sregexp.c'\"
else
echo shar: Extracting \"'sregexp.c'\" \(16596 characters\)
sed "s/^X//" >'sregexp.c' <<'END_OF_FILE'
X
X/* This is a routine to test if a string matches a regular expression.
X *
X *
X *  The regular expression sytax is a slight extension of the regular
X * AmigaDos wildcard patterns. Apparently 2.0 has added a few new things
X * (well, at least a not operator) to the game.  This may or may not
X * be consistant with those additions (it's the way they otta done it.)
X *
X * Here it is:
X *
X *	?	    matches any one character
X *
X *	#(pat)      matches zero or more occurances of the pattern pat.
X *
X *	(pat)       seperates out a piece of the pattern.
X *
X *	pat1|pat2   matches to either pat1 or pat2
X *
X *	'           escapes the special meaning of these symbols.
X *
X *	%	    matches the null string.
X *
X *  EXTENSIONS
X *
X *	[chars]     will match any single character in the set chars,
X *		    specified as single characters or ranges seperated
X *		    by a -.  Ex. [af-i+] would match a, f, g, h, i, and
X *		    +.	If ~ is the first character in the set then the
X *		    set matched is the complement of the set specified.
X *		    Ex. [~a-z] would match any one character that is
X *		    not a (lower case if case sensitivity is on) letter.
X *		    Note that a [~a] is NOT the same as a ~[a]. The former
X *		    would match a 'b' but not a 'ab', whereas the latter
X *		    would match both.
X *
X *	~(pat)      will match anything that doesn't match the pattern.
X *		    Note: it is illegal to repeat a not. ie #~a is illegal.
X *		    (So is #(~(a)) so don't even try it.) You can repeat
X *		    something with a not IN it, as long as it can't be
X *		    reduced to the form #~(pattern). (A #[~a] is OK.)
X *		    However ~#a has the expected effect (matches any
X *		    non-null string not composed entirely of a's.)
X *
X *	*	    same as #?.
X *
X *
X */
X
X#include "sregexp.h"
X
Xconst char wilds[] = {	      /* string of the wildcards, for easy access */
X			CHR_REPEAT,
X			CHR_NOT,
X			CHR_OPENBRACE,
X			CHR_CLOSEBRACE,
X			CHR_OPENSET,
X			CHR_CLOSESET,
X			CHR_ANYCHAR,
X			CHR_NULL,
X			CHR_OR,
X			CHR_ESCAPE,
X/*			CHR_RANGE,	 <--- special case  */
X			CHR_STAR,
X			0
X};
X
X#ifdef __DEBUG__
Xextern void puts(char *);
Xextern void printf(char *, ...);
X#endif
X
X
Xstruct SregExp *
Xparsesregexp(expr)
Xchar *expr;
X/* This is the entry point into the parsing subroutines. */
X{
X    return parsesub(&expr,0);
X}
X
Xstatic struct SregExp *
Xparsesub(p,end)
Xchar **p,end;
X/* This routine will parse a sub expression up until the character
X   'end' is encontered.  This is 0 for the whole pattern and ')'
X   for a subpattern */
X{
X    struct SregList *list,*head=NULL,*orlist,*orhead=NULL;
X    struct SregExp *sreg;
X    int num = 0,ornum = 0;
X
X    if (**p == end) {
X	char *q;
X
X	q = "%";
X	return parseone(&q,TRUE);
X    }
X
X    while (**p != end) {
X	if (!(sreg = parseone(p,TRUE)))  /* parse on wildcard */
X	    goto cleanup;
X	if (head) {     /* if there's already a list, just stick it on */
X	    if (!(list = (list->srl_next = getmem(sizeof(struct SregList))))) {
X		report(MEM_ERROR);
X		goto cleanup;
X	    }
X	} else {	/* otherwise, make a new list */
X	    if (!(list = (head = getmem(sizeof(struct SregList))))) {
X		report(MEM_ERROR);
X		goto cleanup;
X	    }
X	}
X	list->srl_sreg = sreg;
X	list->srl_next = NULL;
X	num++;
X	if (**p == CHR_OR) {        /* deal with an or */
X	    if (!(sreg = makesum(head,num)))
X		goto cleanup;
X	    if (orhead) {           /* either add onto the or list */
X		if (!(orlist = (orlist->srl_next = getmem(sizeof(struct SregList))))) {
X		    report(MEM_ERROR);
X		    goto cleanup;
X		}
X	    } else {		    /* or make a new or list */
X		if (!(orlist = (orhead = getmem(sizeof(struct SregList))))) {
X		    report(MEM_ERROR);
X		    goto cleanup;
X		}
X	    }
X	    orlist->srl_sreg = sreg;
X	    orlist->srl_next = NULL;
X	    ornum++;
X	    (*p)++;
X	    head = NULL;
X	    num = 0;
X	}
X    }
X    if (!(sreg = makesum(head,num)))
X	goto cleanup;
X    if (orhead) {       /* if this expression had an or, clean it up */
X	if (!(orlist = (orlist->srl_next = getmem(sizeof(struct SregList))))) {
X	    report(MEM_ERROR);
X	    goto cleanup;
X	}
X	orlist->srl_sreg = sreg;
X	orlist->srl_next = NULL;
X	ornum++;
X	if (!(sreg = makeor(orhead,ornum)))
X	    goto cleanup;
X    }
X
X    return sreg;	/* sub expression successfully matched. */
X
Xcleanup:	/* troubles all head here to clean up */
X
X    list = head;
X    while (list) {          /* free all the bits of the current sum */
X	head = list->srl_next;
X	freesregexp(list->srl_sreg);
X	FreeMem(list,sizeof(struct SregList));
X	list = head;
X    }
X    list = orhead;
X    while (list) {          /* and all of the current or parts */
X	head = list->srl_next;
X	freesregexp(list->srl_sreg);
X	FreeMem(list,sizeof(struct SregList));
X	list = head;
X    }
X
X    return NULL;	    /* return the failure */
X}
X
Xstatic struct SregExp *
Xmakesum(list,num)
Xstruct SregList *list;
Xint num;
X/* This routine takes a linked list of sreg's and joins them together
X   Under the auspices of one big SRP_SUM type sreg */
X{
X    struct SregList *lnk;
X    struct SregExp *sreg;
X    int i,len=0;
X    char fixed = SRF_FIXLEN;
X
X    if (num == 0) {
X	report(ILLEGAL_ERR);
X	return NULL;
X    } else if (num == 1) {
X	sreg = list->srl_sreg;
X	FreeMem(list,sizeof(struct SregList));
X	return sreg;
X    } if (!(sreg = getmem(sizeof(struct SregExp) + num*sizeof(struct SregExp *)))) {
X	report(MEM_ERROR);
X	return NULL;
X    }
X    sreg->sre_Type = SRP_SUM;
X    sreg->sre_Flag = 0;
X    sreg->sre_Data.number = num;
X    for (i = 0; i < num; i++) {
X	len += realen(list->srl_sreg);
X	fixed &= isfixed(list->srl_sreg) ? SRF_FIXLEN : 0;
X	sreg->sre_List[i] = list->srl_sreg;
X	lnk = list->srl_next;
X	FreeMem(list,sizeof(struct SregList));
X	list = lnk;
X    }
X    sreg->sre_MinLen = len;
X    sreg->sre_Flag |= fixed;
X    return sreg;
X}
X
Xstatic struct SregExp *
Xmakeor(list,num)
Xstruct SregList *list;
Xint num;
X/* This does basically the same thing as makesum, except it makes
X   an SRP_OR type sreg to join the list and doesn't deal with some
X   special cases */
X{
X    struct SregList *lnk;
X    struct SregExp *sreg;
X    int i,len;
X    char fixed = SRF_FIXLEN;
X
X    if (!(sreg = getmem(sizeof(struct SregExp) + num*sizeof(struct SregExp *)))) {
X	report(MEM_ERROR);
X	return NULL;
X    }
X    sreg->sre_Type = SRP_OR;
X    sreg->sre_Flag = 0;
X    sreg->sre_Data.number = num;
X    for (i = 0; i < num; i++) {
X	if (i == 0)
X	    len = realen(list->srl_sreg);
X	else if (len != realen(list->srl_sreg)) {
X	    fixed = 0;
X	    if (len > realen(list->srl_sreg))
X		len = realen(list->srl_sreg);
X	}
X	fixed &= isfixed(list->srl_sreg) ? SRF_FIXLEN : 0;
X	sreg->sre_List[i] = list->srl_sreg;
X	lnk = list->srl_next;
X	FreeMem(list,sizeof(struct SregList));
X	list = lnk;
X    }
X    sreg->sre_MinLen = len;
X    sreg->sre_Flag |= fixed;
X    return sreg;
X}
X
Xstatic struct SregExp *
Xparseone(p,cat)
Xchar **p,cat;
X/* This routine parses one wildcard character from the string *p,
X   leaving it set up pointing to the begining of the next
X   wildcard. If 'cat' is true then a string of characters will
X   be grouped together as a SRP_STRING type sreg.  It may be
X   false because of the scope rules of ~ and #, which only
X   repeat the very next pattern. */
X{
X    struct SregExp *sreg;
X
X    switch (**p) {
X	case (CHR_REPEAT) :
X	    (*p)++;
X	    if (!(sreg = parseone(p,FALSE)))
X		return NULL;
X	    if (sreg->sre_Flag & SRF_NOT) {
X		report(ILLEGAL_ERR);
X		freesregexp(sreg);
X		return NULL;
X	    }
X	    sreg->sre_Flag |= SRF_REPEAT;
X	    break;
X	case (CHR_NOT) :
X	    (*p)++;
X	    if (!(sreg = parseone(p,FALSE)))
X		return NULL;
X	    sreg->sre_Flag |= SRF_NOT;
X	    break;
X	case (CHR_OPENBRACE) :
X	    (*p)++;
X	    sreg = parsesub(p,CHR_CLOSEBRACE);
X	    (*p)++;
X	    break;
X	case (CHR_OPENSET) :
X	    (*p)++;
X	    if (!(sreg = getmem(sizeof(struct SregExp)))) {
X		report(MEM_ERROR);
X		return NULL;
X	    }
X	    sreg->sre_Type = SRP_SETCHAR;
X	    sreg->sre_Flag = SRF_FIXLEN;
X	    sreg->sre_MinLen = 1;
X	    if (!(sreg->sre_Data.setchar = makeset(p))) {
X		FreeMem(sreg,sizeof(sreg));
X		return NULL;
X	    }
X	    (*p)++;
X	    break;
X	case (CHR_ANYCHAR) :
X	    (*p)++;
X	    if (!(sreg = getmem(sizeof(struct SregExp)))) {
X		report(MEM_ERROR);
X		return NULL;
X	    }
X	    sreg->sre_Type = SRP_ANYCHAR;
X	    sreg->sre_Flag = SRF_FIXLEN;
X	    sreg->sre_MinLen = 1;
X	    break;
X	case (CHR_STAR) :
X	    (*p)++;
X	    if (!(sreg = getmem(sizeof(struct SregExp)))) {
X		report(MEM_ERROR);
X		return NULL;
X	    }
X	    sreg->sre_Type = SRP_ANYCHAR;
X	    sreg->sre_Flag = SRF_FIXLEN | SRF_REPEAT;
X	    sreg->sre_MinLen = 1;
X	    break;
X	case (CHR_NULL) :
X	    (*p)++;
X	    if (!(sreg = getmem(sizeof(struct SregExp)))) {
X		report(MEM_ERROR);
X		return NULL;
X	    }
X	    sreg->sre_Type = SRP_NULL;
X	    sreg->sre_Flag = SRF_FIXLEN;
X	    sreg->sre_MinLen = 0;
X	    break;
X	case (CHR_CLOSEBRACE) :
X	case (CHR_CLOSESET) :
X	case (CHR_OR) :
X	case (0) :
X	    report(ILLEGAL_ERR);
X	    return NULL;
X	default :
X	    if (!(sreg = getmem(sizeof(struct SregExp)))) {
X		report(MEM_ERROR);
X		return NULL;
X	    }
X	    sreg->sre_Flag = SRF_FIXLEN;
X	    if (!cat) {
X		sreg->sre_Data.onechar = onechar(p,FALSE);
X		sreg->sre_Type = SRP_ONECHAR;
X		sreg->sre_MinLen = 1;
X	    } else {
X		char *q=*p;
X		int len=0;
X
X		while (onechar(&q,FALSE))
X		    len++;
X		sreg->sre_MinLen = len;
X		if (len == 1) {
X		    sreg->sre_Data.onechar = onechar(p,FALSE);
X		    sreg->sre_Type = SRP_ONECHAR;
X		} else {
X		    sreg->sre_Type = SRP_STRING;
X		    if (!(q = sreg->sre_Data.string = getmem(len+1))) {
X			report(MEM_ERROR);
X			FreeMem(sreg,sizeof(sreg));
X			return NULL;
X		    }
X		    while (*q++ = onechar(p,FALSE)) ;
X		    *q = 0;
X		}
X	    }
X    }
X    return sreg;
X}
X
Xstatic char
Xonechar(p,minus)
Xchar **p,minus;
X/* this routine picks one character off the string *p.	It handles
X   escaping the special meaning of the wildcard characters, and
X   returns 0 if we're at the end of the string or the next
X   char is a wildcard.	if 'minus' is true, then the '-' is
X   treated as a wildcard, otherwise it isn't */
X{
X    if (**p == CHR_ESCAPE)
X	(*p)++;
X    else if (strchr(wilds,**p) || (minus && **p == CHR_RANGE))
X	return 0;
X    return *(*p)++;
X}
X
Xstatic char *
Xmakeset(p)
Xchar **p;
X/* this makes a table of match flags from the character specifier
X   that goes in between [ and ].  It handles a leading '~' and
X   leaves *p pointing to the closing brace. Note: This routine
X   checks to make sure the specifier ends in a ] and fails if
X   it doesn't */
X{
X    char *set,not=FALSE,ok=FALSE,s,e;
X
X    if (**p == CHR_NOT) {
X	(*p)++;
X	not = TRUE;
X    }
X    if (!(set = getmem(32))) {
X	report(MEM_ERROR);
X	return NULL;
X    }
X    for (s = 0; s < 32; s++)
X	set[s] = 0;
X    while (s = onechar(p,TRUE)) {
X	ok = TRUE;
X	if (**p == CHR_RANGE) {
X	    (*p)++;
X	    if (!(e = onechar(p,TRUE))) {
X		report(ILLEGAL_ERR);
X		FreeMem(set,32);
X		return NULL;
X	    }
X	    for ( ; s <= e; s++)
X		set[s/8] |= 1 << (s % 8);
X	} else
X	    set[s/8] |= 1 << (s % 8);
X    }
X    if (!ok || **p != CHR_CLOSESET) {
X	report(ILLEGAL_ERR);
X	FreeMem(set,32);
X	return NULL;
X    }
X    if (not) {
X	for(s = 0; s < 32; s++)
X	    set[s] = ~set[s];
X    }
X    return set;
X}
X
Xvoid
Xfreesregexp(sreg)
Xstruct SregExp *sreg;
X/* this routine frees up a sreg.  It correctly handles freeing the
X   subpattern elements in a SRP_SUM or SRP_OR sreg and frees the
X   match table or string from a SRP_SETCHAR or SRP_STRING sreg.
X   This is one of the externally visible routines. */
X{
X    int add = 0;
X
X    if (sreg->sre_Type == SRP_SUM || sreg->sre_Type == SRP_OR) {
X	int i;
X
X	add = sreg->sre_Data.number * sizeof(struct SregExp *);
X	for (i = 0; i < sreg->sre_Data.number; i++)
X	    freesregexp(sreg->sre_List[i]);
X
X    } else if (sreg->sre_Type == SRP_STRING)
X	FreeMem(sreg->sre_Data.string,strlen(sreg->sre_Data.string)+1);
X    else if (sreg->sre_Type == SRP_SETCHAR)
X	FreeMem(sreg->sre_Data.setchar,32);
X    FreeMem(sreg,sizeof(struct SregExp) + add);
X}
X
Xint
Xmatchsregexp(p,sreg,up)
Xchar *p;
Xstruct SregExp *sreg;
Xint up;
X/* This is the externally visible stub to the pattern matching part
X   of sreg.  'p' is the string to match to, sreg is the preparsed
X   sreg, and up indicates if the match is case sensitive. */
X{
X    return matchnsregexp(p,sreg,up,strlen(p));
X}
X
Xint
Xmatchnsregexp(p,sreg,up,len)
Xchar *p;
Xstruct SregExp *sreg;
Xint up,len;
X/* This routine will match a sreg to a string of length 'len'. */
X/* The length, rather than NULL terminated is used to make a
X   lot of things a lot simpler */
X{
X    int res,i;
X
X    if (sreg->sre_Flag & SRF_REPEAT) {  /* deal with repeaters. */
X	char not,*h;
X
X	if (len == 0 || sreg->sre_Type == SRP_ANYCHAR) { /* always true */
X	    res = TRUE;
X	    goto end;
X	}
X	/* check if the lengths match up */
X	if (len < sreg->sre_MinLen || (sreg->sre_Flag & SRF_FIXLEN &&
X			   (sreg->sre_MinLen == 0 || len % sreg->sre_MinLen != 0))) {
X	    res = FALSE;
X	    goto end;
X	}
X	not = sreg->sre_Flag & SRF_NOT;
X	sreg->sre_Flag &= ~(SRF_REPEAT | SRF_NOT);
X	if (sreg->sre_Flag & SRF_FIXLEN) { /* handle fixed lenght matches */
X	    h = p;
X	    while (h-p < len) {
X		if (!(res = matchnsregexp(h,sreg,up,sreg->sre_MinLen)))
X		    goto end;
X		h += sreg->sre_MinLen;
X	    }
X	} else {		    /* and variable length ones */
X	    for (i = len; i >= (sreg->sre_MinLen ? sreg->sre_MinLen : 1); i--) {
X		if (res = matchnsregexp(p,sreg,up,i)) {
X		    sreg->sre_Flag |= SRF_REPEAT;
X		    if (res = matchnsregexp(p+i,sreg,up,len-i))
X			break;
X		    sreg->sre_Flag &= ~SRF_REPEAT;
X		}
X	    }
X	}
X	sreg->sre_Flag |= SRF_REPEAT | not;
X	goto end;
X    }
X
X    /* check the lengths first for quick rejection */
X    if (len < sreg->sre_MinLen || (sreg->sre_Flag & SRF_FIXLEN && len != sreg->sre_MinLen)) {
X	res = FALSE;
X	goto end;
X    }
X
X    switch (sreg->sre_Type) {
X	case (SRP_SUM) :
X	    res = matchsum(&(sreg->sre_List[0]),sreg->sre_Data.number,p,len,up);
X	    break;
X	case (SRP_ONECHAR) :
X	    res = len == 1 && (up ? *p == sreg->sre_Data.onechar :
X			       toupper(*p) == toupper(sreg->sre_Data.onechar));
X	    break;
X	case (SRP_SETCHAR) :
X	    res = len == 1 && matchset(sreg,*p) || (up ? FALSE :
X				 (isupper(*p) ? matchset(sreg,tolower(*p)) :
X						matchset(sreg,toupper(*p))));
X	    break;
X	case (SRP_ANYCHAR) :
X	    res = len == 1;
X	    break;
X	case (SRP_STRING) :
X	    if (up)
X		res = !strncmp(p,sreg->sre_Data.string,len);
X	    else
X		res = !strnicmp(p,sreg->sre_Data.string,len);
X	    break;
X	case (SRP_NULL) :
X	    res = len == 0;
X	    break;
X	case (SRP_OR) :
X	    for (i = 0; i < sreg->sre_Data.number; i++)
X		if (res = matchnsregexp(p,sreg->sre_List[i],up,len)) {
X		    break;
X		}
X	    break;
X    }
X
Xend:
X
X    if (sreg->sre_Flag & SRF_NOT)
X	return !res;
X    else
X	return res;
X}
X
Xstatic int
Xmatchsum(list,num,p,len,up)
Xstruct SregExp *list[];
Xint num,len,up;
Xchar *p;
X/* This routine is called by match to match the elements of a sum
X   of sregs.  It tries to be as effecient as possible, and keep
X   recursion to a minimum.  It will match any fixed length peices
X   at the begining and end first, then match any fixed length
X   peices in the middle to break the string up.  Only then does
X   it do the tiresome matches to the non-fixed length peices. */
X{
X    int i,res,o;
X
X    while (num && isfixed(list[0])) {
X	if (!(res = matchnsregexp(p,list[0],up,list[0]->sre_MinLen)))
X	    return FALSE;
X	p += list[0]->sre_MinLen;
X	len -= list[0]->sre_MinLen;
X	list++;
X	num--;
X    }
X    while (num && isfixed(list[num-1])) {
X	if (!(res = matchnsregexp(p+len-list[num-1]->sre_MinLen,list[num-1],up,
X						       list[num-1]->sre_MinLen)))
X	    return FALSE;
X	len -= list[num-1]->sre_MinLen;
X	num--;
X    }
X    if (num == 0)
X	return TRUE;
X
X    o = 0;
X    for (i = 1; i < num-1; i++) {
X	if (isfixed(list[i])) {
X	    for ( ; len-o >= list[i]->sre_MinLen; o++) {
X		if (res = matchnsregexp(p+o,list[i],up,list[i]->sre_MinLen)) {
X		    if (!(res = matchsum(list,i,p,o,up)))
X			return FALSE;
X		    if (!(res = matchsum(list+(i+1),num-i-1,
X			    p+o+list[i]->sre_MinLen,len-o-list[i]->sre_MinLen,up)))
X			return FALSE;
X		    return TRUE;
X		}
X	    }
X	    return FALSE;
X	} else
X	    o += realen(list[i]);
X    }
X
X    if (num == 1)
X	return matchnsregexp(p,list[0],up,len);
X
X    for (o = len; o >= list[0]->sre_MinLen; o--)
X	if (matchnsregexp(p,list[0],up,o) && matchsum(list+1,num-1,p+o,len-o,up))
X	    return TRUE;
X
X    return FALSE;
X}
X
Xint
Xiswild(p)
Xchar *p;
X/* this is a very simple routine, but it is externally visible.  Returns
X   true if the string has wildcard characters (unescaped) false if
X   not */
X{
X    while (onechar(&p,FALSE)) ;
X    return *p != 0;
X}
X
Xvoid
Xreport(i)
Xint i;
X/* This routine now does set the IoErr value to more information.
X  For now it does nothing. */
X{
X    struct Process *myself;
X
X    if (myself = (struct Process *)FindTask(0))
X	myself->pr_Result2 = i;
X}
END_OF_FILE
if test 16596 -ne `wc -c <'sregexp.c'`; then
    echo shar: \"'sregexp.c'\" unpacked with wrong size!
fi
# end of 'sregexp.c'
fi
if test -f 'sregexp.doc' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'sregexp.doc'\"
else
echo shar: Extracting \"'sregexp.doc'\" \(13775 characters\)
sed "s/^X//" >'sregexp.doc' <<'END_OF_FILE'
XTABLE OF CONTENTS
X
Xsregexp.library/AnchorPath
Xsregexp.library/BuildPath
Xsregexp.library/FreeSpathInfo
Xsregexp.library/FreeSregExp
Xsregexp.library/IsWild
Xsregexp.library/ParseSregExp
Xsregexp.library/MatchNSregExp
Xsregexp.library/MatchSregExp
Xsregexp.library/NextFile
X
Xsregexp.library/AnchorPath			  sregexp.library/AnchorPath
X
X    NAME
X	AnchorPath -- get set up to match a wildcard path.
X
X    SYNOPSIS
X	spath = AnchorPath(anc, wld)
X	D0		   A0	A1
X	struct SpathInfo *AnchorPath(char *, char *);
X
X    FUNCTION
X	This is the first step in matching a wildcarded path. This routine
X	will preparse all of the wildcard elements in the path and set
X	everything up for subsequent calls to NextFile.
X
X	If NULL is returned, then IoErr can be examined to find out more on
X	whatever went wrong.
X
X	The wildcarded path is made up of (almost, see bug note) any legal
X	AmigaDOS path name, with wildcard expressions in the place of file
X	and directory names.  There is one additional syntax: '.../' means
X	recursively search all sub-directories. so:
X	    DH0:.../fred
X	would search all of DH0 for a (file or directory or either, see
X	NextFile) named fred.
X
X	One pretty nifty feature is that wildcards are legal in the volume
X	node part of the path.	This will match to any file system device or
X	assigned directory or volume node that the system currently has
X	mounted. So to match all of the hard drive partitions in your system
X	you would use 'DH?:.../fred'.  The root of your current device will
X	be matched only if the pattern explicitly matches a null string (ie
X	either just ':' or '%:')
X
X    INPUTS
X	anc	  - a null terminated string which is the name of a
X		    directory.	All paths returned by BuildPath and NextFile
X		    will be relative to this directory.
X
X	wld	  - the wildcarded path to be matched.
X
X    RESULTS
X	spath	  - a pointer to a SpathInfo structure ready for calls to
X		    NextFile.
X
X    NOTES
X	It will be most usual to pass a pointer to a null string for anc,
X	this will make all paths relative to the current working directory.
X
X	If the wildcarded path ends in a '/' then the search will match only
X	directories, and the '/' will be appended to all paths returned by
X	BuildPath and NextFile. If you specify a path ending in '/' and then
X	ask NextFile to look for only files the search will fail.  If the
X	path does not end in a '/' then no '/' will be appended to the path
X	returned, regardless of whether the match is to a file or a
X	directory.
X
X    BUGS
X	(well, possible bugs actually)  If one of the elements of the path
X	explicitly matches a null string (ie. either /%/ or just //) then
X	the routine will match to the parent directory. This works in all of
X	the cases I have tried (and the only important use, which is at the
X	beginning of the path.) I am just not terribly confident with the
X	way it's done, so if funny bugs creep up, look here first.
X
X    SEE ALSO
X	ParseSregExp, NextFile, BuildPath, FreeSpathInfo
X
Xsregexp.library/BuildPath			   sregexp.library/BuildPath
X
X    NAME
X	BuildPath -- build the path to the current match to a SpathInfo
X		     structure
X
X    SYNOPSIS
X	len = BuildPath(spi,buff,len)
X	D0		A0  A1	 D0
X	int BuildPath(Struct SpathInfo *, char *, int);
X
X    FUNCTION
X	The path to the current match of the SpathInfo structure is copied
X	into the buffer and null terminated.  This will have unpredictable
X	results, possibly including fireworks, if it is called before the
X	first call to NextFile.
X
X	This routine will mainly be used to try again with a bigger buffer
X	if NextPath failed with SPE_BUFF_FULL.
X
X    INPUTS
X	spi	  - The pointer returned by a call to AnchorPath
X
X	buff	  - a buffer length len long to copy the path name into.
X
X	len	  - the length of the buffer, buff.
X
X
X    RESULTS
X	len	  - exactly the same as returned by NextFile.
X
X    SEE ALSO
X	NextFile, AnchorPath.
X
Xsregexp.library/FreeSpathInfo		       sregexp.library/FreeSpathInfo
X
X    NAME
X	FreeSpathInfo -- free up all of the resources locked by calls
X			 to AnchorPath and NextFile
X
X    SYNOPSIS
X	FreeSpathInfo(spi)
X		      A0
X	void FreeSpathInfo(struct SpathInfo *);
X
X    FUNCTION
X	This will free all of the memory and file locks currently wrapped up
X	in the SpathInfo structure.  This is the ONLY way you should try to
X	free up these resources.
X
X	This routine can be called at any point, either immediately after
X	the call to AnchorPath, or after any calls to NextFile or BuildPath.
X
X    INPUTS
X	spi	  - A pointer to a SpathInfo structure to be freed.
X
X    SEE ALSO
X	AnchorPath.
X
Xsregexp.library/FreeSregExp			 sregexp.library/FreeSregExp
X
X    NAME
X	FreeSregExp -- free up a preparsed wildcard created by ParseSregExp
X
X    SYNOPSIS
X	FreeSregExp(sreg)
X		    A0
X	void FreeSregExp(struct SregExp *);
X
X    FUNCTION
X	This routine will free all of the resources associated with a
X	preparsed wildcard expression.	This is the only legal way to free
X	the object created by ParseSregExp, and you should not try to do it
X	yourself.
X
X    INPUTS
X	sreg	  - a pointer to the preparsed wildcard expression returned
X		    by ParseSregExp.
X
X    SEE ALSO
X	ParseSregExp, MatchNSregExp, MatchSregExp.
X
Xsregexp.library/IsWild				      sregexp.library/IsWild
X
X    NAME
X	IsWild -- test if a string has any unescaped wildcard characters.
X
X    SYNOPSIS
X	bool = IsWild(wildcard);
X	D0	      A0
X	int IsWild(char *);
X
X    FUNCTION
X	This routine merely checks if the string contains any unescaped
X	wildcard characters.  It does not actually test if the string is
X	wild.  For example, it would fail on '(this is a test)' because of
X	the round brackets, which are wildcard characters.
X
X    INPUTS
X	wildcard  - a pointer to a wildcard string.
X
X    RESULTS
X	bool	  - non-zero if any unescaped wildcard characters were
X		    found.
X
X    NOTES
X	This routine has very little merit, and is not really all that
X	useful.  I will probably add a routine in future versions that does
X	the same thing but takes the preparsed wildcard expression and
X	returns the unique string which it will match, or NULL.
X
X    SEE ALSO
X	ParseSregExp.
X
Xsregexp.library/ParseSregExp			sregexp.library/ParseSregExp
X
X    NAME
X	ParseSregExp -- preparse a wildcard expression for matching.
X
X    SYNOPSIS
X	sreg = ParseSregExp(wildcard)
X	D0		 A0
X	struct SregExp *ParseSregExp(char *);
X
X    FUNCTION
X	A wildcard string must be preparsed before it can be passed to
X	MatchSregExp or MatchNSregExp to actually test if it matches a given
X	target string.
X
X	This function returns a pointer to the successfully created
X	structure, or NULL on failure.	On failure, IoErr() can be examined
X	to get more information on the cause of the trouble.
X	ERROR_INVALID_COMPONENT_NAME is returned if the wildcard string is
X	illegal and ERROR_NO_FREE_STORE is returned if memory allocation
X	failed.
X
X    WILDCARD SYNTAX
X	The wildcard syntax accepted is an extension of the usual AmigaDOS
X	wildcards.  Any 1.3 wildcard expression should be ok.  Apparently
X	under 2.0 they have added a not operator, and the one here may or
X	may not be compatible with the way they have done it.  (They SHOULD
X	have done it this way.)
X
X	Here is a synopsis:
X
X	?	    matches any one character
X
X	#(pat)      matches zero or more occurrences of the pattern pat.
X
X	(pat)       separates out a piece of the pattern.
X
X	pat1|pat2   matches to either pat1 or pat2
X
X	'           escapes the special meaning of these symbols.
X
X	%	    matches the null string.
X
X	These are the extensions:
X
X	[chars]     will match any single character in the set chars,
X		    specified as single characters or ranges separated by a
X		    -.	Ex. [af-i+] would match a, f, g, h, i, and +.  If ~
X		    is the first character in the set then the set matched
X		    is the complement of the set specified. Ex. [~a-z] would
X		    match any one character that is not a (lower case if
X		    case sensitivity is on) letter. Note that a [~a] is NOT
X		    the same as a ~[a]. The former would match a 'b' but not
X		    a 'ab', whereas the latter would match both. Special
X		    care should be taken when using this wildcard in case
X		    insensitive matches. As expected, [a] would match either
X		    'a' or 'A' in a case insensitive search, but [~a] would
X		    match anything, since it doesn't match 'a', but would
X		    match a 'A'.
X
X	~(pat)      will match anything that doesn't match the pattern.
X		    Note: it is illegal to repeat a not. ie #~a is illegal.
X		    (So is #(~(a)) so don't even try it.) You can repeat
X		    something with a not IN it, as long as it can't be
X		    reduced to the form #~(pattern). (A #[~a] is OK.)
X		    However ~#a has the expected effect (matches any
X		    non-null string not composed entirely of a's.)
X
X	*	    same as #?.
X
X    INPUTS
X	wildcard  - a pointer to the null terminated wildcard expression
X		    string.
X
X    RETURNS
X	sreg	  - a preparsed version of the wildcard expression.
X
X    SEE ALSO
X	FreeSregExp, MatchNSregExp, MatchSregExp.
X
Xsregexp.library/MatchNSregExp		       sregexp.library/MatchNSregExp
X
X    NAME
X	MatchNSregExp - match a preparsed wildcard expression to a target
X
X    SYNOPSIS
X	bool = MatchNSregExp(target,sreg,case,len)
X	D0		      A0     A1    D0	D1
X	int MatchNSregExp(char *, struct SregExp *, int int);
X
X    FUNCTION
X	This function tests if the given fixed length target string matches
X	the preparsed wildcard expression.
X
X	This routine is identical to MatchSregExp, except it takes a pointer
X	to a string and its length, rather than a null terminated string.
X
X    INPUTS
X	target	  - the null terminated target string you wish to test
X		    against the wildcard expression.
X
X	sreg	  - the preparsed wildcard expression.
X
X	case	  - if this is non-zero then the match is case sensitive,
X		    otherwise it is case insensitive.
X
X	len	  - the length of the string pointed to by target.
X
X    RESULTS
X	bool	  - non-zero if the target matches the expression, zero
X		    otherwise.
X
X    NOTES
X	See ParseSregExp for a discussion of the wildcard expression and the
X	tricky behaviour of character sets (ie. [...]) when the search is
X	case insensitive.
X
X	This routine is handy for matching BCPL strings.  If p is a c
X	pointer (byte, not longword address) of a BCPL string then
X
X	    MatchNSregExp(p+1,sreg,case,*p)
X
X	will test the BCPL string for a match.
X
X    SEE ALSO
X	FreeSregExp, ParseSregExp, MatchSregExp.
X
Xsregexp.library/MatchSregExp			sregexp.library/MatchSregExp
X
X    NAME
X	MatchSregExp - match a preparsed wildcard expression to a target
X
X    SYNOPSIS
X	bool = MatchSregExp(target,sreg,case)
X	D0		      A0     A1   D0
X	int MatchSregExp(char *, struct SregExp *, int);
X
X    FUNCTION
X	This function tests if the given null terminated target string
X	matches the preparsed wildcard expression.
X
X	This routine is identical to MatchNSregExp, except it takes a
X	pointer to a null terminated string,  rather than a string and its
X	length.
X
X    INPUTS
X	target	  - the null terminated target string you wish to test
X		    against the wildcard expression.
X
X	sreg	  - the preparsed wildcard expression.
X
X	case	  - if this is non-zero then the match is case sensitive,
X		    otherwise it is case insensitive.
X
X    RESULTS
X	bool	  - non-zero if the target matches the expression, zero
X		    otherwise.
X
X    NOTES
X	See ParseSregExp for a discussion of the wildcard expression and the
X	tricky behaviour of character sets (ie. [...]) when the search is
X	case insensitive.
X
X	This call currently just results in the call:
X
X	    MatchNSregExp(target,sreg,case,strlen(target));
X
X	but this may change in future version.
X
X    SEE ALSO
X	FreeSregExp, ParseSregExp, MatchNSregExp.
X
Xsregexp.library/NextFile			    sregexp.library/NextFile
X
X    NAME
X	NextFile -- return the next (or first) file matching the path.
X
X    SYNOPSIS
X	len = NextFile(spi,buff,len,dirs)
X	D0	       A0  A1	D0  D1
X	int NextFile(struct SpathInfo *, char *, int int);
X
X    FUNCTION
X	This routine copies the path to the next (or first, if this is the
X	first call) file or directory matching the wildcard in the SpathInfo
X	structure created by a call to AnchorPath.
X
X	The usual calling sequence would be:
X	    AnchorPath
X	    repeat while no errors and more files
X		NextFile
X	    FreeSpathInfo
X
X	The length of the path is returned, or if there is an error or there
X	are no more matches a negative result is returned.  Both the
X	negative number and the Value if IoErr will give more information
X	about why the routine returned.
X
X    INPUTS
X	spi	  - The pointer returned by a call to AnchorPath
X
X	buff	  - a buffer length len long to copy the path name into.
X
X	len	  - the length of the buffer, buff.
X
X	dirs	  - if this is greater than zero, only directories will
X		    match; if it is zero, both files and directories will
X		    match; if it is less than zero, only files will match.
X		    See the defines in the include file.
X
X    RESULTS
X	len	  - on success this will be the length of the path copied
X		    into the buffer. If it is less than zero, some kind of
X		    special event is signalled.
X		    SPE_ALL_DONE  - This signals there are no more matches
X				    to the path. IoErr will also be set to
X				    ERROR_NO_MORE_ENTRIES
X		    SPE_ERROR	  - Some error happened, see IoErr.
X		    SPE_BUFF_FULL - The buffer you suplied was not big
X				    enough for the path name.  Get a bigger
X				    one and call BuildPath.
X		    SPE_SIGBREAK  - One of the dos break signals was
X				    received by your process. This does not
X				    clear the signals, but since some
X				    searches can take a while it checks
X				    every now and again.  You can just clear
X				    the signal and call NextPath again to
X				    ignore the signal.
X
X    NOTES
X	It is meaningless to mix calls with a different value of dirs.
X	Anything passed by in a call in which you did not ask for objects of
X	a given type will not reappear in subsequent calls in which you do
X	ask for that type.
X
X    SEE ALSO
X	AnchorPath, BuildPath.
X
END_OF_FILE
if test 13775 -ne `wc -c <'sregexp.doc'`; then
    echo shar: \"'sregexp.doc'\" unpacked with wrong size!
fi
# end of 'sregexp.doc'
fi
echo shar: End of archive 2 \(of 2\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked both archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Mail submissions (sources or binaries) to <amiga@uunet.uu.net>.
Mail comments to the moderator at <amiga-request@uunet.uu.net>.
Post requests for sources, and general discussion to comp.sys.amiga.misc.