=================================================================== RCS file: /cvs/mandoc/mandocdb.c,v retrieving revision 1.44 retrieving revision 1.49.2.1 diff -u -p -r1.44 -r1.49.2.1 --- mandoc/mandocdb.c 2012/03/23 05:07:35 1.44 +++ mandoc/mandocdb.c 2013/09/17 21:32:07 1.49.2.1 @@ -1,7 +1,7 @@ -/* $Id: mandocdb.c,v 1.44 2012/03/23 05:07:35 kristaps Exp $ */ +/* $Id: mandocdb.c,v 1.49.2.1 2013/09/17 21:32:07 schwarze Exp $ */ /* - * Copyright (c) 2011 Kristaps Dzonsons - * Copyright (c) 2011 Ingo Schwarze + * Copyright (c) 2011, 2012 Kristaps Dzonsons + * Copyright (c) 2011, 2012 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -19,14 +19,15 @@ #include "config.h" #endif -#include #include #include #include #include +#include #include #include +#include #include #include #include @@ -55,11 +56,20 @@ #define MANDOC_SRC 0x1 #define MANDOC_FORM 0x2 +#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) + /* Access to the mandoc database on disk. */ struct mdb { - char idxn[MAXPATHLEN]; /* index db filename */ - char dbn[MAXPATHLEN]; /* keyword db filename */ + char idxn[PATH_MAX]; /* index db filename */ + char dbn[PATH_MAX]; /* keyword db filename */ DB *idx; /* index recno database */ DB *db; /* keyword btree database */ }; @@ -127,12 +137,12 @@ static void index_merge(const struct of *, struct m const char *); static void index_prune(const struct of *, struct mdb *, struct recs *, const char *); -static void ofile_argbuild(int, char *[], +static void ofile_argbuild(int, char *[], struct of **, const char *); static void ofile_dirbuild(const char *, const char *, - const char *, int, struct of **); + const char *, int, struct of **, char *); static void ofile_free(struct of *); -static void pformatted(DB *, struct buf *, struct buf *, +static void pformatted(DB *, struct buf *, struct buf *, const struct of *, const char *); static int pman_node(MAN_ARGS); static void pmdoc_node(MDOC_ARGS); @@ -295,6 +305,7 @@ main(int argc, char *argv[]) enum op op; /* current operation */ const char *dir; int ch, i, flags; + char dirbuf[PATH_MAX]; DB *hash; /* temporary keyword hashtable */ BTREEINFO info; /* btree configuration */ size_t sz1, sz2; @@ -385,7 +396,7 @@ main(int argc, char *argv[]) info.lorder = 4321; info.flags = R_DUP; - mp = mparse_alloc(MPARSE_AUTO, MANDOCLEVEL_FATAL, NULL, NULL); + mp = mparse_alloc(MPARSE_AUTO, MANDOCLEVEL_FATAL, NULL, NULL, NULL); memset(&buf, 0, sizeof(struct buf)); memset(&dbuf, 0, sizeof(struct buf)); @@ -399,21 +410,21 @@ main(int argc, char *argv[]) ofile_argbuild(argc, argv, &of, "."); if (NULL == of) goto out; - index_merge(of, mp, &dbuf, &buf, + index_merge(of, mp, &dbuf, &buf, hash, &mdb, &recs, "."); goto out; } if (OP_UPDATE == op || OP_DELETE == op) { - strlcat(mdb.dbn, dir, MAXPATHLEN); - strlcat(mdb.dbn, "/", MAXPATHLEN); - sz1 = strlcat(mdb.dbn, MANDOC_DB, MAXPATHLEN); + strlcat(mdb.dbn, dir, PATH_MAX); + strlcat(mdb.dbn, "/", PATH_MAX); + sz1 = strlcat(mdb.dbn, MANDOC_DB, PATH_MAX); - strlcat(mdb.idxn, dir, MAXPATHLEN); - strlcat(mdb.idxn, "/", MAXPATHLEN); - sz2 = strlcat(mdb.idxn, MANDOC_IDX, MAXPATHLEN); + strlcat(mdb.idxn, dir, PATH_MAX); + strlcat(mdb.idxn, "/", PATH_MAX); + sz2 = strlcat(mdb.idxn, MANDOC_IDX, PATH_MAX); - if (sz1 >= MAXPATHLEN || sz2 >= MAXPATHLEN) { + if (sz1 >= PATH_MAX || sz2 >= PATH_MAX) { fprintf(stderr, "%s: path too long\n", dir); exit((int)MANDOCLEVEL_BADARG); } @@ -481,8 +492,8 @@ main(int argc, char *argv[]) exit((int)MANDOCLEVEL_SYSERR); } - strlcpy(mdb.dbn, MANDOC_DB, MAXPATHLEN); - strlcpy(mdb.idxn, MANDOC_IDX, MAXPATHLEN); + strlcpy(mdb.dbn, MANDOC_DB, PATH_MAX); + strlcpy(mdb.idxn, MANDOC_IDX, PATH_MAX); flags = O_CREAT | O_TRUNC | O_RDWR; mdb.db = dbopen(mdb.dbn, flags, 0644, DB_BTREE, &info); @@ -500,7 +511,8 @@ main(int argc, char *argv[]) * Search for manuals and fill the new database. */ - ofile_dirbuild(".", "", "", 0, &of); + strlcpy(dirbuf, dirs.paths[i], PATH_MAX); + ofile_dirbuild(".", "", "", 0, &of, dirbuf); if (NULL != of) { index_merge(of, mp, &dbuf, &buf, hash, @@ -535,7 +547,7 @@ out: usage: fprintf(stderr, - "usage: %s [-avvv] [-C file] | dir ... | -t file ...\n" + "usage: %s [-av] [-C file] | dir ... | -t file ...\n" " -d dir [file ...] | " "-u dir [file ...]\n", progname); @@ -617,12 +629,9 @@ index_merge(const struct of *of, struct mparse *mp, skip = 0; assert(of->sec); assert(msec); - if (warnings && strcasecmp(msec, of->sec)) - fprintf(stderr, "%s: section \"%s\" manual " - "in \"%s\" directory\n", - fn, msec, of->sec); - - + if (strcasecmp(msec, of->sec)) + WARNING(fn, basedir, "Section \"%s\" manual " + "in \"%s\" directory", msec, of->sec); /* * Manual page directories exist for each kernel * architecture as returned by machine(1). @@ -640,10 +649,10 @@ index_merge(const struct of *of, struct mparse *mp, assert(of->arch); assert(march); - if (warnings && strcasecmp(march, of->arch)) - fprintf(stderr, "%s: architecture \"%s\" manual " - "in \"%s\" directory\n", - fn, march, of->arch); + if (strcasecmp(march, of->arch)) + WARNING(fn, basedir, "Architecture \"%s\" " + "manual in \"%s\" directory", + march, of->arch); /* * By default, skip a file if the title given @@ -813,9 +822,9 @@ index_merge(const struct of *of, struct mparse *mp, while (0 == (*files->seq)(files, &key, &val, seq)) { seq = R_NEXT; if (val.size) - fprintf(stderr, "%s: probably " - "unreachable, title is %s\n", - (char *)val.data, (char *)key.data); + WARNING((char *)val.data, basedir, + "Probably unreachable, title " + "is %s", (char *)key.data); } (*files->close)(files); } @@ -828,7 +837,7 @@ index_merge(const struct of *of, struct mparse *mp, * in `idx' (zeroing its value size). */ static void -index_prune(const struct of *ofile, struct mdb *mdb, +index_prune(const struct of *ofile, struct mdb *mdb, struct recs *recs, const char *basedir) { const struct of *of; @@ -904,7 +913,7 @@ index_prune(const struct of *ofile, struct mdb *mdb, } if (verb) - printf("%s: Deleting from index: %s\n", + printf("%s: Deleting from index: %s\n", basedir, fn); val.size = 0; @@ -1314,8 +1323,8 @@ static int pman_node(MAN_ARGS) { const struct man_node *head, *body; - const char *start, *sv; - size_t sz; + char *start, *sv, *title; + size_t sz, titlesz; if (NULL == n) return(0); @@ -1338,9 +1347,55 @@ pman_node(MAN_ARGS) NULL != (body = body->child) && MAN_TEXT == body->type) { - assert(body->string); - start = sv = body->string; + title = NULL; + titlesz = 0; + /* + * Suck the entire NAME section into memory. + * Yes, we might run away. + * But too many manuals have big, spread-out + * NAME sections over many lines. + */ + for ( ; NULL != body; body = body->next) { + if (MAN_TEXT != body->type) + break; + if (0 == (sz = strlen(body->string))) + continue; + title = mandoc_realloc + (title, titlesz + sz + 1); + memcpy(title + titlesz, body->string, sz); + titlesz += sz + 1; + title[(int)titlesz - 1] = ' '; + } + if (NULL == title) + return(0); + title = mandoc_realloc(title, titlesz + 1); + title[(int)titlesz] = '\0'; + + /* Skip leading space. */ + + sv = title; + while (isspace((unsigned char)*sv)) + sv++; + + if (0 == (sz = strlen(sv))) { + free(title); + return(0); + } + + /* Erase trailing space. */ + + start = &sv[sz - 1]; + while (start > sv && isspace((unsigned char)*start)) + *start-- = '\0'; + + if (start == sv) { + free(title); + return(0); + } + + start = sv; + /* * Go through a special heuristic dance here. * This is why -man manuals are great! @@ -1377,10 +1432,11 @@ pman_node(MAN_ARGS) if (sv == start) { buf_append(buf, start); + free(title); return(1); } - while (' ' == *start) + while (isspace((unsigned char)*start)) start++; if (0 == strncmp(start, "-", 1)) @@ -1402,6 +1458,7 @@ pman_node(MAN_ARGS) buf_appendb(buf, start, sz); hash_put(hash, buf, TYPE_Nd); + free(title); } } @@ -1425,8 +1482,7 @@ pformatted(DB *hash, struct buf *buf, struct buf *dbuf size_t len, plen, titlesz; if (NULL == (stream = fopen(of->fname, "r"))) { - if (warnings) - perror(of->fname); + WARNING(of->fname, basedir, "%s", strerror(errno)); return; } @@ -1481,7 +1537,6 @@ pformatted(DB *hash, struct buf *buf, struct buf *dbuf title[(int)titlesz - 1] = ' '; } - /* * If no page content can be found, or the input line * is already the next section header, or there is no @@ -1490,9 +1545,8 @@ pformatted(DB *hash, struct buf *buf, struct buf *dbuf */ if (NULL == title || '\0' == *title) { - if (warnings) - fprintf(stderr, "%s: Cannot find NAME " - "section: %s\n", basedir, of->fname); + WARNING(of->fname, basedir, + "Cannot find NAME section"); buf_appendb(dbuf, buf->cp, buf->size); hash_put(hash, buf, TYPE_Nd); fclose(stream); @@ -1513,9 +1567,8 @@ pformatted(DB *hash, struct buf *buf, struct buf *dbuf for (p += 2; ' ' == *p || '\b' == *p; p++) /* Skip to next word. */ ; } else { - if (warnings) - fprintf(stderr, "%s/%s: No dash in " - "title line\n", basedir, of->fname); + WARNING(of->fname, basedir, + "No dash in title line"); p = title; } @@ -1545,7 +1598,7 @@ static void ofile_argbuild(int argc, char *argv[], struct of **of, const char *basedir) { - char buf[MAXPATHLEN]; + char buf[PATH_MAX]; const char *sec, *arch, *title; char *p; int i, src_form; @@ -1593,10 +1646,8 @@ ofile_argbuild(int argc, char *argv[], break; } if ('\0' == *title) { - if (warnings) - fprintf(stderr, "%s/%s: Cannot deduce " - "title from filename\n", - basedir, argv[i]); + WARNING(argv[i], basedir, + "Cannot deduce title from filename"); title = buf; } @@ -1636,9 +1687,9 @@ ofile_argbuild(int argc, char *argv[], */ static void ofile_dirbuild(const char *dir, const char* psec, const char *parch, - int p_src_form, struct of **of) + int p_src_form, struct of **of, char *basedir) { - char buf[MAXPATHLEN]; + char buf[PATH_MAX]; size_t sz; DIR *d; const char *fn, *sec, *arch; @@ -1648,8 +1699,7 @@ ofile_dirbuild(const char *dir, const char* psec, cons int src_form; if (NULL == (d = opendir(dir))) { - if (warnings) - perror(dir); + WARNING("", dir, "%s", strerror(errno)); return; } @@ -1679,9 +1729,7 @@ ofile_dirbuild(const char *dir, const char* psec, cons src_form |= MANDOC_FORM; sec = fn + 3; } else { - if (warnings) fprintf(stderr, - "%s/%s: bad section\n", - dir, fn); + WARNING(fn, basedir, "Bad section"); if (use_all) sec = fn; else @@ -1689,49 +1737,45 @@ ofile_dirbuild(const char *dir, const char* psec, cons } } else if ('\0' == *arch) { if (NULL != strchr(fn, '.')) { - if (warnings) fprintf(stderr, - "%s/%s: bad architecture\n", - dir, fn); + WARNING(fn, basedir, "Bad architecture"); if (0 == use_all) continue; } arch = fn; } else { - if (warnings) fprintf(stderr, "%s/%s: " - "excessive subdirectory\n", dir, fn); + WARNING(fn, basedir, "Excessive subdirectory"); if (0 == use_all) continue; } buf[0] = '\0'; - strlcat(buf, dir, MAXPATHLEN); - strlcat(buf, "/", MAXPATHLEN); - sz = strlcat(buf, fn, MAXPATHLEN); + strlcat(buf, dir, PATH_MAX); + strlcat(buf, "/", PATH_MAX); + strlcat(basedir, "/", PATH_MAX); + strlcat(basedir, fn, PATH_MAX); + sz = strlcat(buf, fn, PATH_MAX); - if (MAXPATHLEN <= sz) { - if (warnings) fprintf(stderr, "%s/%s: " - "path too long\n", dir, fn); + if (PATH_MAX <= sz) { + WARNING(fn, basedir, "Path too long"); continue; } - ofile_dirbuild(buf, sec, arch, src_form, of); + ofile_dirbuild(buf, sec, arch, + src_form, of, basedir); + + p = strrchr(basedir, '/'); + *p = '\0'; continue; } if (DT_REG != dp->d_type) { - if (warnings) - fprintf(stderr, - "%s/%s: not a regular file\n", - dir, fn); + WARNING(fn, basedir, "Not a regular file"); continue; } if (!strcmp(MANDOC_DB, fn) || !strcmp(MANDOC_IDX, fn)) continue; if ('\0' == *psec) { - if (warnings) - fprintf(stderr, - "%s/%s: file outside section\n", - dir, fn); + WARNING(fn, basedir, "File outside section"); if (0 == use_all) continue; } @@ -1744,20 +1788,14 @@ ofile_dirbuild(const char *dir, const char* psec, cons suffix = strrchr(fn, '.'); if (NULL == suffix) { - if (warnings) - fprintf(stderr, - "%s/%s: no filename suffix\n", - dir, fn); + WARNING(fn, basedir, "No filename suffix"); if (0 == use_all) continue; } else if ((MANDOC_SRC & src_form && strcmp(suffix + 1, psec)) || (MANDOC_FORM & src_form && strcmp(suffix + 1, "0"))) { - if (warnings) - fprintf(stderr, - "%s/%s: wrong filename suffix\n", - dir, fn); + WARNING(fn, basedir, "Wrong filename suffix"); if (0 == use_all) continue; if ('0' == suffix[1]) @@ -1776,7 +1814,7 @@ ofile_dirbuild(const char *dir, const char* psec, cons if (0 == use_all && MANDOC_FORM & src_form && '\0' != *psec) { buf[0] = '\0'; - strlcat(buf, dir, MAXPATHLEN); + strlcat(buf, dir, PATH_MAX); p = strrchr(buf, '/'); if ('\0' != *parch && NULL != p) for (p--; p > buf; p--) @@ -1788,22 +1826,18 @@ ofile_dirbuild(const char *dir, const char* psec, cons p++; if (0 == strncmp("cat", p, 3)) memcpy(p, "man", 3); - strlcat(buf, "/", MAXPATHLEN); - sz = strlcat(buf, fn, MAXPATHLEN); - if (sz >= MAXPATHLEN) { - if (warnings) fprintf(stderr, - "%s/%s: path too long\n", - dir, fn); + strlcat(buf, "/", PATH_MAX); + sz = strlcat(buf, fn, PATH_MAX); + if (sz >= PATH_MAX) { + WARNING(fn, basedir, "Path too long"); continue; } q = strrchr(buf, '.'); if (NULL != q && p < q++) { *q = '\0'; - sz = strlcat(buf, psec, MAXPATHLEN); - if (sz >= MAXPATHLEN) { - if (warnings) fprintf(stderr, - "%s/%s: path too long\n", - dir, fn); + sz = strlcat(buf, psec, PATH_MAX); + if (sz >= PATH_MAX) { + WARNING(fn, basedir, "Path too long"); continue; } if (0 == access(buf, R_OK)) @@ -1814,13 +1848,12 @@ ofile_dirbuild(const char *dir, const char* psec, cons buf[0] = '\0'; assert('.' == dir[0]); if ('/' == dir[1]) { - strlcat(buf, dir + 2, MAXPATHLEN); - strlcat(buf, "/", MAXPATHLEN); + strlcat(buf, dir + 2, PATH_MAX); + strlcat(buf, "/", PATH_MAX); } - sz = strlcat(buf, fn, MAXPATHLEN); - if (sz >= MAXPATHLEN) { - if (warnings) fprintf(stderr, - "%s/%s: path too long\n", dir, fn); + sz = strlcat(buf, fn, PATH_MAX); + if (sz >= PATH_MAX) { + WARNING(fn, basedir, "Path too long"); continue; }