home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fred Fish Collection 1.5
/
ffcollection-1-5-1992-11.iso
/
ff_disks
/
400-499
/
ff473.lzh
/
CNewsSrc
/
cnews_src.lzh
/
libcnews
/
ngmatch.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-12-25
|
7KB
|
247 lines
/*
* ngmatch - newsgroup name matching
*
* ngmatch returns true iff the newsgroup(s) in ngs match
* the pattern(s) in ngpat, where
*
* ngpats: { ngpat { "," ngpat }* }?
* ngpat: "!"? word { "." word }*
* word: { alphanum }+ | "all"
*
* Only one group need match for success.
* Failure to match any pattern with a group is a mismatch of that group only.
* Failure to match any group against any pattern is a total failure.
*
* For each group, note the depth of each match against the patterns,
* negated or not. Ignore mismatches. The deepest match wins at the
* end: a deeper negated match is a failure, a deeper plain match is a
* success; a tie is a failure, but see the description of wildcards.
*
* "all" in a pattern is a wildcard that matches exactly one word;
* it does not cross "." (NGDELIM) delimiters. A non-wildcard match is
* considered to have matched slightly deeper than a wildcard match in the
* same position. This ensures that !alt.sex.all,alt.sex.bondage matches
* alt.sex.bondage.
*/
#include <stdio.h>
#include <string.h>
#ifdef unix
# include <sys/types.h>
#endif /* unix */
#include "news.h"
#define truth(bool) ((bool)? "yes": "no")
#ifndef STATIC
#define STATIC /* static */
#endif
#define ALL "all" /* word wildcard */
/* private */
static boolean debug = NO;
/* forwards */
FORWARD boolean mpatsmatch();
FORWARD int onepatmatch();
void
matchdebug(state)
boolean state;
{
debug = state;
}
boolean
ngmatch(ngpat, ngs)
char *ngpat, *ngs;
{
register char *ngp; /* point at current group */
register char *ngcomma;
register char *rngpat = ngpat;
if (debug)
(void) fprintf(stderr, "ngmatch(`%s', `%s')\n", rngpat, ngs);
for (ngp = ngs; ngp != NULL; ngp = ngcomma) {
register boolean match;
STRCHR(ngp, NGSEP, ngcomma);
if (ngcomma != NULL)
*ngcomma = '\0'; /* will be restored below */
match = mpatsmatch(rngpat, ngp); /* try 1 group, n-patterns */
if (ngcomma != NULL)
*ngcomma++ = NGSEP; /* point after the comma */
if (match)
return YES;
}
return NO; /* no pattern matched any group */
}
/*
* Match one group against multiple patterns, as above.
* The key is to keep track of how deeply plain and negated patterns matched.
*/
STATIC boolean
mpatsmatch(ngpat, grp)
char *ngpat, *grp;
{
register char *patp; /* point at current pattern */
register char *patcomma;
register int depth;
register int faildeepest = 0, hitdeepest = 0; /* in case no match */
register boolean negation;
register char *rgrp = grp; /* optimisation */
if (debug)
(void) fprintf(stderr, "mpatsmatch(`%s', `%s')\n", ngpat, grp);
for (patp = ngpat; patp != NULL; patp = patcomma) {
negation = NO;
STRCHR(patp, NGSEP, patcomma);
if (patcomma != NULL)
*patcomma = '\0'; /* will be restored below */
if (*patp == NGNEG) {
++patp;
negation = YES;
}
depth = onepatmatch(patp, rgrp); /* try 1 pattern, 1 group */
if (patcomma != NULL)
*patcomma++ = NGSEP; /* point after the comma */
if (depth == 0) /* mis-match */
; /* ignore it */
else if (negation) {
/* record depth of deepest negated matched word */
if (depth > faildeepest)
faildeepest = depth;
} else {
/* record depth of deepest plain matched word */
if (depth > hitdeepest)
hitdeepest = depth;
}
}
if (debug)
(void) fprintf(stderr, "mpatsmatch(`%s', `%s') returns %s\n",
ngpat, grp, truth(hitdeepest > faildeepest));
return hitdeepest > faildeepest;
}
/*
* Match a pattern against a group by looking at each word of pattern in turn.
*
* On a match, return the depth (roughly, ordinal number * k) of the rightmost
* word that matches. If group runs out first, the match fails; if pattern
* runs out first, it succeeds. On a failure, return zero.
*/
STATIC int
onepatmatch(patp, grp)
char *patp, *grp;
{
register char *rpatwd; /* used by word match (inner loop) */
register char *patdot, *grdot; /* point at dots after words */
register char *patwd, *grwd; /* point at current words */
register int depth = 0;
for (patwd = patp, grwd = grp; patwd != NULL && grwd != NULL;
patwd = patdot, grwd = grdot) {
register boolean match = NO;
register int incr = 20;
/*
* optimisation: first bytes *must* match, unless first
* pattern byte is start of ALL.
*/
if (*patwd != *grwd && *patwd != ALL[0]) {
depth = 0; /* words differed - mismatch */
break;
}
/* null-terminate words */
STRCHR(patwd, NGDELIM, patdot);
if (patdot != NULL)
*patdot = '\0'; /* will be restored below */
STRCHR(grwd, NGDELIM, grdot);
if (grdot != NULL)
*grdot = '\0'; /* will be restored below */
/*
* Match one word of pattern with one word of group.
* A pattern word of "all" matches any group word,
* but isn't worth as much.
*/
#ifdef FAST_STRCMP
match = STREQ(patwd, grwd);
if (!match && STREQ(patwd, ALL)) {
match = YES;
--incr;
}
#else
for (rpatwd = patwd; *rpatwd == *grwd++; )
if (*rpatwd++ == '\0') {
match = YES; /* literal match */
break;
}
if (!match) {
/* ugly special case match for "all" */
rpatwd = patwd;
if (*rpatwd++ == 'a' && *rpatwd++ == 'l' &&
*rpatwd++ == 'l' && *rpatwd == '\0') {
match = YES;
--incr;
}
}
#endif /* FAST_STRCMP */
if (patdot != NULL)
*patdot++ = NGDELIM; /* point after the dot */
if (grdot != NULL)
*grdot++ = NGDELIM;
if (!match) {
depth = 0; /* words differed - mismatch */
break;
}
depth += incr;
}
/* if group name ran out before pattern, then match fails */
if (grwd == NULL && patwd != NULL)
depth = 0;
if (debug)
(void) fprintf(stderr, "onepatmatch(`%s', `%s') returns %d\n",
patp, grp, depth);
return depth;
}
#ifdef CROSS_POSTINGS_RESTRICTED
/*
* ngtopsame(ngs) - true iff ngs are all in the same top-level distribution
*/
boolean
ngtopsame(ngs)
register char *ngs;
{
register char *nextng;
STRCHR(ngs, NGSEP, nextng);
if (nextng == NULL) /* no groups left */
return YES;
++nextng; /* skip NGSEP */
return firstsame(ngs, nextng) && ngtopsame(nextng);
}
/*
* firstsame(ng1, ng2) - true iff first characters (up to the first
* NGDELIM or NGSEP) are the same in each string. Neither string
* is guaranteed to be null-terminated (a small lie; one *is*).
*/
STATIC boolean
firstsame(ng1, ng2)
register char *ng1, *ng2;
{
register int ng1brk;
static char delimstr[] = { NGSEP, NGDELIM, '\0' };
extern int strcspn();
ng1brk = strcspn(ng1, delimstr);
return ng1brk == strcspn(ng2, delimstr) && STREQN(ng1, ng2, ng1brk);
}
#endif /* CROSS_POSTINGS_RESTRICTED */