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

Diff for /mandoc/mandocdb.c between version 1.55 and 1.62

version 1.55, 2012/06/09 14:11:16 version 1.62, 2013/06/06 02:40:37
Line 1 
Line 1 
 /*      $Id$ */  /*      $Id$ */
 /*  /*
  * Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>   * Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2011, 2012 Ingo Schwarze <schwarze@openbsd.org>   * Copyright (c) 2011, 2012, 2013 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 19 
Line 19 
 #include "config.h"  #include "config.h"
 #endif  #endif
   
 #include <sys/param.h>  
 #include <sys/stat.h>  #include <sys/stat.h>
   
 #include <assert.h>  #include <assert.h>
 #include <ctype.h>  #include <ctype.h>
 #include <errno.h>  
 #include <fcntl.h>  #include <fcntl.h>
 #include <fts.h>  #include <fts.h>
 #include <getopt.h>  #include <getopt.h>
   #include <limits.h>
 #include <stddef.h>  #include <stddef.h>
   #include <stdio.h>
 #include <stdint.h>  #include <stdint.h>
 #include <stdlib.h>  #include <stdlib.h>
 #include <string.h>  #include <string.h>
Line 47 
Line 47 
 #include "manpath.h"  #include "manpath.h"
 #include "mansearch.h"  #include "mansearch.h"
   
 /* Post a warning to stderr. */  
 #define WARNING(_f, _b, _fmt, _args...) \  
         do if (warnings) { \  
                 fprintf(stderr, "%s: ", (_b)); \  
                 fprintf(stderr, (_fmt), ##_args); \  
                 if ('\0' != *(_f)) \  
                         fprintf(stderr, ": %s", (_f)); \  
                 fprintf(stderr, "\n"); \  
         } while (/* CONSTCOND */ 0)  
 /* Post a "verbose" message to stderr. */  
 #define DEBUG(_f, _b, _fmt, _args...) \  
         do if (verb) { \  
                 fprintf(stderr, "%s: ", (_b)); \  
                 fprintf(stderr, (_fmt), ##_args); \  
                 fprintf(stderr, ": %s\n", (_f)); \  
         } while (/* CONSTCOND */ 0)  
   
 #define SQL_EXEC(_v) \  #define SQL_EXEC(_v) \
         if (SQLITE_OK != sqlite3_exec(db, (_v), NULL, NULL, NULL)) \          if (SQLITE_OK != sqlite3_exec(db, (_v), NULL, NULL, NULL)) \
                 fprintf(stderr, "%s\n", sqlite3_errmsg(db))                  fprintf(stderr, "%s\n", sqlite3_errmsg(db))
Line 115  struct of {
Line 98  struct of {
         struct of       *next; /* next in ofs */          struct of       *next; /* next in ofs */
         enum form        dform; /* path-cued form */          enum form        dform; /* path-cued form */
         enum form        sform; /* suffix-cued form */          enum form        sform; /* suffix-cued form */
         char             file[MAXPATHLEN]; /* filename rel. to manpath */          char             file[PATH_MAX]; /* filename rel. to manpath */
         const char      *desc; /* parsed description */          const char      *desc; /* parsed description */
         const char      *sec; /* suffix-cued section (or empty) */          const char      *sec; /* suffix-cued section (or empty) */
         const char      *dsec; /* path-cued section (or empty) */          const char      *dsec; /* path-cued section (or empty) */
Line 139  struct mdoc_handler {
Line 122  struct mdoc_handler {
 #define MDOCF_CHILD      0x01  /* automatically index child nodes */  #define MDOCF_CHILD      0x01  /* automatically index child nodes */
 };  };
   
 static  void     dbclose(const char *, int);  static  void     dbclose(int);
 static  void     dbindex(struct mchars *, int,  static  void     dbindex(struct mchars *, int, const struct of *);
                         const struct of *, const char *);  static  int      dbopen(int);
 static  int      dbopen(const char *, int);  static  void     dbprune(void);
 static  void     dbprune(const char *);  
 static  void     fileadd(struct of *);  static  void     fileadd(struct of *);
 static  int      filecheck(const char *);  static  int      filecheck(const char *);
 static  void     filescan(const char *, const char *);  static  void     filescan(const char *);
 static  struct str *hashget(const char *, size_t);  static  struct str *hashget(const char *, size_t);
 static  void    *hash_alloc(size_t, void *);  static  void    *hash_alloc(size_t, void *);
 static  void     hash_free(void *, size_t, void *);  static  void     hash_free(void *, size_t, void *);
 static  void    *hash_halloc(size_t, void *);  static  void    *hash_halloc(size_t, void *);
 static  void     inoadd(const struct stat *, struct of *);  static  void     inoadd(const struct stat *, struct of *);
 static  int      inocheck(const struct stat *);  static  int      inocheck(const struct stat *);
 static  void     ofadd(const char *, int, const char *,  static  void     ofadd(int, const char *, const char *, const char *,
                         const char *, const char *, const char *,                          const char *, const char *, const struct stat *);
                         const char *, const struct stat *);  
 static  void     offree(void);  static  void     offree(void);
 static  int      ofmerge(struct mchars *, struct mparse *, const char *);  static  void     ofmerge(struct mchars *, struct mparse *);
 static  void     parse_catpage(struct of *, const char *);  static  void     parse_catpage(struct of *);
 static  int      parse_man(struct of *,  static  void     parse_man(struct of *, const struct man_node *);
                         const struct man_node *);  
 static  void     parse_mdoc(struct of *, const struct mdoc_node *);  static  void     parse_mdoc(struct of *, const struct mdoc_node *);
 static  int      parse_mdoc_body(struct of *, const struct mdoc_node *);  static  int      parse_mdoc_body(struct of *, const struct mdoc_node *);
 static  int      parse_mdoc_head(struct of *, const struct mdoc_node *);  static  int      parse_mdoc_head(struct of *, const struct mdoc_node *);
Line 172  static int  parse_mdoc_Nm(struct of *, const struct md
Line 152  static int  parse_mdoc_Nm(struct of *, const struct md
 static  int      parse_mdoc_Sh(struct of *, const struct mdoc_node *);  static  int      parse_mdoc_Sh(struct of *, const struct mdoc_node *);
 static  int      parse_mdoc_St(struct of *, const struct mdoc_node *);  static  int      parse_mdoc_St(struct of *, const struct mdoc_node *);
 static  int      parse_mdoc_Xr(struct of *, const struct mdoc_node *);  static  int      parse_mdoc_Xr(struct of *, const struct mdoc_node *);
 static  int      path_reset(const char *, int, const char *);  static  int      set_basedir(const char *);
 static  void     putkey(const struct of *,  static  void     putkey(const struct of *,
                         const char *, uint64_t);                          const char *, uint64_t);
 static  void     putkeys(const struct of *,  static  void     putkeys(const struct of *,
                         const char *, int, uint64_t);                          const char *, int, uint64_t);
 static  void     putmdockey(const struct of *,  static  void     putmdockey(const struct of *,
                         const struct mdoc_node *, uint64_t);                          const struct mdoc_node *, uint64_t);
   static  void     say(const char *, const char *, ...);
 static  char    *stradd(const char *);  static  char    *stradd(const char *);
 static  char    *straddbuf(const char *, size_t);  static  char    *straddbuf(const char *, size_t);
 static  int      treescan(const char *);  static  int      treescan(void);
 static  size_t   utf8(unsigned int, char [7]);  static  size_t   utf8(unsigned int, char [7]);
 static  void     utf8key(struct mchars *, struct str *);  static  void     utf8key(struct mchars *, struct str *);
 static  void     wordaddbuf(const struct of *,  static  void     wordaddbuf(const struct of *,
Line 192  static int    use_all; /* use all found files */
Line 173  static int    use_all; /* use all found files */
 static  int              nodb; /* no database changes */  static  int              nodb; /* no database changes */
 static  int              verb; /* print what we're doing */  static  int              verb; /* print what we're doing */
 static  int              warnings; /* warn about crap */  static  int              warnings; /* warn about crap */
   static  int              exitcode; /* to be returned by main */
 static  enum op          op; /* operational mode */  static  enum op          op; /* operational mode */
   static  char             basedir[PATH_MAX]; /* current base directory */
 static  struct ohash     inos; /* table of inodes/devices */  static  struct ohash     inos; /* table of inodes/devices */
 static  struct ohash     filenames; /* table of filenames */  static  struct ohash     filenames; /* table of filenames */
 static  struct ohash     strings; /* table of all strings */  static  struct ohash     strings; /* table of all strings */
Line 329  static const struct mdoc_handler mdocs[MDOC_MAX] = {
Line 312  static const struct mdoc_handler mdocs[MDOC_MAX] = {
 int  int
 main(int argc, char *argv[])  main(int argc, char *argv[])
 {  {
         char              cwd[MAXPATHLEN];          int               ch, i;
         int               ch, rc, fd, i;  
         unsigned int      index;          unsigned int      index;
         size_t            j, sz;          size_t            j, sz;
         const char       *dir;          const char       *path_arg;
         struct str       *s;          struct str       *s;
         struct mchars    *mc;          struct mchars    *mc;
         struct manpaths   dirs;          struct manpaths   dirs;
Line 361  main(int argc, char *argv[])
Line 343  main(int argc, char *argv[])
                 ++progname;                  ++progname;
   
         /*          /*
          * Remember where we started by keeping a fd open to the origin  
          * path component: throughout this utility, we chdir() a lot to  
          * handle relative paths, and by doing this, we can return to  
          * the starting point.  
          */  
         if (NULL == getcwd(cwd, MAXPATHLEN)) {  
                 perror(NULL);  
                 return(EXIT_FAILURE);  
         } else if (-1 == (fd = open(cwd, O_RDONLY, 0))) {  
                 perror(cwd);  
                 return(EXIT_FAILURE);  
         }  
   
         /*  
          * We accept a few different invocations.           * We accept a few different invocations.
          * The CHECKOP macro makes sure that invocation styles don't           * The CHECKOP macro makes sure that invocation styles don't
          * clobber each other.           * clobber each other.
Line 385  main(int argc, char *argv[])
Line 353  main(int argc, char *argv[])
                 goto usage; \                  goto usage; \
         } while (/*CONSTCOND*/0)          } while (/*CONSTCOND*/0)
   
         dir = NULL;          path_arg = NULL;
         op = OP_DEFAULT;          op = OP_DEFAULT;
   
         while (-1 != (ch = getopt(argc, argv, "aC:d:ntu:vW")))          while (-1 != (ch = getopt(argc, argv, "aC:d:ntu:vW")))
Line 395  main(int argc, char *argv[])
Line 363  main(int argc, char *argv[])
                         break;                          break;
                 case ('C'):                  case ('C'):
                         CHECKOP(op, ch);                          CHECKOP(op, ch);
                         dir = optarg;                          path_arg = optarg;
                         op = OP_CONFFILE;                          op = OP_CONFFILE;
                         break;                          break;
                 case ('d'):                  case ('d'):
                         CHECKOP(op, ch);                          CHECKOP(op, ch);
                         dir = optarg;                          path_arg = optarg;
                         op = OP_UPDATE;                          op = OP_UPDATE;
                         break;                          break;
                 case ('n'):                  case ('n'):
Line 414  main(int argc, char *argv[])
Line 382  main(int argc, char *argv[])
                         break;                          break;
                 case ('u'):                  case ('u'):
                         CHECKOP(op, ch);                          CHECKOP(op, ch);
                         dir = optarg;                          path_arg = optarg;
                         op = OP_DELETE;                          op = OP_DELETE;
                         break;                          break;
                 case ('v'):                  case ('v'):
Line 435  main(int argc, char *argv[])
Line 403  main(int argc, char *argv[])
                 goto usage;                  goto usage;
         }          }
   
         rc = 1;          exitcode = (int)MANDOCLEVEL_OK;
         mp = mparse_alloc(MPARSE_AUTO,          mp = mparse_alloc(MPARSE_AUTO,
                 MANDOCLEVEL_FATAL, NULL, NULL, NULL);                  MANDOCLEVEL_FATAL, NULL, NULL, NULL);
         mc = mchars_alloc();          mc = mchars_alloc();
Line 449  main(int argc, char *argv[])
Line 417  main(int argc, char *argv[])
                  * Force processing all files.                   * Force processing all files.
                  */                   */
                 use_all = 1;                  use_all = 1;
                 if (NULL == dir)  
                         dir = cwd;  
                 /*                  /*
                  * All of these deal with a specific directory.                   * All of these deal with a specific directory.
                  * Jump into that directory then collect files specified                   * Jump into that directory then collect files specified
                  * on the command-line.                   * on the command-line.
                  */                   */
                 if (0 == path_reset(cwd, fd, dir))                  if (0 == set_basedir(path_arg))
                         goto out;                          goto out;
                 for (i = 0; i < argc; i++)                  for (i = 0; i < argc; i++)
                         filescan(argv[i], dir);                          filescan(argv[i]);
                 if (0 == dbopen(dir, 1))                  if (0 == dbopen(1))
                         goto out;                          goto out;
                 if (OP_TEST != op)                  if (OP_TEST != op)
                         dbprune(dir);                          dbprune();
                 if (OP_DELETE != op)                  if (OP_DELETE != op)
                         rc = ofmerge(mc, mp, dir);                          ofmerge(mc, mp);
                 dbclose(dir, 1);                  dbclose(1);
         } else {          } else {
                 /*                  /*
                  * If we have arguments, use them as our manpaths.                   * If we have arguments, use them as our manpaths.
Line 480  main(int argc, char *argv[])
Line 447  main(int argc, char *argv[])
                         for (i = 0; i < argc; i++)                          for (i = 0; i < argc; i++)
                                 dirs.paths[i] = mandoc_strdup(argv[i]);                                  dirs.paths[i] = mandoc_strdup(argv[i]);
                 } else                  } else
                         manpath_parse(&dirs, dir, NULL, NULL);                          manpath_parse(&dirs, path_arg, NULL, NULL);
   
                 /*                  /*
                  * First scan the tree rooted at a base directory.                   * First scan the tree rooted at a base directory.
Line 495  main(int argc, char *argv[])
Line 462  main(int argc, char *argv[])
                                 dirs.paths[j][--sz] = '\0';                                  dirs.paths[j][--sz] = '\0';
                         if (0 == sz)                          if (0 == sz)
                                 continue;                                  continue;
                         if (0 == path_reset(cwd, fd, dirs.paths[j]))                          if (0 == set_basedir(dirs.paths[j]))
                                 goto out;                                  goto out;
                         if (0 == treescan(dirs.paths[j]))                          if (0 == treescan())
                                 goto out;                                  goto out;
                         if (0 == path_reset(cwd, fd, dirs.paths[j]))                          if (0 == set_basedir(dirs.paths[j]))
                                 goto out;                                  goto out;
                         if (0 == dbopen(dirs.paths[j], 0))                          if (0 == dbopen(0))
                                 goto out;                                  goto out;
   
                         /*                          /*
Line 513  main(int argc, char *argv[])
Line 480  main(int argc, char *argv[])
                         SQL_EXEC("PRAGMA synchronous = OFF");                          SQL_EXEC("PRAGMA synchronous = OFF");
 #endif  #endif
   
                         if (0 == ofmerge(mc, mp, dirs.paths[j]))                          ofmerge(mc, mp);
                                 goto out;                          dbclose(0);
                         dbclose(dirs.paths[j], 0);  
                         offree();                          offree();
                         ohash_delete(&inos);                          ohash_delete(&inos);
                         ohash_init(&inos, 6, &ino_info);                          ohash_init(&inos, 6, &ino_info);
Line 524  main(int argc, char *argv[])
Line 490  main(int argc, char *argv[])
                 }                  }
         }          }
 out:  out:
         close(fd);          set_basedir(NULL);
         manpath_free(&dirs);          manpath_free(&dirs);
         mchars_free(mc);          mchars_free(mc);
         mparse_free(mp);          mparse_free(mp);
Line 538  out:
Line 504  out:
         ohash_delete(&inos);          ohash_delete(&inos);
         ohash_delete(&filenames);          ohash_delete(&filenames);
         offree();          offree();
         return(rc ? EXIT_SUCCESS : EXIT_FAILURE);          return(exitcode);
 usage:  usage:
         fprintf(stderr, "usage: %s [-anvW] [-C file]\n"          fprintf(stderr, "usage: %s [-anvW] [-C file]\n"
                         "       %s [-anvW] dir ...\n"                          "       %s [-anvW] dir ...\n"
Line 548  usage:
Line 514  usage:
                        progname, progname, progname,                         progname, progname, progname,
                        progname, progname);                         progname, progname);
   
         return(EXIT_FAILURE);          return((int)MANDOCLEVEL_BADARG);
 }  }
   
 /*  /*
  * Scan a directory tree rooted at "base" for manpages.   * Scan a directory tree rooted at "basedir" for manpages.
  * We use fts(), scanning directory parts along the way for clues to our   * We use fts(), scanning directory parts along the way for clues to our
  * section and architecture.   * section and architecture.
  *   *
Line 566  usage:
Line 532  usage:
  * TODO: accomodate for multi-language directories.   * TODO: accomodate for multi-language directories.
  */   */
 static int  static int
 treescan(const char *base)  treescan(void)
 {  {
         FTS             *f;          FTS             *f;
         FTSENT          *ff;          FTSENT          *ff;
Line 584  treescan(const char *base)
Line 550  treescan(const char *base)
          */           */
         f = fts_open((char * const *)argv, FTS_LOGICAL, NULL);          f = fts_open((char * const *)argv, FTS_LOGICAL, NULL);
         if (NULL == f) {          if (NULL == f) {
                 perror(base);                  exitcode = (int)MANDOCLEVEL_SYSERR;
                   say("", NULL);
                 return(0);                  return(0);
         }          }
   
Line 599  treescan(const char *base)
Line 566  treescan(const char *base)
                  * Disallow duplicate (hard-linked) files.                   * Disallow duplicate (hard-linked) files.
                  */                   */
                 if (FTS_F == ff->fts_info) {                  if (FTS_F == ff->fts_info) {
                           if (0 == strcmp(path, MANDOC_DB))
                                   continue;
                         if ( ! use_all && ff->fts_level < 2) {                          if ( ! use_all && ff->fts_level < 2) {
                                 WARNING(path, base, "Extraneous file");                                  if (warnings)
                                           say(path, "Extraneous file");
                                 continue;                                  continue;
                         } else if (inocheck(ff->fts_statp)) {                          } else if (inocheck(ff->fts_statp)) {
                                 WARNING(path, base, "Duplicate file");                                  if (warnings)
                                           say(path, "Duplicate file");
                                 continue;                                  continue;
                         }                          } else if (NULL == (sec =
                                           strrchr(ff->fts_name, '.'))) {
                         cp = ff->fts_name;                                  if ( ! use_all) {
                                           if (warnings)
                         if (0 == strcmp(cp, "mandocdb.db")) {                                                  say(path,
                                 WARNING(path, base, "Skip database");                                                      "No filename suffix");
                                 continue;  
                         } else if (NULL != (cp = strrchr(cp, '.'))) {  
                                 if (0 == strcmp(cp + 1, "html")) {  
                                         WARNING(path, base, "Skip html");  
                                         continue;                                          continue;
                                 } else if (0 == strcmp(cp + 1, "gz")) {  
                                         WARNING(path, base, "Skip gz");  
                                         continue;  
                                 } else if (0 == strcmp(cp + 1, "ps")) {  
                                         WARNING(path, base, "Skip ps");  
                                         continue;  
                                 } else if (0 == strcmp(cp + 1, "pdf")) {  
                                         WARNING(path, base, "Skip pdf");  
                                         continue;  
                                 }                                  }
                           } else if (0 == strcmp(++sec, "html")) {
                                   if (warnings)
                                           say(path, "Skip html");
                                   continue;
                           } else if (0 == strcmp(sec, "gz")) {
                                   if (warnings)
                                           say(path, "Skip gz");
                                   continue;
                           } else if (0 == strcmp(sec, "ps")) {
                                   if (warnings)
                                           say(path, "Skip ps");
                                   continue;
                           } else if (0 == strcmp(sec, "pdf")) {
                                   if (warnings)
                                           say(path, "Skip pdf");
                                   continue;
                           } else if ( ! use_all &&
                               ((FORM_SRC == dform && strcmp(sec, dsec)) ||
                                (FORM_CAT == dform && strcmp(sec, "0")))) {
                                   if (warnings)
                                           say(path, "Wrong filename suffix");
                                   continue;
                           } else {
                                   sec[-1] = '\0';
                                   sec = stradd(sec);
                         }                          }
   
                         if (NULL != (sec = strrchr(ff->fts_name, '.'))) {  
                                 *sec = '\0';  
                                 sec = stradd(sec + 1);  
                         }  
                         name = stradd(ff->fts_name);                          name = stradd(ff->fts_name);
                         ofadd(base, dform, path,                          ofadd(dform, path,
                                 name, dsec, sec, arch, ff->fts_statp);                                  name, dsec, sec, arch, ff->fts_statp);
                         continue;                          continue;
                 } else if (FTS_D != ff->fts_info &&                  } else if (FTS_D != ff->fts_info &&
                                 FTS_DP != ff->fts_info)                                  FTS_DP != ff->fts_info) {
                           if (warnings)
                                   say(path, "Not a regular file");
                         continue;                          continue;
                   }
   
                 switch (ff->fts_level) {                  switch (ff->fts_level) {
                 case (0):                  case (0):
Line 667  treescan(const char *base)
Line 648  treescan(const char *base)
                         if (NULL != dsec || use_all)                          if (NULL != dsec || use_all)
                                 break;                                  break;
   
                         WARNING(path, base, "Unknown directory part");                          if (warnings)
                                   say(path, "Unknown directory part");
                         fts_set(f, ff, FTS_SKIP);                          fts_set(f, ff, FTS_SKIP);
                         break;                          break;
                 case (2):                  case (2):
Line 682  treescan(const char *base)
Line 664  treescan(const char *base)
                 default:                  default:
                         if (FTS_DP == ff->fts_info || use_all)                          if (FTS_DP == ff->fts_info || use_all)
                                 break;                                  break;
                         WARNING(path, base, "Extraneous directory part");                          if (warnings)
                                   say(path, "Extraneous directory part");
                         fts_set(f, ff, FTS_SKIP);                          fts_set(f, ff, FTS_SKIP);
                         break;                          break;
                 }                  }
Line 708  treescan(const char *base)
Line 691  treescan(const char *base)
  * See treescan() for the fts(3) version of this.   * See treescan() for the fts(3) version of this.
  */   */
 static void  static void
 filescan(const char *file, const char *base)  filescan(const char *file)
 {  {
           char             buf[PATH_MAX];
         const char      *sec, *arch, *name, *dsec;          const char      *sec, *arch, *name, *dsec;
         char            *p, *start, *buf;          char            *p, *start;
         int              dform;          int              dform;
         struct stat      st;          struct stat      st;
   
Line 720  filescan(const char *file, const char *base)
Line 704  filescan(const char *file, const char *base)
         if (0 == strncmp(file, "./", 2))          if (0 == strncmp(file, "./", 2))
                 file += 2;                  file += 2;
   
         if (-1 == stat(file, &st)) {          if (NULL == realpath(file, buf)) {
                 WARNING(file, base, "%s", strerror(errno));                  exitcode = (int)MANDOCLEVEL_BADARG;
                   say(file, NULL);
                 return;                  return;
           } else if (strstr(buf, basedir) != buf) {
                   exitcode = (int)MANDOCLEVEL_BADARG;
                   say("", "%s: outside base directory", buf);
                   return;
           } else if (-1 == stat(buf, &st)) {
                   exitcode = (int)MANDOCLEVEL_BADARG;
                   say(file, NULL);
                   return;
         } else if ( ! (S_IFREG & st.st_mode)) {          } else if ( ! (S_IFREG & st.st_mode)) {
                 WARNING(file, base, "Not a regular file");                  exitcode = (int)MANDOCLEVEL_BADARG;
                   say(file, "Not a regular file");
                 return;                  return;
         } else if (inocheck(&st)) {          } else if (inocheck(&st)) {
                 WARNING(file, base, "Duplicate file");                  if (warnings)
                           say(file, "Duplicate file");
                 return;                  return;
         }          }
           start = buf + strlen(basedir);
         buf = mandoc_strdup(file);  
         start = buf;  
         sec = arch = name = dsec = NULL;          sec = arch = name = dsec = NULL;
         dform = FORM_NONE;          dform = FORM_NONE;
   
Line 783  filescan(const char *file, const char *base)
Line 776  filescan(const char *file, const char *base)
                 *p = '\0';                  *p = '\0';
         }          }
   
         ofadd(base, dform, file, name, dsec, sec, arch, &st);          ofadd(dform, file, name, dsec, sec, arch, &st);
         free(buf);  
 }  }
   
 /*  /*
Line 853  inoadd(const struct stat *st, struct of *of)
Line 845  inoadd(const struct stat *st, struct of *of)
 }  }
   
 static void  static void
 ofadd(const char *base, int dform, const char *file,  ofadd(int dform, const char *file, const char *name, const char *dsec,
                 const char *name, const char *dsec, const char *sec,          const char *sec, const char *arch, const struct stat *st)
                 const char *arch, const struct stat *st)  
 {  {
         struct of       *of;          struct of       *of;
         int              sform;          int              sform;
Line 880  ofadd(const char *base, int dform, const char *file, 
Line 871  ofadd(const char *base, int dform, const char *file, 
         }          }
   
         of = mandoc_calloc(1, sizeof(struct of));          of = mandoc_calloc(1, sizeof(struct of));
         strlcpy(of->file, file, MAXPATHLEN);          strlcpy(of->file, file, PATH_MAX);
         of->name = name;          of->name = name;
         of->sec = sec;          of->sec = sec;
         of->dsec = dsec;          of->dsec = dsec;
Line 912  offree(void)
Line 903  offree(void)
   
 /*  /*
  * Run through the files in the global vector "ofs" and add them to the   * Run through the files in the global vector "ofs" and add them to the
  * database specified in "base".   * database specified in "basedir".
  *   *
  * This handles the parsing scheme itself, using the cues of directory   * This handles the parsing scheme itself, using the cues of directory
  * and filename to determine whether the file is parsable or not.   * and filename to determine whether the file is parsable or not.
  */   */
 static int  static void
 ofmerge(struct mchars *mc, struct mparse *mp, const char *base)  ofmerge(struct mchars *mc, struct mparse *mp)
 {  {
         int              form;          int              form;
         size_t           sz;          size_t           sz;
         struct mdoc     *mdoc;          struct mdoc     *mdoc;
         struct man      *man;          struct man      *man;
         char             buf[MAXPATHLEN];          char             buf[PATH_MAX];
         char            *bufp;          char            *bufp;
         const char      *msec, *march, *mtitle, *cp;          const char      *msec, *march, *mtitle, *cp;
         struct of       *of;          struct of       *of;
Line 939  ofmerge(struct mchars *mc, struct mparse *mp, const ch
Line 930  ofmerge(struct mchars *mc, struct mparse *mp, const ch
                  * own.                   * own.
                  */                   */
                 if ( ! use_all && FORM_CAT == of->dform) {                  if ( ! use_all && FORM_CAT == of->dform) {
                         sz = strlcpy(buf, of->file, MAXPATHLEN);                          sz = strlcpy(buf, of->file, PATH_MAX);
                         if (sz >= MAXPATHLEN) {                          if (sz >= PATH_MAX) {
                                 WARNING(of->file, base,                                  if (warnings)
                                         "Filename too long");                                          say(of->file, "Filename too long");
                                 continue;                                  continue;
                         }                          }
                         bufp = strstr(buf, "cat");                          bufp = strstr(buf, "cat");
Line 950  ofmerge(struct mchars *mc, struct mparse *mp, const ch
Line 941  ofmerge(struct mchars *mc, struct mparse *mp, const ch
                         memcpy(bufp, "man", 3);                          memcpy(bufp, "man", 3);
                         if (NULL != (bufp = strrchr(buf, '.')))                          if (NULL != (bufp = strrchr(buf, '.')))
                                 *++bufp = '\0';                                  *++bufp = '\0';
                         strlcat(buf, of->dsec, MAXPATHLEN);                          strlcat(buf, of->dsec, PATH_MAX);
                         if (filecheck(buf)) {                          if (filecheck(buf)) {
                                 WARNING(of->file, base, "Man "                                  if (warnings)
                                         "source exists: %s", buf);                                          say(of->file, "Man "
                                               "source exists: %s", buf);
                                 continue;                                  continue;
                         }                          }
                 }                  }
Line 1006  ofmerge(struct mchars *mc, struct mparse *mp, const ch
Line 998  ofmerge(struct mchars *mc, struct mparse *mp, const ch
                  * section, like encrypt(1) = makekey(8).  Do not skip                   * section, like encrypt(1) = makekey(8).  Do not skip
                  * manuals for such reasons.                   * manuals for such reasons.
                  */                   */
                 if ( ! use_all && form && strcasecmp(msec, of->dsec))                  if (warnings && !use_all && form &&
                         WARNING(of->file, base, "Section \"%s\" "                                  strcasecmp(msec, of->dsec))
                           say(of->file, "Section \"%s\" "
                                 "manual in %s directory",                                  "manual in %s directory",
                                 msec, of->dsec);                                  msec, of->dsec);
   
Line 1025  ofmerge(struct mchars *mc, struct mparse *mp, const ch
Line 1018  ofmerge(struct mchars *mc, struct mparse *mp, const ch
                  * Thus, warn about architecture mismatches,                   * Thus, warn about architecture mismatches,
                  * but don't skip manuals for this reason.                   * but don't skip manuals for this reason.
                  */                   */
                 if ( ! use_all && strcasecmp(march, of->arch))                  if (warnings && !use_all && strcasecmp(march, of->arch))
                         WARNING(of->file, base, "Architecture \"%s\" "                          say(of->file, "Architecture \"%s\" "
                                 "manual in \"%s\" directory",                                  "manual in \"%s\" directory",
                                 march, of->arch);                                  march, of->arch);
   
Line 1039  ofmerge(struct mchars *mc, struct mparse *mp, const ch
Line 1032  ofmerge(struct mchars *mc, struct mparse *mp, const ch
                 } else if (NULL != man)                  } else if (NULL != man)
                         parse_man(of, man_node(man));                          parse_man(of, man_node(man));
                 else                  else
                         parse_catpage(of, base);                          parse_catpage(of);
   
                 dbindex(mc, form, of, base);                  dbindex(mc, form, of);
         }          }
   
         return(1);  
 }  }
   
 static void  static void
 parse_catpage(struct of *of, const char *base)  parse_catpage(struct of *of)
 {  {
         FILE            *stream;          FILE            *stream;
         char            *line, *p, *title;          char            *line, *p, *title;
         size_t           len, plen, titlesz;          size_t           len, plen, titlesz;
   
         if (NULL == (stream = fopen(of->file, "r"))) {          if (NULL == (stream = fopen(of->file, "r"))) {
                 WARNING(of->file, base, "%s", strerror(errno));                  if (warnings)
                           say(of->file, NULL);
                 return;                  return;
         }          }
   
Line 1107  parse_catpage(struct of *of, const char *base)
Line 1099  parse_catpage(struct of *of, const char *base)
          */           */
   
         if (NULL == title || '\0' == *title) {          if (NULL == title || '\0' == *title) {
                 WARNING(of->file, base, "Cannot find NAME section");                  if (warnings)
                           say(of->file, "Cannot find NAME section");
                   putkey(of, of->name, TYPE_Nd);
                 fclose(stream);                  fclose(stream);
                 free(title);                  free(title);
                 return;                  return;
Line 1126  parse_catpage(struct of *of, const char *base)
Line 1120  parse_catpage(struct of *of, const char *base)
                 for (p += 2; ' ' == *p || '\b' == *p; p++)                  for (p += 2; ' ' == *p || '\b' == *p; p++)
                         /* Skip to next word. */ ;                          /* Skip to next word. */ ;
         } else {          } else {
                 WARNING(of->file, base, "No dash in title line");                  if (warnings)
                           say(of->file, "No dash in title line");
                 p = title;                  p = title;
         }          }
   
Line 1186  putmdockey(const struct of *of, const struct mdoc_node
Line 1181  putmdockey(const struct of *of, const struct mdoc_node
         }          }
 }  }
   
 static int  static void
 parse_man(struct of *of, const struct man_node *n)  parse_man(struct of *of, const struct man_node *n)
 {  {
         const struct man_node *head, *body;          const struct man_node *head, *body;
Line 1195  parse_man(struct of *of, const struct man_node *n)
Line 1190  parse_man(struct of *of, const struct man_node *n)
         size_t           sz, titlesz;          size_t           sz, titlesz;
   
         if (NULL == n)          if (NULL == n)
                 return(0);                  return;
   
         /*          /*
          * We're only searching for one thing: the first text child in           * We're only searching for one thing: the first text child in
Line 1237  parse_man(struct of *of, const struct man_node *n)
Line 1232  parse_man(struct of *of, const struct man_node *n)
                                 title[titlesz - 1] = ' ';                                  title[titlesz - 1] = ' ';
                         }                          }
                         if (NULL == title)                          if (NULL == title)
                                 return(1);                                  return;
   
                         title = mandoc_realloc(title, titlesz + 1);                          title = mandoc_realloc(title, titlesz + 1);
                         title[titlesz] = '\0';                          title[titlesz] = '\0';
Line 1250  parse_man(struct of *of, const struct man_node *n)
Line 1245  parse_man(struct of *of, const struct man_node *n)
   
                         if (0 == (sz = strlen(sv))) {                          if (0 == (sz = strlen(sv))) {
                                 free(title);                                  free(title);
                                 return(1);                                  return;
                         }                          }
   
                         /* Erase trailing space. */                          /* Erase trailing space. */
Line 1261  parse_man(struct of *of, const struct man_node *n)
Line 1256  parse_man(struct of *of, const struct man_node *n)
   
                         if (start == sv) {                          if (start == sv) {
                                 free(title);                                  free(title);
                                 return(1);                                  return;
                         }                          }
   
                         start = sv;                          start = sv;
Line 1298  parse_man(struct of *of, const struct man_node *n)
Line 1293  parse_man(struct of *of, const struct man_node *n)
                         if (sv == start) {                          if (sv == start) {
                                 putkey(of, start, TYPE_Nm);                                  putkey(of, start, TYPE_Nm);
                                 free(title);                                  free(title);
                                 return(1);                                  return;
                         }                          }
   
                         while (isspace((unsigned char)*start))                          while (isspace((unsigned char)*start))
Line 1322  parse_man(struct of *of, const struct man_node *n)
Line 1317  parse_man(struct of *of, const struct man_node *n)
                         of->desc = stradd(start);                          of->desc = stradd(start);
                         putkey(of, start, TYPE_Nd);                          putkey(of, start, TYPE_Nd);
                         free(title);                          free(title);
                         return(1);                          return;
                 }                  }
         }          }
   
         for (n = n->child; n; n = n->next)          for (n = n->child; n; n = n->next)
                 if (parse_man(of, n))                  parse_man(of, n);
                         return(1);  
   
         return(0);  
 }  }
   
 static void  static void
Line 1796  utf8key(struct mchars *mc, struct str *key)
Line 1788  utf8key(struct mchars *mc, struct str *key)
  * Also, UTF-8-encode the description at the last possible moment.   * Also, UTF-8-encode the description at the last possible moment.
  */   */
 static void  static void
 dbindex(struct mchars *mc, int form,  dbindex(struct mchars *mc, int form, const struct of *of)
                 const struct of *of, const char *base)  
 {  {
         struct str      *key;          struct str      *key;
         const char      *desc;          const char      *desc;
         int64_t          recno;          int64_t          recno;
         size_t           i;          size_t           i;
   
         DEBUG(of->file, base, "Adding to index");          if (verb)
                   say(of->file, "Adding to index");
   
         if (nodb)          if (nodb)
                 return;                  return;
Line 1846  dbindex(struct mchars *mc, int form, 
Line 1838  dbindex(struct mchars *mc, int form, 
 }  }
   
 static void  static void
 dbprune(const char *base)  dbprune(void)
 {  {
         struct of       *of;          struct of       *of;
         size_t           i;          size_t           i;
Line 1859  dbprune(const char *base)
Line 1851  dbprune(const char *base)
                 SQL_BIND_TEXT(stmts[STMT_DELETE], i, of->file);                  SQL_BIND_TEXT(stmts[STMT_DELETE], i, of->file);
                 SQL_STEP(stmts[STMT_DELETE]);                  SQL_STEP(stmts[STMT_DELETE]);
                 sqlite3_reset(stmts[STMT_DELETE]);                  sqlite3_reset(stmts[STMT_DELETE]);
                 DEBUG(of->file, base, "Deleted from index");                  if (verb)
                           say(of->file, "Deleted from index");
         }          }
 }  }
   
Line 1868  dbprune(const char *base)
Line 1861  dbprune(const char *base)
  * If "real" is not set, rename the temporary file into the real one.   * If "real" is not set, rename the temporary file into the real one.
  */   */
 static void  static void
 dbclose(const char *base, int real)  dbclose(int real)
 {  {
         size_t           i;          size_t           i;
         char             file[MAXPATHLEN];          char             file[PATH_MAX];
   
         if (nodb)          if (nodb)
                 return;                  return;
Line 1887  dbclose(const char *base, int real)
Line 1880  dbclose(const char *base, int real)
         if (real)          if (real)
                 return;                  return;
   
         strlcpy(file, MANDOC_DB, MAXPATHLEN);          strlcpy(file, MANDOC_DB, PATH_MAX);
         strlcat(file, "~", MAXPATHLEN);          strlcat(file, "~", PATH_MAX);
         if (-1 == rename(file, MANDOC_DB))          if (-1 == rename(file, MANDOC_DB)) {
                 perror(MANDOC_DB);                  exitcode = (int)MANDOCLEVEL_SYSERR;
                   say(MANDOC_DB, NULL);
           }
 }  }
   
 /*  /*
Line 1902  dbclose(const char *base, int real)
Line 1897  dbclose(const char *base, int real)
  * Must be matched by dbclose().   * Must be matched by dbclose().
  */   */
 static int  static int
 dbopen(const char *base, int real)  dbopen(int real)
 {  {
         char             file[MAXPATHLEN];          char             file[PATH_MAX];
         const char      *sql;          const char      *sql;
         int              rc, ofl;          int              rc, ofl;
         size_t           sz;          size_t           sz;
Line 1912  dbopen(const char *base, int real)
Line 1907  dbopen(const char *base, int real)
         if (nodb)          if (nodb)
                 return(1);                  return(1);
   
         sz = strlcpy(file, MANDOC_DB, MAXPATHLEN);          sz = strlcpy(file, MANDOC_DB, PATH_MAX);
         if ( ! real)          if ( ! real)
                 sz = strlcat(file, "~", MAXPATHLEN);                  sz = strlcat(file, "~", PATH_MAX);
   
         if (sz >= MAXPATHLEN) {          if (sz >= PATH_MAX) {
                 fprintf(stderr, "%s: Path too long\n", file);                  fprintf(stderr, "%s: Path too long\n", file);
                 return(0);                  return(0);
         }          }
Line 1929  dbopen(const char *base, int real)
Line 1924  dbopen(const char *base, int real)
   
         rc = sqlite3_open_v2(file, &db, ofl, NULL);          rc = sqlite3_open_v2(file, &db, ofl, NULL);
         if (SQLITE_OK == rc)          if (SQLITE_OK == rc)
                 return(1);                  goto prepare_statements;
         if (SQLITE_CANTOPEN != rc) {          if (SQLITE_CANTOPEN != rc) {
                 perror(file);                  exitcode = (int)MANDOCLEVEL_SYSERR;
                   say(file, NULL);
                 return(0);                  return(0);
         }          }
   
Line 1939  dbopen(const char *base, int real)
Line 1935  dbopen(const char *base, int real)
         db = NULL;          db = NULL;
   
         if (SQLITE_OK != (rc = sqlite3_open(file, &db))) {          if (SQLITE_OK != (rc = sqlite3_open(file, &db))) {
                 perror(file);                  exitcode = (int)MANDOCLEVEL_SYSERR;
                   say(file, NULL);
                 return(0);                  return(0);
         }          }
   
Line 1963  dbopen(const char *base, int real)
Line 1960  dbopen(const char *base, int real)
               "CREATE INDEX \"key_index\" ON keys (key);\n";                "CREATE INDEX \"key_index\" ON keys (key);\n";
   
         if (SQLITE_OK != sqlite3_exec(db, sql, NULL, NULL, NULL)) {          if (SQLITE_OK != sqlite3_exec(db, sql, NULL, NULL, NULL)) {
                 perror(sqlite3_errmsg(db));                  exitcode = (int)MANDOCLEVEL_SYSERR;
                   say(file, "%s", sqlite3_errmsg(db));
                 return(0);                  return(0);
         }          }
   
   prepare_statements:
           SQL_EXEC("PRAGMA foreign_keys = ON");
         sql = "DELETE FROM docs where file=?";          sql = "DELETE FROM docs where file=?";
         sqlite3_prepare_v2(db, sql, -1, &stmts[STMT_DELETE], NULL);          sqlite3_prepare_v2(db, sql, -1, &stmts[STMT_DELETE], NULL);
         sql = "INSERT INTO docs "          sql = "INSERT INTO docs "
Line 2000  hash_free(void *p, size_t sz, void *arg)
Line 2000  hash_free(void *p, size_t sz, void *arg)
 }  }
   
 static int  static int
 path_reset(const char *cwd, int fd, const char *base)  set_basedir(const char *targetdir)
 {  {
           static char      startdir[PATH_MAX];
           static int       fd;
   
         if (-1 == fchdir(fd)) {          /*
                 perror(cwd);           * Remember where we started by keeping a fd open to the origin
            * path component: throughout this utility, we chdir() a lot to
            * handle relative paths, and by doing this, we can return to
            * the starting point.
            */
           if ('\0' == *startdir) {
                   if (NULL == getcwd(startdir, PATH_MAX)) {
                           exitcode = (int)MANDOCLEVEL_SYSERR;
                           if (NULL != targetdir)
                                   say(".", NULL);
                           return(0);
                   }
                   if (-1 == (fd = open(startdir, O_RDONLY, 0))) {
                           exitcode = (int)MANDOCLEVEL_SYSERR;
                           say(startdir, NULL);
                           return(0);
                   }
                   if (NULL == targetdir)
                           targetdir = startdir;
           } else {
                   if (-1 == fd)
                           return(0);
                   if (-1 == fchdir(fd)) {
                           close(fd);
                           basedir[0] = '\0';
                           exitcode = (int)MANDOCLEVEL_SYSERR;
                           say(startdir, NULL);
                           return(0);
                   }
                   if (NULL == targetdir) {
                           close(fd);
                           return(1);
                   }
           }
           if (NULL == realpath(targetdir, basedir)) {
                   basedir[0] = '\0';
                   exitcode = (int)MANDOCLEVEL_BADARG;
                   say(targetdir, NULL);
                 return(0);                  return(0);
         } else if (-1 == chdir(base)) {          } else if (-1 == chdir(basedir)) {
                 perror(base);                  exitcode = (int)MANDOCLEVEL_BADARG;
                   say("", NULL);
                 return(0);                  return(0);
         }          }
         return(1);          return(1);
   }
   
   static void
   say(const char *file, const char *format, ...)
   {
           va_list          ap;
   
           if ('\0' != *basedir)
                   fprintf(stderr, "%s", basedir);
           if ('\0' != *basedir && '\0' != *file)
                   fputs("//", stderr);
           if ('\0' != *file)
                   fprintf(stderr, "%s", file);
           fputs(": ", stderr);
   
           if (NULL == format) {
                   perror(NULL);
                   return;
           }
   
           va_start(ap, format);
           vfprintf(stderr, format, ap);
           va_end(ap);
   
           fputc('\n', stderr);
 }  }

Legend:
Removed from v.1.55  
changed lines
  Added in v.1.62

CVSweb