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

Diff for /mandoc/mandocdb.c between version 1.58 and 1.59

version 1.58, 2013/06/05 02:00:26 version 1.59, 2013/06/05 17:48:14
Line 23 
Line 23 
   
 #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 <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 122  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  int      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 *);
Line 155  static int  parse_mdoc_Nm(struct of *, const struct md
Line 153  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 *, const char *, ...);  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 176  static int    use_all; /* use all found files */
Line 174  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 313  static const struct mdoc_handler mdocs[MDOC_MAX] = {
Line 313  static const struct mdoc_handler mdocs[MDOC_MAX] = {
 int  int
 main(int argc, char *argv[])  main(int argc, char *argv[])
 {  {
         char              cwd[PATH_MAX];          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 345  main(int argc, char *argv[])
Line 344  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, PATH_MAX)) {  
                 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 369  main(int argc, char *argv[])
Line 354  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 379  main(int argc, char *argv[])
Line 364  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 398  main(int argc, char *argv[])
Line 383  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 419  main(int argc, char *argv[])
Line 404  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 433  main(int argc, char *argv[])
Line 418  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 464  main(int argc, char *argv[])
Line 448  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 479  main(int argc, char *argv[])
Line 463  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 497  main(int argc, char *argv[])
Line 481  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 508  main(int argc, char *argv[])
Line 491  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 522  out:
Line 505  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 532  usage:
Line 515  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 550  usage:
Line 533  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 568  treescan(const char *base)
Line 551  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 585  treescan(const char *base)
Line 569  treescan(const char *base)
                 if (FTS_F == ff->fts_info) {                  if (FTS_F == ff->fts_info) {
                         if ( ! use_all && ff->fts_level < 2) {                          if ( ! use_all && ff->fts_level < 2) {
                                 if (warnings)                                  if (warnings)
                                         say(base, path, "Extraneous file");                                          say(path, "Extraneous file");
                                 continue;                                  continue;
                         } else if (inocheck(ff->fts_statp)) {                          } else if (inocheck(ff->fts_statp)) {
                                 if (warnings)                                  if (warnings)
                                         say(base, path, "Duplicate file");                                          say(path, "Duplicate file");
                                 continue;                                  continue;
                         }                          }
   
Line 597  treescan(const char *base)
Line 581  treescan(const char *base)
   
                         if (0 == strcmp(cp, "mandocdb.db")) {                          if (0 == strcmp(cp, "mandocdb.db")) {
                                 if (warnings)                                  if (warnings)
                                         say(base, path, "Skip database");                                          say(path, "Skip database");
                                 continue;                                  continue;
                         } else if (NULL != (cp = strrchr(cp, '.'))) {                          } else if (NULL != (cp = strrchr(cp, '.'))) {
                                 if (0 == strcmp(cp + 1, "html")) {                                  if (0 == strcmp(cp + 1, "html")) {
                                         if (warnings)                                          if (warnings)
                                                 say(base, path, "Skip html");                                                  say(path, "Skip html");
                                         continue;                                          continue;
                                 } else if (0 == strcmp(cp + 1, "gz")) {                                  } else if (0 == strcmp(cp + 1, "gz")) {
                                         if (warnings)                                          if (warnings)
                                                 say(base, path, "Skip gz");                                                  say(path, "Skip gz");
                                         continue;                                          continue;
                                 } else if (0 == strcmp(cp + 1, "ps")) {                                  } else if (0 == strcmp(cp + 1, "ps")) {
                                         if (warnings)                                          if (warnings)
                                                 say(base, path, "Skip ps");                                                  say(path, "Skip ps");
                                         continue;                                          continue;
                                 } else if (0 == strcmp(cp + 1, "pdf")) {                                  } else if (0 == strcmp(cp + 1, "pdf")) {
                                         if (warnings)                                          if (warnings)
                                                 say(base, path, "Skip pdf");                                                  say(path, "Skip pdf");
                                         continue;                                          continue;
                                 }                                  }
                         }                          }
Line 624  treescan(const char *base)
Line 608  treescan(const char *base)
                                 sec = stradd(sec + 1);                                  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 &&
Line 659  treescan(const char *base)
Line 643  treescan(const char *base)
                                 break;                                  break;
   
                         if (warnings)                          if (warnings)
                                 say(base, path, "Unknown directory part");                                  say(path, "Unknown directory part");
                         fts_set(f, ff, FTS_SKIP);                          fts_set(f, ff, FTS_SKIP);
                         break;                          break;
                 case (2):                  case (2):
Line 675  treescan(const char *base)
Line 659  treescan(const char *base)
                         if (FTS_DP == ff->fts_info || use_all)                          if (FTS_DP == ff->fts_info || use_all)
                                 break;                                  break;
                         if (warnings)                          if (warnings)
                                 say(base, path, "Extraneous directory part");                                  say(path, "Extraneous directory part");
                         fts_set(f, ff, FTS_SKIP);                          fts_set(f, ff, FTS_SKIP);
                         break;                          break;
                 }                  }
Line 701  treescan(const char *base)
Line 685  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 713  filescan(const char *file, const char *base)
Line 698  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)) {
                 if (warnings)                  exitcode = (int)MANDOCLEVEL_BADARG;
                         say(base, file, "%s", strerror(errno));                  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)) {
                 if (warnings)                  exitcode = (int)MANDOCLEVEL_BADARG;
                         say(base, file, "Not a regular file");                  say(file, "Not a regular file");
                 return;                  return;
         } else if (inocheck(&st)) {          } else if (inocheck(&st)) {
                 if (warnings)                  if (warnings)
                         say(base, file, "Duplicate file");                          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 779  filescan(const char *file, const char *base)
Line 770  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 849  inoadd(const struct stat *st, struct of *of)
Line 839  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 908  offree(void)
Line 897  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;
Line 938  ofmerge(struct mchars *mc, struct mparse *mp, const ch
Line 927  ofmerge(struct mchars *mc, struct mparse *mp, const ch
                         sz = strlcpy(buf, of->file, PATH_MAX);                          sz = strlcpy(buf, of->file, PATH_MAX);
                         if (sz >= PATH_MAX) {                          if (sz >= PATH_MAX) {
                                 if (warnings)                                  if (warnings)
                                         say(base, of->file,                                          say(of->file, "Filename too long");
                                             "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 938  ofmerge(struct mchars *mc, struct mparse *mp, const ch
                         strlcat(buf, of->dsec, PATH_MAX);                          strlcat(buf, of->dsec, PATH_MAX);
                         if (filecheck(buf)) {                          if (filecheck(buf)) {
                                 if (warnings)                                  if (warnings)
                                         say(base, of->file, "Man "                                          say(of->file, "Man "
                                             "source exists: %s", buf);                                              "source exists: %s", buf);
                                 continue;                                  continue;
                         }                          }
Line 1006  ofmerge(struct mchars *mc, struct mparse *mp, const ch
Line 994  ofmerge(struct mchars *mc, struct mparse *mp, const ch
                  */                   */
                 if (warnings && !use_all && form &&                  if (warnings && !use_all && form &&
                                 strcasecmp(msec, of->dsec))                                  strcasecmp(msec, of->dsec))
                         say(base, of->file, "Section \"%s\" "                          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 1013  ofmerge(struct mchars *mc, struct mparse *mp, const ch
                  * but don't skip manuals for this reason.                   * but don't skip manuals for this reason.
                  */                   */
                 if (warnings && !use_all && strcasecmp(march, of->arch))                  if (warnings && !use_all && strcasecmp(march, of->arch))
                         say(base, of->file, "Architecture \"%s\" "                          say(of->file, "Architecture \"%s\" "
                                 "manual in \"%s\" directory",                                  "manual in \"%s\" directory",
                                 march, of->arch);                                  march, of->arch);
   
Line 1038  ofmerge(struct mchars *mc, struct mparse *mp, const ch
Line 1026  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;
Line 1055  parse_catpage(struct of *of, const char *base)
Line 1041  parse_catpage(struct of *of, const char *base)
   
         if (NULL == (stream = fopen(of->file, "r"))) {          if (NULL == (stream = fopen(of->file, "r"))) {
                 if (warnings)                  if (warnings)
                         say(base, of->file, "%s", strerror(errno));                          say(of->file, NULL);
                 return;                  return;
         }          }
   
Line 1108  parse_catpage(struct of *of, const char *base)
Line 1094  parse_catpage(struct of *of, const char *base)
   
         if (NULL == title || '\0' == *title) {          if (NULL == title || '\0' == *title) {
                 if (warnings)                  if (warnings)
                         say(base, of->file, "Cannot find NAME section");                          say(of->file, "Cannot find NAME section");
                 fclose(stream);                  fclose(stream);
                 free(title);                  free(title);
                 return;                  return;
Line 1128  parse_catpage(struct of *of, const char *base)
Line 1114  parse_catpage(struct of *of, const char *base)
                         /* Skip to next word. */ ;                          /* Skip to next word. */ ;
         } else {          } else {
                 if (warnings)                  if (warnings)
                         say(base, of->file, "No dash in title line");                          say(of->file, "No dash in title line");
                 p = title;                  p = title;
         }          }
   
Line 1798  utf8key(struct mchars *mc, struct str *key)
Line 1784  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;
Line 1807  dbindex(struct mchars *mc, int form, 
Line 1792  dbindex(struct mchars *mc, int form, 
         size_t           i;          size_t           i;
   
         if (verb)          if (verb)
                 say(base, of->file, "Adding to index");                  say(of->file, "Adding to index");
   
         if (nodb)          if (nodb)
                 return;                  return;
Line 1849  dbindex(struct mchars *mc, int form, 
Line 1834  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 1863  dbprune(const char *base)
Line 1848  dbprune(const char *base)
                 SQL_STEP(stmts[STMT_DELETE]);                  SQL_STEP(stmts[STMT_DELETE]);
                 sqlite3_reset(stmts[STMT_DELETE]);                  sqlite3_reset(stmts[STMT_DELETE]);
                 if (verb)                  if (verb)
                         say(base, of->file, "Deleted from index");                          say(of->file, "Deleted from index");
         }          }
 }  }
   
Line 1872  dbprune(const char *base)
Line 1857  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[PATH_MAX];          char             file[PATH_MAX];
Line 1893  dbclose(const char *base, int real)
Line 1878  dbclose(const char *base, int real)
   
         strlcpy(file, MANDOC_DB, PATH_MAX);          strlcpy(file, MANDOC_DB, PATH_MAX);
         strlcat(file, "~", PATH_MAX);          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 1906  dbclose(const char *base, int real)
Line 1893  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[PATH_MAX];          char             file[PATH_MAX];
         const char      *sql;          const char      *sql;
Line 1935  dbopen(const char *base, int real)
Line 1922  dbopen(const char *base, int real)
         if (SQLITE_OK == rc)          if (SQLITE_OK == rc)
                 goto prepare_statements;                  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 1943  dbopen(const char *base, int real)
Line 1931  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 1967  dbopen(const char *base, int real)
Line 1956  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);
         }          }
   
Line 2006  hash_free(void *p, size_t sz, void *arg)
Line 1996  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  static void
 say(const char *dir, const char *file, const char *format, ...)  say(const char *file, const char *format, ...)
 {  {
         va_list          ap;          va_list          ap;
   
         fprintf(stderr, "%s", dir);          if ('\0' != *basedir)
                   fprintf(stderr, "%s", basedir);
           if ('\0' != *basedir && '\0' != *file)
                   fputs("//", stderr);
         if ('\0' != *file)          if ('\0' != *file)
                 fprintf(stderr, "//%s", file);                  fprintf(stderr, "%s", file);
         fputs(": ", stderr);          fputs(": ", stderr);
   
           if (NULL == format) {
                   perror(NULL);
                   return;
           }
   
         va_start(ap, format);          va_start(ap, format);
         vfprintf(stderr, format, ap);          vfprintf(stderr, format, ap);

Legend:
Removed from v.1.58  
changed lines
  Added in v.1.59

CVSweb