home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 18
/
aminetcdnumber181997.iso
/
Aminet
/
comm
/
ums
/
SUMSTools.lha
/
UMS
/
Tools
/
SUMSTools
/
Source
/
filter.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-08-03
|
9KB
|
436 lines
/*
** General Purpose Expression Filter Code.
**
** You need a BitHook and a FilterSpec to customize this.
**
** Your data needs to have the ability to flag certain entries
** with certain bits and select some of them with mask and match
** values, just as UMS. This is absolutely necessary for a fast
** and efficient filter handling!
**
** This code is prepared to have complexity values for expressions.
** Complex expressions (that might take a long time to evaluate)
** would be calculated after less complex expressions already
** clipped away a considerable amount of data.
**
** sumstools don't make use of these complexity values for now,
** all complexity values are set to 0.
*/
/* 30-Jan-94 [kmel] Corrected misfeature with filter token, "AND"
** and "OR" were also recognized in expressions.
*/
#include <exec/memory.h>
#include "sumstl.h"
#include <stdio.h>
#include <ctype.h>
#include "filter.h"
#define between(a,x,b) ((UBYTE)(x)>=(UBYTE)(a) && (UBYTE)(x)<=(UBYTE)(b))
struct Expression
{
struct Expression *left;
struct Expression *right;
struct Hook *hook;
ULONG uid;
APTR udata;
UBYTE relation;
UBYTE complexity;
char data[1];
};
#define REL_NONE 0
#define REL_FIRST 1
#define REL_LOWEQ 1
#define REL_HIGHEQ 2
#define REL_LOWER 3
#define REL_HIGHER 4
#define REL_NOTEQUAL 5
#define REL_EQUAL 6
#define REL_LAST 6
#define CON_FIRST 7
#define CON_OR 7
#define CON_AND 8
#define CON_LAST 8
#define OPEN_BRACE 9
#define CLOSE_BRACE 10
struct FilterTokenize
{
char *name;
char token;
};
static struct FilterTokenize Tokens[] =
{
{ "OR" , CON_OR },
{ "|" , CON_OR },
{ "AND", CON_AND },
{ "&" , CON_AND },
{ "<=" , REL_LOWEQ },
{ ">=" , REL_HIGHEQ },
{ "<" , REL_LOWER },
{ ">" , REL_HIGHER },
{ "!=" , REL_NOTEQUAL },
{ "<>" , REL_NOTEQUAL },
{ "=" , REL_EQUAL },
{ "(" , OPEN_BRACE },
{ ")" , CLOSE_BRACE },
{ NULL , 0 }
};
static char *FilterTokenize(char *spec,struct FilterTokenize *tokens)
{
struct FilterTokenize *x;
char *str = spec;
BOOL anf = FALSE, space = FALSE, con;
int len;
while (*str)
{
// printf("spec: %s space: %d\n", spec, space);
if (*str=='"')
{
anf = !anf;
memmove(str,str+1,strlen(str));
}
else if (!anf)
{
if (*str==' ')
{
memmove(str,str+1,strlen(str));
space = TRUE;
}
else
{
for (x=tokens; x->name; x++)
{
if (!strnicmp(str, x->name, len = strlen(x->name)))
{
// printf("Token: %s space: %d\n", x->name, space);
if ((con = between(CON_FIRST, x->token, CON_LAST)) && (*(str+len) != ' '))
space = FALSE;
if (!con || space)
{
// printf("Token inserted: %s\n", x->name);
*str = x->token;
if (len>1)
memmove(str+1, str+len,strlen(str+len)+1);
break;
}
}
}
if (!x->name)
str++;
space = FALSE;
}
}
else
str++;
}
return(spec);
}
static struct FilterSpec *FindFilterSpec(struct FilterSpec *spec,char *name,int len)
{
struct FilterSpec *fs;
for (fs=spec;fs->keyword;fs++)
if (!(strnicmp(fs->keyword,name,len)))
return(fs);
return(NULL);
}
#define FCERROR ((char *)-1)
static char *findconj(char *str,int len)
{
int blevel = 0;
while (len--)
{
if (!blevel && between(CON_FIRST,*str,CON_LAST))
{
return(str);
}
else if (*str==OPEN_BRACE)
{
blevel++;
}
else if (*str==CLOSE_BRACE)
{
if (!blevel) return(FCERROR);
blevel--;
}
str++;
}
return(blevel ? FCERROR : NULL);
}
static VOID deleteexp(struct Expression *exp)
{
if (exp)
{
deleteexp(exp->left);
deleteexp(exp->right);
FreeVec(exp);
}
}
static APTR createexp(LONG *err,struct Hook *hook,struct FilterSpec *spec,char *str,int len)
{
char *c;
struct Expression *exp;
if (len==-1) len=strlen(str);
if (len<1)
{
*err = FIL_ERROR_EMPTYEXPRESSION;
return(NULL);
}
if ((c=findconj(str,len)) == FCERROR)
{
*err = FIL_ERROR_UNMATCHEDBRACES;
return(NULL);
}
if (c)
{
if (exp=AllocVec(sizeof(struct Expression),MEMF_CLEAR))
{
if (exp->left = createexp(err,hook,spec,str,c-str))
{
if (exp->right = createexp(err,hook,spec,c+1,len-(c-str)-1))
{
exp->hook = hook;
exp->relation = *c;
return(exp);
}
}
deleteexp(exp);
}
else
*err = FIL_ERROR_OUTOFMEMORY;
return(NULL);
}
else if (str[0]==OPEN_BRACE)
{
if (str[len-1]!=CLOSE_BRACE)
{
*err = FIL_ERROR_UNMATCHEDBRACES;
return(NULL);
}
return(createexp(err,hook,spec,str+1,len-2));
}
else if (len>=3)
{
int l;
struct FilterSpec *fs;
c = str;
while (*c && !between(REL_FIRST,*c,REL_LAST))
c++;
if (!*c)
{
*err = FIL_ERROR_MISC;
return(NULL);
}
if ((l = c - str)<1)
{
*err = FIL_ERROR_MISC;
return(NULL);
}
if (!(fs = FindFilterSpec(spec,str,l)))
{
*err = FIL_ERROR_UNKNOWNKEYWORD;
return(NULL);
}
str += l+1;
len -= l+1;
if (len<0)
{
*err = FIL_ERROR_MISC;
return(NULL);
}
if (!(exp=AllocVec(sizeof(struct Expression)+len,MEMF_CLEAR)))
{
*err = FIL_ERROR_OUTOFMEMORY;
return(NULL);
}
exp->hook = hook;
exp->uid = fs->id;
exp->udata = fs->data;
exp->relation = *c;
exp->complexity = 0;
if (len>0) strncpy(exp->data,str,len);
return(exp);
}
*err = FIL_ERROR_MISC;
return(NULL);
}
static LONG filterexp(struct Expression *exp,APTR data,ULONG mask,ULONG match,ULONG setbit)
{
int err;
ULONG help = setbit<<1;
/*printf("fexp: mask %08lx match %08lx set %08lx\n",mask,match,setbit);*/
if (help & (FIL_LASTBIT>>2)) return(FIL_ERROR_TOODEEP);
mask |= setbit;
switch (exp->relation)
{
case CON_AND:
{
ULONG help2 = help<<1;
if (exp->left->complexity <= exp->right->complexity)
{
if (err=filterexp(exp->left ,data,mask,match,help)) return(err);
if (err=filterexp(exp->right,data,mask|help,match|help,help2)) return(err);
}
else
{
if (err=filterexp(exp->right,data,mask,match,help)) return(err);
if (err=filterexp(exp->left ,data,mask|help,match|help,help2)) return(err);
}
if (err=CallHook(exp->hook,data,exp->uid,exp->udata,mask|help|help2,match|help|help2,setbit,help2,FIL_ACTION_BITS,NULL)) return(err);
if (err=CallHook(exp->hook,data,exp->uid,exp->udata,mask|help,match|help,0,help,FIL_ACTION_BITS,NULL)) return(err);
}
break;
case CON_OR:
{
if (exp->left->complexity <= exp->right->complexity)
{
if (err=filterexp(exp->left ,data,mask,match,setbit)) return(err);
if (err=filterexp(exp->right,data,mask,match,setbit)) return(err);
}
else
{
if (err=filterexp(exp->right,data,mask,match,setbit)) return(err);
if (err=filterexp(exp->left ,data,mask,match,setbit)) return(err);
}
}
break;
default:
{
switch (exp->relation)
{
case REL_EQUAL:
{
if (err=CallHook(exp->hook,data,exp->uid,exp->udata,mask,match,setbit,0,FIL_ACTION_EQUAL,exp->data)) return(err);
}
break;
case REL_NOTEQUAL:
{
if (err=CallHook(exp->hook,data,exp->uid,exp->udata,mask,match,help,0,FIL_ACTION_EQUAL,exp->data)) return(err);
if (err=CallHook(exp->hook,data,exp->uid,exp->udata,mask|help,match,setbit,0,FIL_ACTION_BITS,NULL)) return(err);
if (err=CallHook(exp->hook,data,exp->uid,exp->udata,mask|help,match|help,0,help,FIL_ACTION_BITS,NULL)) return(err);
}
break;
case REL_LOWEQ:
{
if (err=CallHook(exp->hook,data,exp->uid,exp->udata,mask,match,setbit,0,FIL_ACTION_EQUAL,exp->data)) return(err);
}
case REL_LOWER:
{
if (err=CallHook(exp->hook,data,exp->uid,exp->udata,mask,match,setbit,0,FIL_ACTION_LOWER,exp->data)) return(err);
}
break;
case REL_HIGHER:
{
if (err=CallHook(exp->hook,data,exp->uid,exp->udata,mask,match,help,0,FIL_ACTION_EQUAL,exp->data)) return(err);
}
case REL_HIGHEQ:
{
if (err=CallHook(exp->hook,data,exp->uid,exp->udata,mask,match,help,0,FIL_ACTION_LOWER,exp->data)) return(err);
if (err=CallHook(exp->hook,data,exp->uid,exp->udata,mask|help,match,setbit,0,FIL_ACTION_BITS,NULL)) return(err);
if (err=CallHook(exp->hook,data,exp->uid,exp->udata,mask|help,match|help,0,help,FIL_ACTION_BITS,NULL)) return(err);
}
break;
}
}
break;
}
return(FIL_ERROR_OK);
}
/*
** That's the master function. You call only this one from outside.
*/
LONG FilterExpression(struct Hook *hook,struct FilterSpec *spec,char *str,APTR data,ULONG mask,ULONG match,ULONG setbit)
{
LONG err;
struct Expression *exp;
char *dup;
if (dup=AllocVec(strlen(str)+1,MEMF_ANY))
{
strcpy(dup,str);
if (exp=createexp(&err,hook,spec,FilterTokenize(dup,Tokens),strlen(dup)))
{
err=filterexp(exp,data,mask,match,setbit);
deleteexp(exp);
}
FreeVec(dup);
}
return(err);
}