home *** CD-ROM | disk | FTP | other *** search
-
- /**********************************************************************
- * 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
-