home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 300-399 / ff319.lzh / CNewsSrc / cnews.orig.lzh / libcnews / ngmatch.c < prev    next >
C/C++ Source or Header  |  1989-06-27  |  6KB  |  223 lines

  1. /*
  2.  * ngmatch - newsgroup name matching
  3.  *
  4.  * ngmatch returns true iff the newsgroup(s) in ngs match
  5.  * the pattern(s) in ngpat, where
  6.  *
  7.  *     ngpats: { ngpat { "," ngpat }* }?
  8.  *    ngpat: "!"? word { "." word }*
  9.  *    word: { alphanum }+ | "all"
  10.  *
  11.  * Only one group need match for success.  (Redundant?)
  12.  *
  13.  * For each group, note the depth of each match against the patterns,
  14.  * negated or not.  Ignore mismatches.  The deepest match wins at the end;
  15.  * if it's a tie, negated matches are rejections.
  16.  *
  17.  * A match of any group against the patterns is a success.
  18.  * Failure to match any pattern with a group is a mismatch of that group.
  19.  * Failure to match any group against any pattern is a total failure.
  20.  *
  21.  * "all" in a pattern is a wildcard that matches exactly one word;
  22.  * it does not cross "." (NGDELIM) delimiters.
  23.  */
  24.  
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include <sys/types.h>
  28. #include "news.h"
  29.  
  30. #define truth(bool) ((bool)? "yes": "no")
  31.  
  32. #ifndef STATIC
  33. #define STATIC /* static */
  34. #endif
  35.  
  36. #define ALL "all"            /* word wildcard */
  37.  
  38. /* private */
  39. static boolean debug = NO;
  40.  
  41. /* forwards */
  42. extern boolean mpatsmatch();
  43.  
  44. void
  45. matchdebug(state)
  46. boolean state;
  47. {
  48.     debug = state;
  49. }
  50.  
  51. boolean
  52. ngmatch(ngpat, ngs)
  53. char *ngpat, *ngs;
  54. {
  55.     register char *ngp;            /* point at current group */
  56.     register char *ngcomma;
  57.     register char *rngpat = ngpat;
  58.  
  59.     if (debug)
  60.         (void) fprintf(stderr, "ngmatch(`%s', `%s')\n", rngpat, ngs);
  61.     for (ngp = ngs; ngp != NULL; ngp = ngcomma) {
  62.         register boolean match;
  63.  
  64.         INDEX(ngp, NGSEP, ngcomma);
  65.         if (ngcomma != NULL)
  66.             *ngcomma = '\0';    /* will be restored below */
  67.         match = mpatsmatch(rngpat, ngp); /* try 1 group, n-patterns */
  68.         if (ngcomma != NULL)
  69.             *ngcomma++ = NGSEP;    /* point after the comma */
  70.         if (match)
  71.             return YES;
  72.     }
  73.     return NO;            /* no pattern matched any group */
  74. }
  75.  
  76. /*
  77.  * Match one group against multiple patterns, as above.
  78.  * The key is to keep track of how deeply plain and negated patterns matched.
  79.  */
  80. STATIC boolean
  81. mpatsmatch(ngpat, grp)
  82. char *ngpat, *grp;
  83. {
  84.     register char *patp;        /* point at current pattern */
  85.     register char *patcomma;
  86.     register int depth;
  87.     register int faildeepest = 0, hitdeepest = 0;    /* in case no match */
  88.     register boolean negation;
  89.  
  90.     if (debug)
  91.         (void) fprintf(stderr, "mpatsmatch(`%s', `%s')\n", ngpat, grp);
  92.     for (patp = ngpat; patp != NULL; patp = patcomma) {
  93.         negation = NO;
  94.         INDEX(patp, NGSEP, patcomma);
  95.         if (patcomma != NULL)
  96.             *patcomma = '\0';    /* will be restored below */
  97.         if (*patp == NGNEG) {
  98.             ++patp;
  99.             negation = YES;
  100.         }
  101.         depth = onepatmatch(patp, grp);    /* try 1 pattern, 1 group */
  102.         if (patcomma != NULL)
  103.             *patcomma++ = NGSEP;    /* point after the comma */
  104.         if (depth == 0)            /* mis-match */
  105.             ;            /* ignore it */
  106.         else if (negation) {
  107.             /* record ordinal # of deepest negated matched word */
  108.             if (depth > faildeepest)
  109.                 faildeepest = depth;
  110.         } else {
  111.             /* record ordinal # of deepest plain matched word */
  112.             if (depth > hitdeepest)
  113.                 hitdeepest = depth;
  114.         }
  115.     }
  116.     if (debug)
  117.         (void) fprintf(stderr, "mpatsmatch(`%s', `%s') returns %s\n",
  118.             ngpat, grp, truth(hitdeepest > faildeepest));
  119.     return hitdeepest > faildeepest;
  120. }
  121.  
  122. /*
  123.  * Match a pattern against a group by looking at each word of pattern in turn.
  124.  *
  125.  * On a match, return the ordinal number of the rightmost word that matches.
  126.  * If group runs out first, the match fails; else it succeeds.
  127.  * On a failure, return zero.
  128.  */
  129. STATIC int
  130. onepatmatch(patp, grp)
  131. char *patp, *grp;
  132. {
  133.     register char *rpatwd;        /* used by word match (inner loop) */
  134.     register char *patdot, *grdot;    /* point at dots after words */
  135.     register char *patwd, *grwd;    /* point at current words */
  136.     register int depth = 0;
  137.  
  138.     for (patwd = patp, grwd = grp; patwd != NULL && grwd != NULL;
  139.         patwd = patdot, grwd = grdot, depth++) {
  140.         register boolean match;
  141.  
  142.             /* null-terminate words */
  143.             INDEX(patwd, NGDELIM, patdot);
  144.         if (patdot != NULL)
  145.             *patdot = '\0';        /* will be restored below */
  146.             INDEX(grwd, NGDELIM, grdot);
  147.         if (grdot != NULL)
  148.             *grdot = '\0';        /* will be restored below */
  149.  
  150.         /*
  151.          * Match one word of pattern with one word of group.
  152.          * A pattern word of "all" matches any group word.
  153.          */
  154. #ifdef FAST_STRCMP
  155.         match = STREQ(patwd, grwd) || STREQ(patwd, ALL);
  156. #else
  157.         match = NO;
  158.         for (rpatwd = patwd; *rpatwd == *grwd++; )
  159.             if (*rpatwd++ == '\0') {
  160.                 match = YES;        /* literal match */
  161.                 break;
  162.             }
  163.         if (!match) {
  164.             /* ugly special case match for "all" */
  165.             rpatwd = patwd;
  166.             match = *rpatwd++ == 'a' && *rpatwd++ == 'l' &&
  167.                     *rpatwd++ == 'l' && *rpatwd   == '\0';
  168.         }
  169. #endif                /* FAST_STRCMP */
  170.  
  171.         if (patdot != NULL)
  172.             *patdot++ = NGDELIM;    /* point after the dot */
  173.         if (grdot != NULL)
  174.             *grdot++ = NGDELIM;
  175.         if (!match) {
  176.             depth = 0;        /* words differed - mismatch */
  177.             break;
  178.         }
  179.     }
  180.     /* if group name ran out before pattern, then match fails */
  181.     if (grwd == NULL && patwd != NULL)
  182.         depth = 0;
  183.     if (debug)
  184.         (void) fprintf(stderr, "onepatmatch(`%s', `%s') returns %d\n",
  185.             patp, grp, depth);
  186.     return depth;
  187. }
  188.  
  189. #ifdef CROSS_POSTINGS_RESTRICTED
  190. /*
  191.  * ngtopsame(ngs) - true iff ngs are all in the same top-level distribution
  192.  */
  193. boolean
  194. ngtopsame(ngs)
  195. register char *ngs;
  196. {
  197.     register char *nextng;
  198.  
  199.     INDEX(ngs, NGSEP, nextng);
  200.     if (nextng == NULL)        /* no groups left */
  201.         return YES;
  202.     ++nextng;            /* skip NGSEP */
  203.     return firstsame(ngs, nextng) && ngtopsame(nextng);
  204. }
  205.  
  206. /*
  207.  * firstsame(ng1, ng2) - true iff first characters (up to the first
  208.  * NGDELIM or NGSEP) are the same in each string.  Neither string
  209.  * is guaranteed to be null-terminated (a small lie; one *is*).
  210.  */
  211. STATIC boolean
  212. firstsame(ng1, ng2)
  213. register char *ng1, *ng2;
  214. {
  215.     register int ng1brk;
  216.     static char delimstr[] = { NGSEP, NGDELIM, '\0' };
  217.     extern int strcspn();
  218.  
  219.     ng1brk = strcspn(ng1, delimstr);
  220.     return ng1brk == strcspn(ng2, delimstr) && STREQN(ng1, ng2, ng1brk);
  221. }
  222. #endif                /* CROSS_POSTINGS_RESTRICTED */
  223.