[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.25 and 1.32.2.8

version 1.25, 2011/12/16 12:07:45 version 1.32.2.8, 2014/08/14 04:13:30
Line 1 
Line 1 
 /*      $Id$ */  /*      $Id$ */
 /*  /*
  * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>   * Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>   * Copyright (c) 2011, 2014 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 15 
Line 15 
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF   * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */   */
 #ifdef HAVE_CONFIG_H  
 #include "config.h"  #include "config.h"
 #endif  
   
   #include <sys/param.h>
   #include <sys/types.h>
   
 #include <assert.h>  #include <assert.h>
 #include <fcntl.h>  #include <fcntl.h>
 #include <regex.h>  #include <regex.h>
Line 28 
Line 29 
 #include <string.h>  #include <string.h>
 #include <unistd.h>  #include <unistd.h>
   
 #if defined(__linux__)  #if defined(__APPLE__)
   # include <libkern/OSByteOrder.h>
   #elif defined(__linux__) || defined(__CYGWIN__)
 # include <endian.h>  # include <endian.h>
   #elif defined(__sun)
   # include <sys/byteorder.h>
   #else
   # include <sys/endian.h>
   #endif
   
   #if defined(__linux__) || defined(__CYGWIN__) || defined(__sun)
 # include <db_185.h>  # include <db_185.h>
 #elif defined(__APPLE__)  
 # include <libkern/OSByteOrder.h>  
 # include <db.h>  
 #else  #else
 # include <db.h>  # include <db.h>
 #endif  #endif
Line 41 
Line 48 
 #include "mandocdb.h"  #include "mandocdb.h"
 #include "apropos_db.h"  #include "apropos_db.h"
 #include "mandoc.h"  #include "mandoc.h"
   #include "mandoc_aux.h"
   
 struct  rec {  #define RESFREE(_x) \
         struct res       res; /* resulting record info */          do { \
         /*                  free((_x)->file); \
          * Maintain a binary tree for checking the uniqueness of `rec'                  free((_x)->cat); \
          * when adding elements to the results array.                  free((_x)->title); \
          * Since the results array is dynamic, use offset in the array                  free((_x)->arch); \
          * instead of a pointer to the structure.                  free((_x)->desc); \
          */                  free((_x)->matches); \
         int              lhs;          } while (/*CONSTCOND*/0)
         int              rhs;  
         int              matched; /* expression is true */  
         int             *matches; /* partial truth evaluations */  
 };  
   
 struct  expr {  struct  expr {
         int              regex; /* is regex? */          int              regex; /* is regex? */
Line 73  struct type {
Line 77  struct type {
 };  };
   
 struct  rectree {  struct  rectree {
         struct rec      *node; /* record array for dir tree */          struct res      *node; /* record array for dir tree */
         int              len; /* length of record array */          int              len; /* length of record array */
 };  };
   
Line 123  static const struct type types[] = {
Line 127  static const struct type types[] = {
   
 static  DB      *btree_open(void);  static  DB      *btree_open(void);
 static  int      btree_read(const DBT *, const DBT *,  static  int      btree_read(const DBT *, const DBT *,
                         const struct mchars *,                          const struct mchars *,
                         struct db_val *, char **);                          uint64_t *, recno_t *, char **);
 static  int      expreval(const struct expr *, int *);  static  int      expreval(const struct expr *, int *);
 static  void     exprexec(const struct expr *,  static  void     exprexec(const struct expr *,
                         const char *, uint64_t, struct rec *);                          const char *, uint64_t, struct res *);
 static  int      exprmark(const struct expr *,  static  int      exprmark(const struct expr *,
                         const char *, uint64_t, int *);                          const char *, uint64_t, int *);
 static  struct expr *exprexpr(int, char *[], int *, int *, size_t *);  static  struct expr *exprexpr(int, char *[], int *, int *, size_t *);
 static  struct expr *exprterm(char *, int);  static  struct expr *exprterm(char *, int);
 static  DB      *index_open(void);  static  DB      *index_open(void);
 static  int      index_read(const DBT *, const DBT *, int,  static  int      index_read(const DBT *, const DBT *, int,
                         const struct mchars *, struct rec *);                          const struct mchars *, struct res *);
 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 *);  
 static  int      single_search(struct rectree *, const struct opts *,  static  int      single_search(struct rectree *, const struct opts *,
                         const struct expr *, size_t terms,                          const struct expr *, size_t terms,
                         struct mchars *, int);                          struct mchars *, int);
Line 153  btree_open(void)
Line 156  btree_open(void)
         DB              *db;          DB              *db;
   
         memset(&info, 0, sizeof(BTREEINFO));          memset(&info, 0, sizeof(BTREEINFO));
           info.lorder = 4321;
         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);
Line 167  btree_open(void)
Line 171  btree_open(void)
  * Return 0 if the database is insane, else 1.   * Return 0 if the database is insane, else 1.
  */   */
 static int  static int
 btree_read(const DBT *k, const DBT *v,  btree_read(const DBT *k, const DBT *v, const struct mchars *mc,
                 const struct mchars *mc,                  uint64_t *mask, recno_t *rec, char **buf)
                 struct db_val *dbv, char **buf)  
 {  {
         const struct db_val *vp;          uint64_t         vbuf[2];
   
         /* Are our sizes sane? */          /* Are our sizes sane? */
         if (k->size < 2 || sizeof(struct db_val) != v->size)          if (k->size < 2 || sizeof(vbuf) != v->size)
                 return(0);                  return(0);
   
         /* Is our string nil-terminated? */          /* Is our string nil-terminated? */
         if ('\0' != ((const char *)k->data)[(int)k->size - 1])          if ('\0' != ((const char *)k->data)[(int)k->size - 1])
                 return(0);                  return(0);
   
         vp = v->data;  
         norm_string((const char *)k->data, mc, buf);          norm_string((const char *)k->data, mc, buf);
         dbv->rec = betoh32(vp->rec);          memcpy(vbuf, v->data, v->size);
         dbv->mask = betoh64(vp->mask);          *mask = betoh64(vbuf[0]);
           *rec  = betoh64(vbuf[1]);
         return(1);          return(1);
 }  }
   
Line 197  btree_read(const DBT *k, const DBT *v, 
Line 200  btree_read(const DBT *k, const DBT *v, 
 static size_t  static size_t
 norm_utf8(unsigned int cp, char out[7])  norm_utf8(unsigned int cp, char out[7])
 {  {
         size_t           rc;          int              rc;
   
         rc = 0;          rc = 0;
   
Line 238  norm_utf8(unsigned int cp, char out[7])
Line 241  norm_utf8(unsigned int cp, char out[7])
                 return(0);                  return(0);
   
         out[rc] = '\0';          out[rc] = '\0';
         return(rc);          return((size_t)rc);
 }  }
   
 /*  /*
Line 256  norm_string(const char *val, const struct mchars *mc, 
Line 259  norm_string(const char *val, const struct mchars *mc, 
         const char       *seq, *cpp;          const char       *seq, *cpp;
         int               len, u, pos;          int               len, u, pos;
         enum mandoc_esc   esc;          enum mandoc_esc   esc;
         static const char res[] = { '\\', '\t',          static const char res[] = { '\\', '\t', ASCII_NBRSP,
                                 ASCII_NBRSP, ASCII_HYPH, '\0' };                          ASCII_HYPH, ASCII_BREAK, '\0' };
   
         /* Pre-allocate by the length of the input */          /* Pre-allocate by the length of the input */
   
Line 277  norm_string(const char *val, const struct mchars *mc, 
Line 280  norm_string(const char *val, const struct mchars *mc, 
                         val += (int)sz;                          val += (int)sz;
                 }                  }
   
                 if (ASCII_HYPH == *val) {                  switch (*val) {
                   case (ASCII_HYPH):
                         (*buf)[pos++] = '-';                          (*buf)[pos++] = '-';
                         val++;                          val++;
                         continue;                          continue;
                 } else if ('\t' == *val || ASCII_NBRSP == *val) {                  case ('\t'):
                           /* FALLTHROUGH */
                   case (ASCII_NBRSP):
                         (*buf)[pos++] = ' ';                          (*buf)[pos++] = ' ';
                         val++;                          val++;
                           /* FALLTHROUGH */
                   case (ASCII_BREAK):
                         continue;                          continue;
                 } else if ('\\' != *val)                  default:
                         break;                          break;
                   }
                   if ('\\' != *val)
                           break;
   
                 /* Read past the slash. */                  /* Read past the slash. */
   
Line 361  index_open(void)
Line 372  index_open(void)
  */   */
 static int  static int
 index_read(const DBT *key, const DBT *val, int index,  index_read(const DBT *key, const DBT *val, int index,
                 const struct mchars *mc, struct rec *rec)                  const struct mchars *mc, struct res *rec)
 {  {
         size_t           left;          size_t           left;
         char            *np, *cp;          char            *np, *cp;
Line 380  index_read(const DBT *key, const DBT *val, int index,
Line 391  index_read(const DBT *key, const DBT *val, int index,
                 return(0);                  return(0);
   
         cp = val->data;          cp = val->data;
         rec->res.rec = *(recno_t *)key->data;          assert(sizeof(recno_t) == key->size);
         rec->res.volume = index;          memcpy(&rec->rec, key->data, key->size);
           rec->volume = index;
   
         if ('d' == (type = *cp++))          if ('d' == (type = *cp++))
                 rec->res.type = RESTYPE_MDOC;                  rec->type = RESTYPE_MDOC;
         else if ('a' == type)          else if ('a' == type)
                 rec->res.type = RESTYPE_MAN;                  rec->type = RESTYPE_MAN;
         else if ('c' == type)          else if ('c' == type)
                 rec->res.type = RESTYPE_CAT;                  rec->type = RESTYPE_CAT;
         else          else
                 return(0);                  return(0);
   
         left--;          left--;
         INDEX_BREAD(rec->res.file);          INDEX_BREAD(rec->file);
         INDEX_BREAD(rec->res.cat);          INDEX_BREAD(rec->cat);
         INDEX_BREAD(rec->res.title);          INDEX_BREAD(rec->title);
         INDEX_BREAD(rec->res.arch);          INDEX_BREAD(rec->arch);
         INDEX_BREAD(rec->res.desc);          INDEX_BREAD(rec->desc);
         return(1);          return(1);
 }  }
   
Line 410  index_read(const DBT *key, const DBT *val, int index,
Line 422  index_read(const DBT *key, const DBT *val, int index,
 int  int
 apropos_search(int pathsz, char **paths, const struct opts *opts,  apropos_search(int pathsz, char **paths, const struct opts *opts,
                 const struct expr *expr, size_t terms, void *arg,                  const struct expr *expr, size_t terms, void *arg,
                   size_t *sz, struct res **resp,
                 void (*res)(struct res *, size_t, void *))                  void (*res)(struct res *, size_t, void *))
 {  {
         struct rectree   tree;          struct rectree   tree;
         struct mchars   *mc;          struct mchars   *mc;
         struct res      *ress;          int              i;
         int              i, mlen, rc;  
   
         memset(&tree, 0, sizeof(struct rectree));          memset(&tree, 0, sizeof(struct rectree));
   
         rc = 0;  
         mc = mchars_alloc();          mc = mchars_alloc();
           *sz = 0;
           *resp = NULL;
   
         /*          /*
          * Main loop.  Change into the directory containing manpage           * Main loop.  Change into the directory containing manpage
Line 428  apropos_search(int pathsz, char **paths, const struct 
Line 441  apropos_search(int pathsz, char **paths, const struct 
          */           */
   
         for (i = 0; i < pathsz; i++) {          for (i = 0; i < pathsz; i++) {
                   assert('/' == paths[i][0]);
                 if (chdir(paths[i]))                  if (chdir(paths[i]))
                         continue;                          continue;
                 if ( ! single_search(&tree, opts, expr, terms, mc, i))                  if (single_search(&tree, opts, expr, terms, mc, i))
                         goto out;                          continue;
   
                   resfree(tree.node, tree.len);
                   mchars_free(mc);
                   return(0);
         }          }
   
         /*          (*res)(tree.node, tree.len, arg);
          * Count matching files, transfer to a "clean" array, then feed          *sz = tree.len;
          * them to the output handler.          *resp = tree.node;
          */  
   
         for (mlen = i = 0; i < tree.len; i++)  
                 if (tree.node[i].matched)  
                         mlen++;  
   
         ress = mandoc_malloc(mlen * sizeof(struct res));  
   
         for (mlen = i = 0; i < tree.len; i++)  
                 if (tree.node[i].matched)  
                         memcpy(&ress[mlen++], &tree.node[i].res,  
                                         sizeof(struct res));  
   
         (*res)(ress, mlen, arg);  
         free(ress);  
   
         rc = 1;  
 out:  
         for (i = 0; i < tree.len; i++)  
                 recfree(&tree.node[i]);  
   
         free(tree.node);  
         mchars_free(mc);          mchars_free(mc);
         return(rc);          return(1);
 }  }
   
 static int  static int
Line 472  single_search(struct rectree *tree, const struct opts 
Line 468  single_search(struct rectree *tree, const struct opts 
         DBT              key, val;          DBT              key, val;
         DB              *btree, *idx;          DB              *btree, *idx;
         char            *buf;          char            *buf;
         struct rec      *rs;          struct res      *rs;
         struct rec       r;          struct res       r;
         struct db_val    vb;          uint64_t         mask;
           recno_t          rec;
   
         root    = -1;          root    = -1;
         leaf    = -1;          leaf    = -1;
Line 483  single_search(struct rectree *tree, const struct opts 
Line 480  single_search(struct rectree *tree, const struct opts 
         buf     = NULL;          buf     = NULL;
         rs      = tree->node;          rs      = tree->node;
   
         memset(&r, 0, sizeof(struct rec));          memset(&r, 0, sizeof(struct res));
   
         if (NULL == (btree = btree_open()))          if (NULL == (btree = btree_open()))
                 return(1);                  return(1);
Line 494  single_search(struct rectree *tree, const struct opts 
Line 491  single_search(struct rectree *tree, const struct opts 
         }          }
   
         while (0 == (ch = (*btree->seq)(btree, &key, &val, R_NEXT))) {          while (0 == (ch = (*btree->seq)(btree, &key, &val, R_NEXT))) {
                 if ( ! btree_read(&key, &val, mc, &vb, &buf))                  if ( ! btree_read(&key, &val, mc, &mask, &rec, &buf))
                         break;                          break;
   
                 /*                  /*
                  * See if this keyword record matches any of the                   * See if this keyword record matches any of the
                  * expressions we have stored.                   * expressions we have stored.
                  */                   */
                 if ( ! exprmark(expr, buf, vb.mask, NULL))                  if ( ! exprmark(expr, buf, mask, NULL))
                         continue;                          continue;
   
                 /*                  /*
Line 511  single_search(struct rectree *tree, const struct opts 
Line 508  single_search(struct rectree *tree, const struct opts 
                  */                   */
   
                 for (leaf = root; leaf >= 0; )                  for (leaf = root; leaf >= 0; )
                         if (vb.rec > rs[leaf].res.rec &&                          if (rec > rs[leaf].rec &&
                                         rs[leaf].rhs >= 0)                                          rs[leaf].rhs >= 0)
                                 leaf = rs[leaf].rhs;                                  leaf = rs[leaf].rhs;
                         else if (vb.rec < rs[leaf].res.rec &&                          else if (rec < rs[leaf].rec &&
                                         rs[leaf].lhs >= 0)                                          rs[leaf].lhs >= 0)
                                 leaf = rs[leaf].lhs;                                  leaf = rs[leaf].lhs;
                         else                          else
Line 526  single_search(struct rectree *tree, const struct opts 
Line 523  single_search(struct rectree *tree, const struct opts 
                  * try to evaluate it now and continue anyway.                   * try to evaluate it now and continue anyway.
                  */                   */
   
                 if (leaf >= 0 && rs[leaf].res.rec == vb.rec) {                  if (leaf >= 0 && rs[leaf].rec == rec) {
                         if (0 == rs[leaf].matched)                          if (0 == rs[leaf].matched)
                                 exprexec(expr, buf, vb.mask, &rs[leaf]);                                  exprexec(expr, buf, mask, &rs[leaf]);
                         continue;                          continue;
                 }                  }
   
Line 538  single_search(struct rectree *tree, const struct opts 
Line 535  single_search(struct rectree *tree, const struct opts 
                  * database, then begin partial evaluation.                   * database, then begin partial evaluation.
                  */                   */
   
                 key.data = &vb.rec;                  key.data = &rec;
                 key.size = sizeof(recno_t);                  key.size = sizeof(recno_t);
   
                 if (0 != (*idx->get)(idx, &key, &val, 0))                  if (0 != (*idx->get)(idx, &key, &val, 0))
Line 550  single_search(struct rectree *tree, const struct opts 
Line 547  single_search(struct rectree *tree, const struct opts 
   
                 /* XXX: this should be elsewhere, I guess? */                  /* XXX: this should be elsewhere, I guess? */
   
                 if (opts->cat && strcasecmp(opts->cat, r.res.cat))                  if (opts->cat && strcasecmp(opts->cat, r.cat))
                         continue;                          continue;
   
                 if (opts->arch && *r.res.arch)                  if (opts->arch && *r.arch)
                         if (strcasecmp(opts->arch, r.res.arch))                          if (strcasecmp(opts->arch, r.arch))
                                 continue;                                  continue;
   
                 tree->node = rs = mandoc_realloc                  tree->node = rs = mandoc_reallocarray(rs,
                         (rs, (tree->len + 1) * sizeof(struct rec));                      tree->len + 1, sizeof(struct res));
   
                 memcpy(&rs[tree->len], &r, sizeof(struct rec));                  memcpy(&rs[tree->len], &r, sizeof(struct res));
                 memset(&r, 0, sizeof(struct rec));                  memset(&r, 0, sizeof(struct res));
                 rs[tree->len].matches =                  rs[tree->len].matches =
                         mandoc_calloc(terms, sizeof(int));                          mandoc_calloc(terms, sizeof(int));
   
                 exprexec(expr, buf, vb.mask, &rs[tree->len]);                  exprexec(expr, buf, mask, &rs[tree->len]);
   
                 /* Append to our tree. */                  /* Append to our tree. */
   
                 if (leaf >= 0) {                  if (leaf >= 0) {
                         if (vb.rec > rs[leaf].res.rec)                          if (rec > rs[leaf].rec)
                                 rs[leaf].rhs = tree->len;                                  rs[leaf].rhs = tree->len;
                         else                          else
                                 rs[leaf].lhs = tree->len;                                  rs[leaf].lhs = tree->len;
Line 584  single_search(struct rectree *tree, const struct opts 
Line 581  single_search(struct rectree *tree, const struct opts 
         (*idx->close)(idx);          (*idx->close)(idx);
   
         free(buf);          free(buf);
         recfree(&r);          RESFREE(&r);
         return(1 == ch);          return(1 == ch);
 }  }
   
 static void  void
 recfree(struct rec *rec)  resfree(struct res *rec, size_t sz)
 {  {
           size_t           i;
   
         free(rec->res.file);          for (i = 0; i < sz; i++)
         free(rec->res.cat);                  RESFREE(&rec[i]);
         free(rec->res.title);          free(rec);
         free(rec->res.arch);  
         free(rec->res.desc);  
   
         free(rec->matches);  
 }  }
   
 /*  /*
Line 889  expreval(const struct expr *p, int *ms)
Line 883  expreval(const struct expr *p, int *ms)
  */   */
 static void  static void
 exprexec(const struct expr *e, const char *cp,  exprexec(const struct expr *e, const char *cp,
                 uint64_t mask, struct rec *r)                  uint64_t mask, struct res *r)
 {  {
   
         assert(0 == r->matched);          assert(0 == r->matched);

Legend:
Removed from v.1.25  
changed lines
  Added in v.1.32.2.8

CVSweb