home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frozen Fish 1: Amiga
/
FrozenFish-Apr94.iso
/
bbs
/
alib
/
d1xx
/
d102
/
match_stuff.lha
/
Match_Stuff
/
Mat.c
< prev
next >
Wrap
C/C++ Source or Header
|
1987-09-06
|
17KB
|
545 lines
/* Mat -- string and file matching filter 87:8:15 */
/* Copyright (C) 1987 Peter Goodeve */
#include <stdio.h>
#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 <pattern> [<template>] filenames...\n",
stderr);
exit(0);
}
++argv; /* skip over program name */
argc--;
while (checkarg(&argc, &argv)) /* loop */;
if (matchmode & MATCH_NEEDPAT) {
origpat = *argv++;
argc--;
if (!(cmplcode = CmplPat(origpat,aux))) {
fputs("badly formed pattern\n",stderr);
exit(20);
}
uppercase(origpat, upperpat); /* best to do it now -- in case...*/
}
if ((cmplcode & CODE_SLICE) || (matchmode & MATCH_NEEDTMPLT)) {
if (argc-- < 2) {
fputs( "this format requires a template argument...\n",
stderr);
exit(20);
}
splice = *argv++;
for (failspl = splice; *failspl;)
if (*failspl++ == '^' && *failspl++ == '|') break;
if(*failspl) *(failspl-2) = '\0';
else failspl = NULL;
}
for ( ; argc; argc--, argv++) {
while (checkarg(&argc, &argv)); /* loop */
if (!argc /* might get keyw. at end of string */) break;
if (casesens || !origpat) pat = origpat;
else pat = upperpat;
if (matchmode == MATCH_IMMED) {
matchnames(*argv,pat,aux,splice,failspl);
continue; /* go into short loop! */
}
ref = buildrefs(*argv, NULL);
if (builderr)
fputs("Bad Filename Pattern\n", stderr);
else while (fname = findfile(ref)) {
if (matchmode == MATCH_NAMES) {
if (!splice) {
fputs("MUST have a template!\n", stderr);
CurrentDir(maindir);
exit(20);
}
matchnames(fname,pat,aux,splice,failspl);
}
else {
fp = openfile(fname);
if (matchmode == JOIN_FILES)
copyfile(fp);
else
matchfile(fp, pat, aux, splice, failspl);
fclose(fp);
}
}
freerefs(ref);
CurrentDir(maindir);
}
exit(success ? 0 : 5); /* returns 0 if success, otherwise WARN */
}
/* numeric string used to maintain sequential index number of matches: */
char findxnum[6] = "00000",
*endfindx = &findxnum[4];
/*
* matchfile -- procedure to search for matching lines in the currently
* open file. If there is no template, any matching line is
* sent to the standard output, otherwise the pieces specified
* by the template are spliced together into a new output line.
*/
matchfile(fp, pat, aux, template, ftemplate)
FILE *fp; char *pat, *aux, *template, *ftemplate;
{
char inline[257], upperline[256], cuts[33],
linenum[10], *endnum = &linenum[4], *lnp,
pieces[256], compline[300],
*linep, *matchp;
struct CutsRef sliceset[15], *fsliceset; /* probably should be static */
char *Splice();
int p;
strcpy(linenum, "00000");
for (p = 0; p < 15; p++) sliceset[p].Mode = 0;
sliceset[5].ID = 'O';
sliceset[5].Segment = inline;
sliceset[6].ID = 'N';
sliceset[6].Segment = linenum;
sliceset[7].ID = 'F';
sliceset[7].Segment = LocalName;
sliceset[8].ID = 'D';
sliceset[8].Segment = FileDir;
sliceset[9].ID = 'I';
sliceset[9].Segment = findxnum;
sliceset[10].ID = 'B';
sliceset[10].Segment = "\n";
sliceset[11].ID = 'Q';
sliceset[11].Segment = "\"";
sliceset[12].ID = 0; /* until we add more stuff.. */
fsliceset = &sliceset[5]; /* this set may be used if no match */
while (fgets(matchp = inline, 256, fp)) {
p = strlen(inline);
for (lnp = endnum; lnp >= linenum && ++(*lnp) > '9';)
*lnp-- = '0';
if (inline[--p] == '\n') inline[p] = '\0'; /* note we move back */
if (!casesens)
uppercase(inline, matchp = upperline);
if (SMatch(pat, aux, matchp, cuts)) {
success = TRUE;
for (lnp = endfindx; lnp >= findxnum && ++(*lnp) > '9';)
*lnp-- = '0';
if (template) {
Slice(inline, cuts, pieces, sliceset);
linep = Splice(sliceset, template, compline);
}
else linep = inline;
fputs(linep, stdout);
if (newlines) fputc('\n',stdout);
if (firstonly) break;
}
else
if (ftemplate) { /* may specify output if match fails, too */
fputs( Splice(fsliceset, ftemplate, compline), stdout);
if (newlines) fputc('\n', stdout);
}
}
}
/*
* matchnames -- procedure to match literal strings -- either filenames
* or literal arguments in the command line. Action is
* similar to matchfile, but slicing information can be
* obtained from the filename pattern rather than a
* separately specified one and splicing may occur without
* any slices (using implicitly defined pieces).
*/
matchnames(fname, pat, aux, template, ftemplate)
char *fname, *pat, *aux, *template, *ftemplate;
{
char cuts[33], pieces[256], compline[300], *linep, *matchp;
struct CutsRef sliceset[15], *fsliceset; /* probably should be static */
char uppername[64];
char *Splice(), *lnp;
int p;
for (p = 0; p < 15; p++) sliceset[p].Mode = 0;
sliceset[5].ID = 'O';
sliceset[5].Segment = fname;
sliceset[6].ID = 'N';
sliceset[6].Segment = findxnum; /* for convenience (?!) */
sliceset[7].ID = 'F';
sliceset[7].Segment = LocalName;
sliceset[8].ID = 'D';
sliceset[8].Segment = FileDir;
sliceset[9].ID = 'I';
sliceset[9].Segment = findxnum;
sliceset[10].ID = 'B';
sliceset[10].Segment = "\n";
sliceset[11].ID = 'Q';
sliceset[11].Segment = "\"";
sliceset[12].ID = 0; /* until we add more stuff.. */
fsliceset = &sliceset[5];
*cuts = '\0';
if (!casesens)
uppercase(fname, matchp = uppername);
else matchp = fname;
if (!pat /* may be missing */
|| SMatch(pat, aux, matchp, cuts)) {
success = TRUE;
for (lnp = endfindx; lnp >= findxnum && ++(*lnp) > '9';)
*lnp-- = '0';
if (template) {
Slice(fname, *cuts ? cuts : filecuts, pieces, sliceset);
linep = Splice(sliceset, template, compline);
}
else linep = fname;
fputs(linep, stdout);
if (newlines) fputc('\n',stdout);
}
else
if (ftemplate) {
fputs( Splice(fsliceset, ftemplate, compline), stdout);
if (newlines) fputc('\n', stdout);
}
}
/*
* copyfile -- simply copies current file to the standard output
*/
#define BUFLEN 512
copyfile(fp) FILE *fp;
{
UBYTE buffer[BUFLEN];
ULONG fhin, fhout;
int xfbytes;
fhin = fileno(fp);
fhout = fileno(stdout);
while ((xfbytes = read(fhin, buffer, BUFLEN)) > 0)
write(fhout, buffer, xfbytes);
success = TRUE;
}
/*
* Special Argument Recognition Section
*
* checkarg -- matches the argument against argpat, and takes the
* appropriate action if there is a match.
* Note how it uses the slicing information returned
* by SMatch as a convenient way of determining the
* actual meaning of the argument.
*/
char argpat[] =
"NOCASE^|CASE^|(FILES|F)^|STRING^|(JOIN|J)^|FIRST^|ALL^|NOLINES^|LINE^";
#define NOCASE 7
#define CASE 13
#define FILES 24
#define STRING 32
#define JOIN 42
#define FIRST 49
#define ALL 54
#define NOLINES 63
#define LINE 69
UBYTE argaux[72]; /* lengthen as necessary! */
checkarg(pargc,pargv) int *pargc; char **pargv[];
{
char argcuts[33], upperarg[256], *cutp = argcuts;
if (!*pargc) return FALSE; /* don't run off the end... */
CmplPat(argpat, argaux); /* ...pure laziness */
uppercase(**pargv, upperarg);
if (SMatch(argpat, argaux, upperarg, argcuts)) {
while (!cutp[1]) cutp += 2; /* skip phony subpatterns (e.g. "F") */
switch((int)(*cutp)) {
case NOCASE: casesens = FALSE;
break;
case CASE: casesens = TRUE;
break;
case FILES: matchmode = MATCH_NAMES;
break;
case STRING: matchmode = MATCH_IMMED;
break;
case JOIN: matchmode = JOIN_FILES;
break;
case FIRST: firstonly = TRUE;
break;
case ALL: firstonly = FALSE;
break;
case NOLINES: newlines = FALSE;
break;
case LINE: newlines = TRUE;
fputc('\n', stdout);
break;
}
(*pargv)++;
(*pargc)--;
return TRUE;
}
return FALSE;
}
/*
* uppercase -- translates supplied source string to upper case
* (yes, I know there is a library function...)
*/
uppercase(src,dest) char *src, *dest;
{
while (*dest++ = (*src >= 'a' && *src <= 'z') ?
*src++ + ('A' - 'a') : *src++) /* loop */;
}