home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Club Amiga de Montreal - CAM
/
CAM_CD_1.iso
/
files
/
514a.lha
/
sregexp.library_v9.0
/
spath.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-06-08
|
13KB
|
554 lines
/**********************************************************************
* This is the stuff for matching to a wildcarded path. see the docs *
* *
* *
* Copyright (c) 1991 by Jon Spencer. *
* *
* Revision history: *
* May 10, 1991 First version basically completed *
* *
**********************************************************************/
#include "sregexp.h"
extern struct DosLibrary *DOSBase;
#ifdef __DEBUG__
void puts(char *);
void printf(char *, ...);
#endif
#define ROOT ((struct RootNode *)DOSBase->dl_Root)
#define INFO ((struct DosInfo *)ROOT->rn_Info<<2)
#define DEVC(a) ((struct DeviceList *)a<<2)
struct SpathInfo *
anchorpath(anc,wld)
char *anc,*wld;
/* This is routine sets everything up for matching wildcard paths.
It does the expansion of any wildcards in the volume node part
of the path, if any where specified, and gets ready to roll. */
{
struct SpathInfo *spi;
struct SpathNode *spn;
BPTR lock;
register char *q;
char *node,*p,c;
struct DeviceList *dvc;
struct SregExp *pat;
if (!(spi = getmem(sizeof(struct SpathInfo)))) {
report(MEM_ERROR);
return NULL;
}
NewList((struct List *)spi);
for (q = wld; *q != ':' && *q != '/' && *q; q++) ;
if (*q == ':') {
if (!(node = getmem(q - wld + 1))) {
report(MEM_ERROR);
FreeMem(spi,sizeof(struct SpathInfo));
FreeMem(spi,sizeof(struct SpathInfo));
return NULL;
}
for (q = wld, p = node; *q != ':'; )
*p++ = *q++;
*p = 0;
pat = parsesregexp(node);
FreeMem(node,strlen(node)+1);
if (!pat) {
FreeMem(spi,sizeof(struct SpathInfo));
return NULL;
}
/* Check if there is no path to parse */
if (*(q+1)) {
if (!(spi->spi_SregList = parsepath(q+1))) {
freesregexp(pat);
FreeMem(spi,sizeof(struct SpathInfo));
return NULL;
}
} else
spi->spi_SregList = NULL;
if (pat->sre_Type == SRP_NULL) { /* check for paths matching ":..." */
if (!(lock = Lock(anc,SHARED_LOCK))) {
freesregexp(pat);
freespathinfo(spi);
return NULL;
}
if (!(node = getmem(2))) {
report(MEM_ERROR);
UnLock(lock);
freesregexp(pat);
freespathinfo(spi);
return NULL;
}
node[0] = ':';
node[1] = 0;
if (!(spn = makespathnode(lock,node,spi->spi_SregList))) {
UnLock(lock);
FreeMem(node,2);
freesregexp(pat);
freespathinfo(spi);
return NULL;
}
spn->spn_NodeName = node;
AddTail((struct List *)spi,(struct Node *)spn);
UnLock(lock);
} else {
for (dvc = DEVC(INFO->di_DevInfo); dvc; dvc = DEVC(dvc->dl_Next)) {
p = (char *)dvc->dl_Name<<2;
if (matchnsregexp(p+1,pat,FALSE,*p)) {
if (!(node = getmem(*p+2))) {
report(MEM_ERROR);
freesregexp(pat);
freespathinfo(spi);
return NULL;
}
for (c = *p++, q = node; c > 0; c--)
*q++ = *p++;
*q++ = ':';
*q = 0;
if (dvc->dl_Type == DLT_DEVICE) {
lock = Lock(node,SHARED_LOCK); /* ignore non-filesystem devices */
if (!lock)
continue;
UnLock(lock);
}
if (!(spn = makespathnode(NULL,node,spi->spi_SregList))) {
FreeMem(node,strlen(node)+1);
freespathinfo(spi);
return NULL;
}
spn->spn_NodeName = node;
AddTail((struct List *)spi,(struct Node *)spn);
}
}
}
freesregexp(pat);
} else {
/* check if there is any path to parse */
if (*wld) {
if (!(spi->spi_SregList = parsepath(wld))) {
FreeMem(spi,sizeof(struct SpathInfo));
return NULL;
}
} else
spi->spi_SregList = NULL;
if (!(spn = makespathnode(NULL,anc,spi->spi_SregList)))
freespathinfo(spi);
AddTail((struct List *)spi,(struct Node *)spn);
}
return spi;
}
#undef ROOT
#undef INFO
#undef DEVC
struct SregList *
parsepath(wld)
char *wld;
/* This routine takes a wildcarded path and turns it into a singly
linked list of SregExp structures, one node for each path element. */
{
char *q,*p,*cp,c = 1,recurse;
struct SregExp *sre;
struct SregList *srl,*srr = NULL;
if (!(cp = getmem(strlen(wld)+1))) {
report(MEM_ERROR);
return NULL;
}
strcpy(cp,wld);
q = cp;
while (*q && c) {
if (strncmp(q,".../",4) == 0) {
recurse = SRF_RECURSE;
q += 4;
} else
recurse = 0;
p = q;
while (*q && *q != '/') q++;
c = *q;
*q = 0;
if (!(sre = parsesregexp(p)))
goto bad;
sre->sre_Flag |= recurse;
*q++ = c;
if (!srr) {
if (!(srl = srr = getmem(sizeof(struct SregList)))) {
report(MEM_ERROR);
goto bad;
}
} else {
if (!(srl = (srl->srl_next = getmem(sizeof(struct SregList))))) {
report(MEM_ERROR);
goto bad;
}
}
srl->srl_next = NULL;
srl->srl_sreg = sre;
}
if (c == '/') /* If path ends in a / then just take dirs */
srl->srl_sreg->sre_Flag |= SRF_JUSTDIRS;
FreeMem(cp,strlen(cp)+1);
return srr;
bad:
if (sre)
freesregexp(sre);
FreeMem(cp,strlen(cp)+1);
while (srl) {
if (srl->srl_sreg)
freesregexp(srl->srl_sreg);
FreeMem(srl,sizeof(struct SregList));
srl = srl->srl_next;
}
return NULL;
}
struct SpathNode *
makespathnode(lock,file,sreg)
BPTR lock;
char *file;
struct SregList *sreg;
/* This routine makes a new node to be linked into the list of current
directory locks, basically */
{
struct SpathNode *spn;
BPTR cdir;
if (!(spn = getmem(sizeof(struct SpathNode)))) {
report(MEM_ERROR);
return NULL;
}
if (lock)
cdir = CurrentDir(lock);
if (!(spn->spn_Lock = Lock(file,SHARED_LOCK))) {
FreeMem(spn,sizeof(struct SpathNode));
return NULL;
}
spn->spn_SregList = sreg;
if (!(Examine(spn->spn_Lock,&spn->spn_FIB))) {
UnLock(spn->spn_Lock);
FreeMem(spn,sizeof(struct SpathNode));
return NULL;
}
spn->spn_Flags = 0;
spn->spn_NodeName = NULL;
if (lock)
CurrentDir(cdir);
return spn;
}
#define FILENAME (spn->spn_FIB.fib_FileName)
#define NEXTPATH (spn->spn_SregList->srl_next)
#define THISPATH (spn->spn_SregList)
#define LOCK (spn->spn_Lock)
#define FIB (spn->spn_FIB)
#define SREG (spn->spn_SregList->srl_sreg)
#define ISDIR (FIB.fib_DirEntryType > 0)
#define ISRECURSE (SREG->sre_Flag & SRF_RECURSE)
#define ISDONEONCE (spn->spn_Flags & SPF_DONEONCE)
#define ISJUSTDIRS (SREG->sre_Flag & SRF_JUSTDIRS)
#define WANTIT (ISDIR ? dirs >= 0 : !ISJUSTDIRS && dirs <= 0)
#define SIGBREAKF_ANY (SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D | SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_F)
int
nextfile(spi,buf,len,dirs)
struct SpathInfo *spi;
char *buf;
int len,dirs;
/* This routine is a mess. It jumps all over the place and is generally
hard to follow. The basic idea behind it is to implement recursion,
but without using the stack. Basically the linked list of SpathNode
structures, anchored in the SpathInfo structure works as our stack
for us. "Why not just use the stack?" you ask. Well, unfortunately,
we have to return in the middle of the scan, each time a new match
is found. This would mean unrolling all of the stack that defines
how far through the search we are to get back to the return address.
By using the linked list of SpathInfo structures, we can preserve
the state of the 'stack' betweem calls. */
{
struct SpathNode *spn;
try_again:
if (SetSignal(0,0) & SIGBREAKF_ANY)
return SPE_SIGBREAK;
spn = spi->spi_TailPred;
/* check if we're done. */
if (!spn->spn_Pred) {
report(ERROR_NO_MORE_ENTRIES);
return SPE_ALL_DONE;
}
/* check if we're at the end of the path: used to match just nodes.*/
if (!THISPATH) {
if (ISDONEONCE)
goto pop;
spn->spn_Flags |= SPF_DONEONCE;
if (dirs >= 0) {
return buildpath(spi,buf,len);
} else
goto pop;
}
/* check if we set a delayed decend */
if (spn->spn_Flags & SPF_DECEND)
goto decend;
/* check if it matches the null string, ie parent dir */
if (SREG->sre_Type == SRP_NULL) {
/* Check if its done or there is no parent. */
if (ISDONEONCE || !ParentDir(LOCK))
goto pop;
spn->spn_Flags |= SPF_DONEONCE; /* Mark it as done. */
/* mark it as parent match for buildpath */
spn->spn_Flags |= SPF_NEXTPARENT;
if (!(spn = makespathnode(LOCK,"/",NEXTPATH)))
return SPE_ERROR;
AddTail((struct List *)spi,(struct Node *)spn);
goto try_again;
}
/* Check if we can do it quickly */
if ((SREG->sre_Type == SRP_STRING ||
SREG->sre_Type == SRP_ONECHAR) && !ISRECURSE) {
BPTR cdir,lock;
/* Have we already done it? */
if (ISDONEONCE)
goto pop;
/* Mark it as done. */
spn->spn_Flags |= SPF_DONEONCE;
cdir = CurrentDir(LOCK);
if (SREG->sre_Type == SRP_STRING)
lock = Lock(SREG->sre_Data.string,SHARED_LOCK);
else {
char n[2];
n[0] = SREG->sre_Data.onechar;
n[1] = 0;
lock = Lock(n,SHARED_LOCK);
}
CurrentDir(cdir);
if (!lock)
goto pop;
if (!Examine(lock,&FIB)) {
UnLock(lock);
return SPE_ERROR;
}
UnLock(lock);
if (!NEXTPATH) {
if (WANTIT)
return buildpath(spi,buf,len);
else
goto pop;
}
if (ISDIR) {
if (!(spn = makespathnode(LOCK,FILENAME,NEXTPATH))) {
return SPE_ERROR;
}
AddTail((struct List *)spi,(struct Node *)spn);
goto try_again;
}
goto pop;
}
while (ExNext(LOCK,&FIB)) {
if (SetSignal(0,0) & SIGBREAKF_ANY)
return SPE_SIGBREAK;
if (matchsregexp(FILENAME,SREG,FALSE)) {
if (ISDIR && ISRECURSE)
spn->spn_Flags |= SPF_DECEND;
if (!NEXTPATH) {
if (WANTIT)
return buildpath(spi,buf,len);
} else if (ISDIR) {
if (!(spn = makespathnode(LOCK,FILENAME,NEXTPATH))) {
return SPE_ERROR;
}
AddTail((struct List *)spi,(struct Node *)spn);
goto try_again;
}
}
if (ISDIR && ISRECURSE) {
decend:
spn->spn_Flags &= ~SPF_DECEND;
if (!(spn = makespathnode(LOCK,FILENAME,THISPATH))) {
return SPE_ERROR;
}
AddTail((struct List *)spi,(struct Node *)spn);
goto try_again;
}
}
if (IoErr() != ERROR_NO_MORE_ENTRIES)
return SPE_ERROR;
pop:
RemTail((struct List*)spi);
freespathnode(spn);
goto try_again;
}
#undef FILENAME
#undef NEXTPATH
#undef THISPATH
#undef LOCK
#undef FIB
#undef SREG
#undef ISDIR
#undef ISRECURSE
#undef ISDONEONCE
#undef ISJUSTDIRS
#undef WANTIT
int
buildpath(spi,buf,len)
struct SpathInfo *spi;
char *buf;
int len;
/* This routine turns the current 'stack' of SpathNode structures into
a file name the AmigaDOS will like. */
{
struct SpathNode *spn = spi->spi_Head;
int i = 0;
char *q;
if (len < 1)
return SPE_BUFF_FULL;
if (spn->spn_Succ && spn->spn_NodeName) {
while (spn->spn_Succ->spn_Succ && spn->spn_Succ->spn_NodeName) {
spn = spn->spn_Succ;
}
}
if (q = spn->spn_NodeName) {
while (*q && i < len)
buf[i++] = *q++;
if (i >= len)
return SPE_BUFF_FULL;
}
while (spn->spn_Succ) {
if (spn->spn_Flags & SPF_NEXTPARENT) {
buf[i++] = '/';
if (i >= len)
return SPE_BUFF_FULL;
} else {
q = spn->spn_FIB.fib_FileName;
while (*q && i < len)
buf[i++] = *q++;
if (i >= len)
return SPE_BUFF_FULL;
if (spn->spn_Succ->spn_Succ ||
spn->spn_SregList->srl_sreg->sre_Flag & SRF_JUSTDIRS) {
buf[i++] = '/';
if (i >= len)
return SPE_BUFF_FULL;
}
}
spn = spn->spn_Succ;
}
buf[i] = 0;
return i;
}
void
freespathinfo(spi)
struct SpathInfo *spi;
/* This routine frees all of the resoureces tied up in a SpathInfo
structure */
{
struct SpathNode *spn;
struct SregList *srl,*next;
while (spn = (struct SpathNode *)RemTail((struct List *)spi))
freespathnode(spn);
for (srl = spi->spi_SregList; srl; srl = next) {
freesregexp(srl->srl_sreg);
next = srl->srl_next;
FreeMem(srl,sizeof(struct SregList));
}
FreeMem(spi,sizeof(struct SpathInfo));
}
void
freespathnode(spn)
struct SpathNode *spn;
/* This routine frees the memory and lock in a SpathNode structure. */
{
if (spn->spn_NodeName) {
FreeMem(spn->spn_NodeName,strlen(spn->spn_NodeName)+1);
}
UnLock(spn->spn_Lock);
FreeMem(spn,sizeof(struct SpathNode));
}
#ifdef __DEBUG__
/* This is some debugging stuff, not compiled into the release version. */
void
puts(c)
char *c;
{
Write(Output(),c,strlen(c));
Write(Output(),"\n",1);
}
#include <stdarg.h>
extern void vsprintf(char *, char *, va_list);
void printf(f, ...)
char *f;
{
char buff[100];
va_list va;
va_start(va,f);
vsprintf(buff,f,va);
va_end(va);
Write(Output(),buff,strlen(buff));
}
#endif