[BACK]Return to apropos_db.c CVS log [TXT][DIR] Up to [cvsweb.bsd.lv] / mandoc

Diff for /mandoc/Attic/apropos_db.c between version 1.1 and 1.7

version 1.1, 2011/11/13 10:12:05 version 1.7, 2011/11/20 12:46:53
Line 1 
Line 1 
 /*      $Id$ */  /*      $Id$ */
 /*  /*
  * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>   * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
  *   *
  * Permission to use, copy, modify, and distribute this software for any   * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above   * purpose with or without fee is hereby granted, provided that the above
Line 18 
Line 19 
 #include <fcntl.h>  #include <fcntl.h>
 #include <regex.h>  #include <regex.h>
 #include <stdarg.h>  #include <stdarg.h>
   #include <stdint.h>
 #include <stdlib.h>  #include <stdlib.h>
 #include <string.h>  #include <string.h>
   
Line 27 
Line 29 
 # include <db.h>  # include <db.h>
 #endif  #endif
   
   #include "mandocdb.h"
 #include "apropos_db.h"  #include "apropos_db.h"
 #include "mandoc.h"  #include "mandoc.h"
   
 enum    match {  struct  rec {
         MATCH_REGEX,          struct res       res; /* resulting record info */
         MATCH_REGEXCASE,          /*
         MATCH_STR,           * Maintain a binary tree for checking the uniqueness of `rec'
         MATCH_STRCASE           * when adding elements to the results array.
            * Since the results array is dynamic, use offset in the array
            * instead of a pointer to the structure.
            */
           int              lhs;
           int              rhs;
           int              matched; /* expression is true */
           int             *matches; /* partial truth evaluations */
 };  };
   
 struct  expr {  struct  expr {
         enum match       match;          int              regex; /* is regex? */
         int              mask;          int              index; /* index in match array */
         char            *v;          uint64_t         mask; /* type-mask */
         regex_t          re;          int              cs; /* is case-sensitive? */
           int              and; /* is rhs of logical AND? */
           char            *v; /* search value */
           regex_t          re; /* compiled re, if regex */
           struct expr     *next; /* next in sequence */
           struct expr     *subexpr;
 };  };
   
 struct  type {  struct  type {
         int              mask;          uint64_t         mask;
         const char      *name;          const char      *name;
 };  };
   
 static  const struct type types[] = {  static  const struct type types[] = {
         { TYPE_NAME, "name" },          { TYPE_An, "An" },
         { TYPE_FUNCTION, "func" },          { TYPE_Ar, "Ar" },
         { TYPE_UTILITY, "utility" },          { TYPE_At, "At" },
         { TYPE_INCLUDES, "incl" },          { TYPE_Bsx, "Bsx" },
         { TYPE_VARIABLE, "var" },          { TYPE_Bx, "Bx" },
         { TYPE_STANDARD, "stand" },          { TYPE_Cd, "Cd" },
         { TYPE_AUTHOR, "auth" },          { TYPE_Cm, "Cm" },
         { TYPE_CONFIG, "conf" },          { TYPE_Dv, "Dv" },
         { TYPE_DESC, "desc" },          { TYPE_Dx, "Dx" },
         { TYPE_XREF, "xref" },          { TYPE_Em, "Em" },
         { TYPE_PATH, "path" },          { TYPE_Er, "Er" },
         { TYPE_ENV, "env" },          { TYPE_Ev, "Ev" },
         { TYPE_ERR, "err" },          { TYPE_Fa, "Fa" },
         { INT_MAX, "all" },          { TYPE_Fl, "Fl" },
           { TYPE_Fn, "Fn" },
           { TYPE_Fn, "Fo" },
           { TYPE_Ft, "Ft" },
           { TYPE_Fx, "Fx" },
           { TYPE_Ic, "Ic" },
           { TYPE_In, "In" },
           { TYPE_Lb, "Lb" },
           { TYPE_Li, "Li" },
           { TYPE_Lk, "Lk" },
           { TYPE_Ms, "Ms" },
           { TYPE_Mt, "Mt" },
           { TYPE_Nd, "Nd" },
           { TYPE_Nm, "Nm" },
           { TYPE_Nx, "Nx" },
           { TYPE_Ox, "Ox" },
           { TYPE_Pa, "Pa" },
           { TYPE_Rs, "Rs" },
           { TYPE_Sh, "Sh" },
           { TYPE_Ss, "Ss" },
           { TYPE_St, "St" },
           { TYPE_Sy, "Sy" },
           { TYPE_Tn, "Tn" },
           { TYPE_Va, "Va" },
           { TYPE_Va, "Vt" },
           { TYPE_Xr, "Xr" },
           { INT_MAX, "any" },
         { 0, NULL }          { 0, NULL }
 };  };
   
 static  DB      *btree_open(void);  static  DB      *btree_open(void);
 static  int      btree_read(const DBT *, const struct mchars *, char **);  static  int      btree_read(const DBT *,
 static  int      exprexec(const struct expr *, char *);                          const struct mchars *, char **);
   static  int      expreval(const struct expr *, int *);
   static  void     exprexec(const struct expr *,
                           const char *, uint64_t, struct rec *);
   static  int      exprmark(const struct expr *,
                           const char *, uint64_t, int *);
   static  struct expr *exprexpr(int, char *[], int *, int *, size_t *);
   static  struct expr *exprterm(char *, int);
 static  DB      *index_open(void);  static  DB      *index_open(void);
 static  int      index_read(const DBT *, const DBT *,  static  int      index_read(const DBT *, const DBT *,
                         const struct mchars *, struct rec *);                          const struct mchars *, struct rec *);
 static  void     norm_string(const char *,  static  void     norm_string(const char *,
                         const struct mchars *, char **);                          const struct mchars *, char **);
 static  size_t   norm_utf8(unsigned int, char[7]);  static  size_t   norm_utf8(unsigned int, char[7]);
   static  void     recfree(struct rec *);
   
 /*  /*
  * Open the keyword mandoc-db database.   * Open the keyword mandoc-db database.
Line 89  btree_open(void)
Line 138  btree_open(void)
         memset(&info, 0, sizeof(BTREEINFO));          memset(&info, 0, sizeof(BTREEINFO));
         info.flags = R_DUP;          info.flags = R_DUP;
   
         db = dbopen("mandoc.db", O_RDONLY, 0, DB_BTREE, &info);          db = dbopen(MANDOC_DB, O_RDONLY, 0, DB_BTREE, &info);
         if (NULL != db)          if (NULL != db)
                 return(db);                  return(db);
   
Line 107  btree_read(const DBT *v, const struct mchars *mc, char
Line 156  btree_read(const DBT *v, const struct mchars *mc, char
         /* Sanity: are we nil-terminated? */          /* Sanity: are we nil-terminated? */
   
         assert(v->size > 0);          assert(v->size > 0);
   
         if ('\0' != ((char *)v->data)[(int)v->size - 1])          if ('\0' != ((char *)v->data)[(int)v->size - 1])
                 return(0);                  return(0);
   
