/* Mat -- string and file matching filter 87:8:15 */ /* Copyright (C) 1987 Peter Goodeve */ #include #include "exec/types.h" #include "exec/memory.h" #include "libraries/DOS.h" #include "libraries/DOSextens.h" #include "splicer.h" /* CmplPat() returns this bit set if pattern is "sliced", * and therefore template is needed: */ #define CODE_SLICE 128 /* This structure is used to keep track of subdirectory and file names * and patterns as they are scanned for matches: */ struct FileRef { struct FileInfoBlock fileblock; /* declared first so it will be LW-A */ ULONG currlock, /* lock for PARENT directory to this segment */ flags; char *pathname, /* remainder of path name from this point */ chunkpat[64], /* pattern specified for this file or dir */ chunkaux[64]; /* auxiliary vector for pattern match */ struct FileRef *nextref, *prevref; /* list pointers */ }; #define HAVELOCK 1 #define NEWLOCK 2 #define DONETOP 4 #define ISDEVICE 16 #define ISPATTERN 256 #define MATCH_NODIRS 256 #define MATCH_NEEDPAT 128 #define MATCH_NEEDTMPLT 64 #define MATCH_TEXT (0 | MATCH_NODIRS |MATCH_NEEDPAT) #define MATCH_NAMES (1 | MATCH_NEEDTMPLT) #define MATCH_IMMED (2 | MATCH_NEEDPAT) #define JOIN_FILES (3 | MATCH_NODIRS) int casesens = TRUE, newlines = TRUE, firstonly = FALSE; int matchmode = MATCH_TEXT; int success = FALSE; ULONG maindir; /* current file references (for sliceset): */ char LocalName[64], FileDir[120]; UBYTE filecuts[33]; /* only need one of these */ /* Pointers to ends of File reference list * (full Kernel list structure wasn't worth it here...) */ struct FileRef *firstref, *endref; int builderr = 0; /* set if bad directory reference pattern */ /* * buildrefs -- procedure to allocate FileRefs for the segments * of a file path pattern. * Calls itself recursively until the complete path * specification has been processed. */ struct FileRef *buildrefs(pathname, prev) char *pathname; struct FileRef *prev; { char *pp, *cp; struct FileRef *tref; int res; tref = AllocMem(sizeof(struct FileRef),MEMF_PUBLIC | MEMF_CLEAR); if (!tref) { freerefs(firstref); exit(55); } endref = tref; if (!(tref->prevref = prev)) { *filecuts = builderr = 0; firstref = tref; } pp = tref->pathname = pathname; cp = tref->chunkpat; while (*pp && *pp != '/' && *pp != ':') *cp++ = (*pp >= 'a' && *pp <= 'z') ? *pp++ + ('A' - 'a') : *pp++; if (*pp == ':') { tref->flags |= ISDEVICE; *cp++ = ':'; if (tref->prevref /* not first segment!*/) { builderr = 2; return tref; } } else if (pp == pathname) *cp++ = '/'; *cp = '\0'; res = CmplPat(tref->chunkpat, tref->chunkaux); if (res > 1) tref->flags |= ISPATTERN; if (!res || ((res & CODE_SLICE) && tref->nextref)) { builderr = 1; return tref; } if (*pp) tref->nextref = buildrefs(++pp, tref); return tref; } /* freerefs -- procedure to return the memory used by the * chain of FileRefs to the free list. * Calls itself recursively until all items * in the chain have been freed. */ freerefs(ref) struct FileRef *ref; { if (!ref) return; firstref = endref = NULL; if (ref->flags & NEWLOCK) UnLock(ref->currlock); freerefs(ref->nextref); FreeMem(ref,sizeof(struct FileRef)); } /* * nextlock -- procedure to get a lock for the next higher level; * on the first call, it calls itself recursively until * the top level of the File Reference chain is reached, * at which point it obtains a lock for the current parent, * then returns a lock either for the specific name or * for the first match it finds to the specified pattern; * each level then repeats the process until a final * filename is reached. * Subsequent calls will return a new match if there is * one, otherwise will make recursive calls as far as * necessary to get a new branch of the pattern tree. * [Note that the bottom level match MUST be a file * -- it will not return a directory name.] */ ULONG nextlock(ref) struct FileRef *ref; { struct FileInfoBlock *fbp; char matchstr[108], *pp, *cp; ULONG lk, succ, thislock; fbp = &ref->fileblock; do { if (ref->flags & HAVELOCK) { CurrentDir(ref->currlock); if (!(ref->flags & ISPATTERN)) { thislock = Lock(ref->chunkpat, ACCESS_READ); ref->flags ^= HAVELOCK; /* this way only once..*/ if (thislock && Examine(thislock,fbp)) { return thislock; } } else { lk = ref->currlock; while (succ = ExNext(lk, fbp)) { if( ref->nextref /* not bottom level*/ ? fbp->fib_EntryType < 0 /* ignore files */ : ((matchmode & MATCH_NODIRS) && fbp->fib_EntryType > 0 /* ignore dirs */)) continue; pp = fbp->fib_FileName; cp = matchstr; while (*cp++ = (*pp >= 'a' && *pp <= 'z') ? *pp++ + ('A' - 'a') : *pp++) /* loop */; if (SMatch(ref->chunkpat, ref->chunkaux, matchstr, filecuts) ) break; } ; /* loop until found or exhausted */ if (succ) { return Lock(fbp->fib_FileName, ACCESS_READ); } else { ref->flags ^= HAVELOCK; /* lock no longer valid ..*/ } } } /**[END if (..HAVELOCK) ]**/ /* continues if no current valid lock */ if (ref->prevref) { if (ref->flags & NEWLOCK) UnLock(ref->currlock); ref->flags &= ~(HAVELOCK | NEWLOCK); if (thislock = nextlock(ref->prevref)) { ref->currlock = thislock; ref->flags |= HAVELOCK | NEWLOCK; } } else if (!(ref->flags & DONETOP)) { ref->currlock = CurrentDir(0); CurrentDir(ref->currlock); ref->flags |= (HAVELOCK | DONETOP); } if (ref->flags & HAVELOCK) { Examine(ref->currlock, fbp); } } while (ref->flags & HAVELOCK); return NULL; } /* * findfile -- procedure to scan the File Reference chain * to set a parent directory and get the name of * the next file to be accessed. * Calls nextlock to do most of the work. * Also sets up Directory and Filename strings * for use by the splicing section. */ char *findfile(ref) struct FileRef *ref; { ULONG thislock; char *thisname = endref->fileblock.fib_FileName; char *cp, *pp; struct FileRef *rp, *nrp; thislock = nextlock(endref); /* go up chain to find a matching file */ if (!thislock) return NULL; UnLock(thislock); strcpy(LocalName, thisname); cp = FileDir; for (rp = ref; nrp = rp->nextref; rp = nrp) { pp = rp->fileblock.fib_FileName; while (*cp = *pp++) cp++; *cp++ = (rp->flags & ISDEVICE) ? ':' : nrp->nextref ? '/' : '\0'; } *cp = '\0'; return thisname; } /* * openfile -- procedure to open the file found by findfile */ FILE *openfile(fname) char *fname; { FILE *fp; fp = fopen(fname,"r"); if (!fp) { fputs(fname,stderr); fputs(" -- Couldn't open file!\n",stderr); } return fp; /* regardless */ } /***************************************************************/ main(argc,argv) int argc; char **argv; { char *pat = NULL, aux[256], *splice = NULL, *failspl = NULL, *origpat = NULL, upperpat[256]; int cmplcode = 0; char *fname; struct FileRef *ref; FILE *fp; /* extern int DEBmode; DEBmode = 0; */ maindir = CurrentDir(0); CurrentDir(maindir); /* there must be a neater way to do this ? */ if (argc < 3) { fputs( "format is: MAT [