Line 274  index_open(void)
Line 324  index_open(void)
 {  {
         DB              *db;          DB              *db;
   
         db = dbopen("mandoc.index", O_RDONLY, 0, DB_RECNO, NULL);          db = dbopen(MANDOC_IDX, O_RDONLY, 0, DB_RECNO, NULL);
         if (NULL != db)          if (NULL != db)
                 return(db);                  return(db);
   
Line 304  index_read(const DBT *key, const DBT *val, 
Line 354  index_read(const DBT *key, const DBT *val, 
         left = val->size;          left = val->size;
         cp = (char *)val->data;          cp = (char *)val->data;
   
         rec->rec = *(recno_t *)key->data;          rec->res.rec = *(recno_t *)key->data;
   
         INDEX_BREAD(rec->file);          INDEX_BREAD(rec->res.file);
         INDEX_BREAD(rec->cat);          INDEX_BREAD(rec->res.cat);
         INDEX_BREAD(rec->title);          INDEX_BREAD(rec->res.title);
         INDEX_BREAD(rec->arch);          INDEX_BREAD(rec->res.arch);
         INDEX_BREAD(rec->desc);          INDEX_BREAD(rec->res.desc);
         return(1);          return(1);
 }  }
   
Line 318  index_read(const DBT *key, const DBT *val, 
Line 368  index_read(const DBT *key, const DBT *val, 
  * Search the mandocdb database for the expression "expr".   * Search the mandocdb database for the expression "expr".
  * Filter out by "opts".   * Filter out by "opts".
  * Call "res" with the results, which may be zero.   * Call "res" with the results, which may be zero.
    * Return 0 if there was a database error, else return 1.
  */   */
 void  int
 apropos_search(const struct opts *opts, const struct expr *expr,  apropos_search(const struct opts *opts, const struct expr *expr,
                 void *arg, void (*res)(struct rec *, size_t, void *))                  size_t terms, void *arg,
                   void (*res)(struct res *, size_t, void *))
 {  {
         int              i, len, root, leaf;          int              i, rsz, root, leaf, mlen, rc, ch;
           uint64_t         mask;
         DBT              key, val;          DBT              key, val;
         DB              *btree, *idx;          DB              *btree, *idx;
         struct mchars   *mc;          struct mchars   *mc;
         int              ch;  
         char            *buf;          char            *buf;
         recno_t          rec;          recno_t          rec;
         struct rec      *recs;          struct rec      *rs;
         struct rec       srec;          struct res      *ress;
           struct rec       r;
           struct db_val   *vbuf;
   
           rc      = 0;
         root    = -1;          root    = -1;
         leaf    = -1;          leaf    = -1;
         btree   = NULL;          btree   = NULL;
         idx     = NULL;          idx     = NULL;
         mc      = NULL;          mc      = NULL;
         buf     = NULL;          buf     = NULL;
         recs    = NULL;          rs      = NULL;
         len     = 0;          rsz     = 0;
   
         memset(&srec, 0, sizeof(struct rec));          memset(&r, 0, sizeof(struct rec));
   
         /* XXX: error out with bad regexp? */  
   
         mc = mchars_alloc();          mc = mchars_alloc();
   
         /* XXX: return fact that we've errored? */  
   
         if (NULL == (btree = btree_open()))          if (NULL == (btree = btree_open()))
                 goto out;                  goto out;
         if (NULL == (idx = index_open()))          if (NULL == (idx = index_open()))
                 goto out;                  goto out;
   
         while (0 == (ch = (*btree->seq)(btree, &key, &val, R_NEXT))) {          while (0 == (ch = (*btree->seq)(btree, &key, &val, R_NEXT))) {
                 /*                  if (key.size < 2 || sizeof(struct db_val) != val.size)
                  * Low-water mark for key and value.                          break;
                  * The key must have something in it, and the value must  
                  * have the correct tags/recno mix.  
                  */  
                 if (key.size < 2 || 8 != val.size)  
                         break;  
                 if ( ! btree_read(&key, mc, &buf))                  if ( ! btree_read(&key, mc, &buf))
                         break;                          break;
   
                 if ( ! exprexec(expr, buf))                  vbuf = val.data;
                   rec = vbuf->rec;
                   mask = vbuf->mask;
   
                   /*
                    * See if this keyword record matches any of the
                    * expressions we have stored.
                    */
                   if ( ! exprmark(expr, buf, mask, NULL))
                         continue;                          continue;
   
                 memcpy(&rec, val.data + 4, sizeof(recno_t));  
   
                 /*                  /*
                  * O(log n) scan for prior records.  Since a record                   * O(log n) scan for prior records.  Since a record
                  * number is unbounded, this has decent performance over                   * number is unbounded, this has decent performance over
Line 378  apropos_search(const struct opts *opts, const struct e
Line 430  apropos_search(const struct opts *opts, const struct e
                  */                   */
   
                 for (leaf = root; leaf >= 0; )                  for (leaf = root; leaf >= 0; )
                         if (rec > recs[leaf].rec && recs[leaf].rhs >= 0)                          if (rec > rs[leaf].res.rec &&
                                 leaf = recs[leaf].rhs;                                          rs[leaf].rhs >= 0)
                         else if (rec < recs[leaf].rec && recs[leaf].lhs >= 0)                                  leaf = rs[leaf].rhs;
                                 leaf = recs[leaf].lhs;                          else if (rec < rs[leaf].res.rec &&
                                           rs[leaf].lhs >= 0)
                                   leaf = rs[leaf].lhs;
                         else                          else
                                 break;                                  break;
   
                 if (leaf >= 0 && recs[leaf].rec == rec)                  /*
                    * If we find a record, see if it has already evaluated
                    * to true.  If it has, great, just keep going.  If not,
                    * try to evaluate it now and continue anyway.
                    */
   
                   if (leaf >= 0 && rs[leaf].res.rec == rec) {
                           if (0 == rs[leaf].matched)
                                   exprexec(expr, buf, mask, &rs[leaf]);
                         continue;                          continue;
                   }
   
                 /*                  /*
                  * Now we actually extract the manpage's metadata from                   * We have a new file to examine.
                  * the index database.                   * Extract the manpage's metadata from the index
                    * database, then begin partial evaluation.
                  */                   */
   
                 key.data = &rec;                  key.data = &rec;
Line 399  apropos_search(const struct opts *opts, const struct e
Line 463  apropos_search(const struct opts *opts, const struct e
                 if (0 != (*idx->get)(idx, &key, &val, 0))                  if (0 != (*idx->get)(idx, &key, &val, 0))
                         break;                          break;
   
                 srec.lhs = srec.rhs = -1;                  r.lhs = r.rhs = -1;
                 if ( ! index_read(&key, &val, mc, &srec))                  if ( ! index_read(&key, &val, mc, &r))
                         break;                          break;
   
                 if (opts->cat && strcasecmp(opts->cat, srec.cat))                  /* XXX: this should be elsewhere, I guess? */
   
                   if (opts->cat && strcasecmp(opts->cat, r.res.cat))
                         continue;                          continue;
                 if (opts->arch && strcasecmp(opts->arch, srec.arch))                  if (opts->arch && strcasecmp(opts->arch, r.res.arch))
                         continue;                          continue;
   
                 recs = mandoc_realloc                  rs = mandoc_realloc
                         (recs, (len + 1) * sizeof(struct rec));                          (rs, (rsz + 1) * sizeof(struct rec));
   
                 memcpy(&recs[len], &srec, sizeof(struct rec));                  memcpy(&rs[rsz], &r, sizeof(struct rec));
                   rs[rsz].matches = mandoc_calloc(terms, sizeof(int));
   
                   exprexec(expr, buf, mask, &rs[rsz]);
                 /* Append to our tree. */                  /* Append to our tree. */
   
                 if (leaf >= 0) {                  if (leaf >= 0) {
                         if (rec > recs[leaf].rec)                          if (rec > rs[leaf].res.rec)
                                 recs[leaf].rhs = len;                                  rs[leaf].rhs = rsz;
                         else                          else
                                 recs[leaf].lhs = len;                                  rs[leaf].lhs = rsz;
                 } else                  } else
                         root = len;                          root = rsz;
   
                 memset(&srec, 0, sizeof(struct rec));                  memset(&r, 0, sizeof(struct rec));
                 len++;                  rsz++;
         }          }
   
           /*
            * If we haven't encountered any database errors, then construct
            * an array of results and push them to the caller.
            */
   
         if (1 == ch)          if (1 == ch) {
                 (*res)(recs, len, arg);                  for (mlen = i = 0; i < rsz; i++)
                           if (rs[i].matched)
                                   mlen++;
                   ress = mandoc_malloc(mlen * sizeof(struct res));
                   for (mlen = i = 0; i < rsz; i++)
                           if (rs[i].matched)
                                   memcpy(&ress[mlen++], &rs[i].res,
                                                   sizeof(struct res));
                   (*res)(ress, mlen, arg);
                   free(ress);
                   rc = 1;
           }
   
         /* XXX: else?  corrupt database error? */  
 out:  out:
         for (i = 0; i < len; i++) {          for (i = 0; i < rsz; i++)
                 free(recs[i].file);                  recfree(&rs[i]);
                 free(recs[i].cat);  
                 free(recs[i].title);  
                 free(recs[i].arch);  
                 free(recs[i].desc);  
         }  
   
         free(srec.file);          recfree(&r);
         free(srec.cat);  
         free(srec.title);  
         free(srec.arch);  
         free(srec.desc);  
   
         if (mc)          if (mc)
                 mchars_free(mc);                  mchars_free(mc);
Line 454  out:
Line 528  out:
                 (*idx->close)(idx);                  (*idx->close)(idx);
   
         free(buf);          free(buf);
         free(recs);          free(rs);
           return(rc);
 }  }
   
   static void
   recfree(struct rec *rec)
   {
   
           free(rec->res.file);
           free(rec->res.cat);
           free(rec->res.title);
           free(rec->res.arch);
           free(rec->res.desc);
   
           free(rec->matches);
   }
   
 struct expr *  struct expr *
 exprcomp(int cs, char *argv[], int argc)  exprcomp(int argc, char *argv[], size_t *tt)
 {  {
         struct expr     *p;          int              pos, lvl;
         struct expr      e;          struct expr     *e;
         int              i, pos, ch;  
   
         pos = 0;          pos = lvl = 0;
           *tt = 0;
   
         if (pos > argc)          e = exprexpr(argc, argv, &pos, &lvl, tt);
                 return(NULL);  
   
         for (i = 0; 0 != types[i].mask; i++)          if (0 == lvl && pos >= argc)
                 if (0 == strcmp(types[i].name, argv[pos]))                  return(e);
   
           exprfree(e);
           return(NULL);
   }
   
   /*
    * Compile an array of tokens into an expression.
    * An informal expression grammar is defined in apropos(1).
    * Return NULL if we fail doing so.  All memory will be cleaned up.
    * Return the root of the expression sequence if alright.
    */
   static struct expr *
   exprexpr(int argc, char *argv[], int *pos, int *lvl, size_t *tt)
   {
           struct expr     *e, *first, *next;
           int              log;
   
           first = next = NULL;
   
           for ( ; *pos < argc; (*pos)++) {
                   e = next;
   
                   /*
                    * Close out a subexpression.
                    */
   
                   if (NULL != e && 0 == strcmp(")", argv[*pos])) {
                           if (--(*lvl) < 0)
                                   goto err;
                         break;                          break;
                   }
   
         if (0 == (e.mask = types[i].mask))                  /*
                 return(NULL);                   * Small note: if we're just starting, don't let "-a"
                    * and "-o" be considered logical operators: they're
                    * just tokens unless pairwise joining, in which case we
                    * record their existence (or assume "OR").
                    */
                   log = 0;
   
         if (++pos > argc--)                  if (NULL != e && 0 == strcmp("-a", argv[*pos]))
                 return(NULL);                          log = 1;
                   else if (NULL != e && 0 == strcmp("-o", argv[*pos]))
                           log = 2;
   
         if ('-' != *argv[pos])                  if (log > 0 && ++(*pos) >= argc)
                 e.match = cs ? MATCH_STRCASE : MATCH_STR;                          goto err;
         else if (0 == strcmp("-eq", argv[pos]))  
                 e.match = cs ? MATCH_STRCASE : MATCH_STR;  
         else if (0 == strcmp("-ieq", argv[pos]))  
                 e.match = MATCH_STRCASE;  
         else if (0 == strcmp("-re", argv[pos]))  
                 e.match = cs ? MATCH_REGEXCASE : MATCH_REGEX;  
         else if (0 == strcmp("-ire", argv[pos]))  
                 e.match = MATCH_REGEXCASE;  
         else  
                 return(NULL);  
   
         if ('-' == *argv[pos])                  /*
                 pos++;                   * Now we parse the term part.  This can begin with
                    * "-i", in which case the expression is case
                    * insensitive.
                    */
   
         if (pos > argc--)                  if (0 == strcmp("(", argv[*pos])) {
                 return(NULL);                          ++(*pos);
                           ++(*lvl);
                           next = mandoc_calloc(1, sizeof(struct expr));
                           next->cs = 1;
                           next->subexpr = exprexpr(argc, argv, pos, lvl, tt);
                           if (NULL == next->subexpr) {
                                   free(next);
                                   next = NULL;
                           }
                   } else if (0 == strcmp("-i", argv[*pos])) {
                           if (++(*pos) >= argc)
                                   goto err;
                           next = exprterm(argv[*pos], 0);
                   } else
                           next = exprterm(argv[*pos], 1);
   
         e.v = mandoc_strdup(argv[pos]);                  if (NULL == next)
                           goto err;
   
         if (MATCH_REGEX == e.match || MATCH_REGEXCASE == e.match) {                  next->and = log == 1;
                 ch = REG_EXTENDED | REG_NOSUB;                  next->index = (int)(*tt)++;
                 if (MATCH_REGEXCASE == e.match)  
                         ch |= REG_ICASE;                  /* Append to our chain of expressions. */
                 if (regcomp(&e.re, e.v, ch))  
                   if (NULL == first) {
                           assert(NULL == e);
                           first = next;
                   } else {
                           assert(NULL != e);
                           e->next = next;
                   }
           }
   
           return(first);
   err:
           exprfree(first);
           return(NULL);
   }
   
   /*
    * Parse a terminal expression with the grammar as defined in
    * apropos(1).
    * Return NULL if we fail the parse.
    */
   static struct expr *
   exprterm(char *buf, int cs)
   {
           struct expr      e;
           struct expr     *p;
           char            *key;
           int              i;
   
           memset(&e, 0, sizeof(struct expr));
   
           e.cs = cs;
   
           /* Choose regex or substring match. */
   
           if (NULL == (e.v = strpbrk(buf, "=~"))) {
                   e.regex = 0;
                   e.v = buf;
           } else {
                   e.regex = '~' == *e.v;
                   *e.v++ = '\0';
           }
   
           /* Determine the record types to search for. */
   
           e.mask = 0;
           if (buf < e.v) {
                   while (NULL != (key = strsep(&buf, ","))) {
                           i = 0;
                           while (types[i].mask &&
                                           strcmp(types[i].name, key))
                                   i++;
                           e.mask |= types[i].mask;
                   }
           }
           if (0 == e.mask)
                   e.mask = TYPE_Nm | TYPE_Nd;
   
           if (e.regex) {
                   i = REG_EXTENDED | REG_NOSUB | cs ? 0 : REG_ICASE;
                   if (regcomp(&e.re, e.v, i))
                         return(NULL);                          return(NULL);
         }          }
   
           e.v = mandoc_strdup(e.v);
   
         p = mandoc_calloc(1, sizeof(struct expr));          p = mandoc_calloc(1, sizeof(struct expr));
         memcpy(p, &e, sizeof(struct expr));          memcpy(p, &e, sizeof(struct expr));
         return(p);          return(p);
Line 516  exprcomp(int cs, char *argv[], int argc)
Line 710  exprcomp(int cs, char *argv[], int argc)
 void  void
 exprfree(struct expr *p)  exprfree(struct expr *p)
 {  {
           struct expr     *pp;
   
           while (NULL != p) {
                   if (p->subexpr)
                           exprfree(p->subexpr);
                   if (p->regex)
                           regfree(&p->re);
                   free(p->v);
                   pp = p->next;
                   free(p);
                   p = pp;
           }
   }
   
         if (NULL == p)  static int
                 return;  exprmark(const struct expr *p, const char *cp,
                   uint64_t mask, int *ms)
   {
   
         if (MATCH_REGEX == p->match)          for ( ; p; p = p->next) {
                 regfree(&p->re);                  if (p->subexpr) {
                           if (exprmark(p->subexpr, cp, mask, ms))
                                   return(1);
                           continue;
                   } else if ( ! (mask & p->mask))
                           continue;
   
         free(p->v);                  if (p->regex) {
         free(p);                          if (regexec(&p->re, cp, 0, NULL, 0))
                                   continue;
                   } else if (p->cs) {
                           if (NULL == strstr(cp, p->v))
                                   continue;
                   } else {
                           if (NULL == strcasestr(cp, p->v))
                                   continue;
                   }
   
                   if (NULL == ms)
                           return(1);
                   else
                           ms[p->index] = 1;
           }
   
           return(0);
 }  }
   
 static int  static int
 exprexec(const struct expr *p, char *cp)  expreval(const struct expr *p, int *ms)
 {  {
           int              match;
   
         if (MATCH_STR == p->match)          /*
                 return(0 == strcmp(p->v, cp));           * AND has precedence over OR.  Analysis is left-right, though
         else if (MATCH_STRCASE == p->match)           * it doesn't matter because there are no side-effects.
                 return(0 == strcasecmp(p->v, cp));           * Thus, step through pairwise ANDs and accumulate their Boolean
            * evaluation.  If we encounter a single true AND collection or
            * standalone term, the whole expression is true (by definition
            * of OR).
            */
   
         assert(MATCH_REGEX == p->match);          for (match = 0; p && ! match; p = p->next) {
         return(0 == regexec(&p->re, cp, 0, NULL, 0));                  /* Evaluate a subexpression, if applicable. */
                   if (p->subexpr && ! ms[p->index])
                           ms[p->index] = expreval(p->subexpr, ms);
   
                   match = ms[p->index];
                   for ( ; p->next && p->next->and; p = p->next) {
                           /* Evaluate a subexpression, if applicable. */
                           if (p->next->subexpr && ! ms[p->next->index])
                                   ms[p->next->index] =
                                           expreval(p->next->subexpr, ms);
                           match = match && ms[p->next->index];
                   }
           }
   
           return(match);
   }
   
   /*
    * First, update the array of terms for which this expression evaluates
    * to true.
    * Second, logically evaluate all terms over the updated array of truth
    * values.
    * If this evaluates to true, mark the expression as satisfied.
    */
   static void
   exprexec(const struct expr *p, const char *cp,
                   uint64_t mask, struct rec *r)
   {
   
           assert(0 == r->matched);
           exprmark(p, cp, mask, r->matches);
           r->matched = expreval(p, r->matches);
 }  }

Legend:
Removed from v.1.1  
changed lines
  Added in v.1.7

CVSweb