=================================================================== RCS file: /cvs/mandoc/mandocdb.c,v retrieving revision 1.202 retrieving revision 1.220.2.12 diff -u -p -r1.202 -r1.220.2.12 --- mandoc/mandocdb.c 2015/10/13 15:53:05 1.202 +++ mandoc/mandocdb.c 2017/02/17 14:50:13 1.220.2.12 @@ -1,7 +1,8 @@ -/* $Id: mandocdb.c,v 1.202 2015/10/13 15:53:05 schwarze Exp $ */ +/* $Id: mandocdb.c,v 1.220.2.12 2017/02/17 14:50:13 schwarze Exp $ */ /* * Copyright (c) 2011, 2012 Kristaps Dzonsons - * Copyright (c) 2011-2015 Ingo Schwarze + * Copyright (c) 2011-2017 Ingo Schwarze + * Copyright (c) 2016 Ed Maste * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -23,7 +24,9 @@ #include #include +#if HAVE_ERR #include +#endif #include #include #if HAVE_FTS @@ -31,8 +34,10 @@ #else #include "compat_fts.h" #endif -#include #include +#if HAVE_SANDBOX_INIT +#include +#endif #include #include #include @@ -99,6 +104,7 @@ struct mpage { char *arch; /* architecture from file content */ char *title; /* title from file content */ char *desc; /* description from file content */ + struct mpage *next; /* singly linked list */ struct mlink *mlinks; /* singly linked list */ int form; /* format from file content */ int name_head_done; @@ -133,8 +139,12 @@ typedef int (*mdoc_fp)(struct mpage *, const struct ro struct mdoc_handler { mdoc_fp fp; /* optional handler */ uint64_t mask; /* set unless handler returns 0 */ + int taboo; /* node flags that must not be set */ }; + +int mandocdb(int, char *[]); + static void dbclose(int); static void dbadd(struct mpage *); static void dbadd_mlink(const struct mlink *mlink); @@ -142,6 +152,11 @@ static void dbadd_mlink_name(const struct mlink *mlin static int dbopen(int); static void dbprune(void); static void filescan(const char *); +#if HAVE_FTS_COMPARE_CONST +static int fts_compare(const FTSENT *const *, const FTSENT *const *); +#else +static int fts_compare(const FTSENT **, const FTSENT **); +#endif static void mlink_add(struct mlink *, const struct stat *); static void mlink_check(struct mpage *, struct mlink *); static void mlink_free(struct mlink *); @@ -154,8 +169,6 @@ static void parse_man(struct mpage *, const struct ro const struct roff_node *); static void parse_mdoc(struct mpage *, const struct roff_meta *, const struct roff_node *); -static int parse_mdoc_body(struct mpage *, const struct roff_meta *, - const struct roff_node *); static int parse_mdoc_head(struct mpage *, const struct roff_meta *, const struct roff_node *); static int parse_mdoc_Fd(struct mpage *, const struct roff_meta *, @@ -171,20 +184,21 @@ static int parse_mdoc_Nm(struct mpage *, const struct const struct roff_node *); static int parse_mdoc_Sh(struct mpage *, const struct roff_meta *, const struct roff_node *); +static int parse_mdoc_Va(struct mpage *, const struct roff_meta *, + const struct roff_node *); static int parse_mdoc_Xr(struct mpage *, const struct roff_meta *, const struct roff_node *); static void putkey(const struct mpage *, char *, uint64_t); static void putkeys(const struct mpage *, char *, size_t, uint64_t); static void putmdockey(const struct mpage *, - const struct roff_node *, uint64_t); + const struct roff_node *, uint64_t, int); static int render_string(char **, size_t *); -static void say(const char *, const char *, ...); +static void say(const char *, const char *, ...) + __attribute__((__format__ (__printf__, 2, 3))); static int set_basedir(const char *, int); static int treescan(void); static size_t utf8(unsigned int, char [7]); -extern char *__progname; - static char tempfilename[32]; static int nodb; /* no database changes */ static int mparse_options; /* abort the parse early */ @@ -195,7 +209,7 @@ static int write_utf8; /* write UTF-8 output; else A static int exitcode; /* to be returned by main */ static enum op op; /* operational mode */ static char basedir[PATH_MAX]; /* current base directory */ -static struct mchars *mchars; /* table of named characters */ +static struct mpage *mpage_head; /* list of distinct manual pages */ static struct ohash mpages; /* table of distinct manual pages */ static struct ohash mlinks; /* table of directory entries */ static struct ohash names; /* table of all names */ @@ -205,129 +219,129 @@ static sqlite3_stmt *stmts[STMT__MAX]; /* current stat static uint64_t name_mask; static const struct mdoc_handler mdocs[MDOC_MAX] = { - { NULL, 0 }, /* Ap */ - { NULL, 0 }, /* Dd */ - { NULL, 0 }, /* Dt */ - { NULL, 0 }, /* Os */ - { parse_mdoc_Sh, TYPE_Sh }, /* Sh */ - { parse_mdoc_head, TYPE_Ss }, /* Ss */ - { NULL, 0 }, /* Pp */ - { NULL, 0 }, /* D1 */ - { NULL, 0 }, /* Dl */ - { NULL, 0 }, /* Bd */ - { NULL, 0 }, /* Ed */ - { NULL, 0 }, /* Bl */ - { NULL, 0 }, /* El */ - { NULL, 0 }, /* It */ - { NULL, 0 }, /* Ad */ - { NULL, TYPE_An }, /* An */ - { NULL, TYPE_Ar }, /* Ar */ - { NULL, TYPE_Cd }, /* Cd */ - { NULL, TYPE_Cm }, /* Cm */ - { NULL, TYPE_Dv }, /* Dv */ - { NULL, TYPE_Er }, /* Er */ - { NULL, TYPE_Ev }, /* Ev */ - { NULL, 0 }, /* Ex */ - { NULL, TYPE_Fa }, /* Fa */ - { parse_mdoc_Fd, 0 }, /* Fd */ - { NULL, TYPE_Fl }, /* Fl */ - { parse_mdoc_Fn, 0 }, /* Fn */ - { NULL, TYPE_Ft }, /* Ft */ - { NULL, TYPE_Ic }, /* Ic */ - { NULL, TYPE_In }, /* In */ - { NULL, TYPE_Li }, /* Li */ - { parse_mdoc_Nd, 0 }, /* Nd */ - { parse_mdoc_Nm, 0 }, /* Nm */ - { NULL, 0 }, /* Op */ - { NULL, 0 }, /* Ot */ - { NULL, TYPE_Pa }, /* Pa */ - { NULL, 0 }, /* Rv */ - { NULL, TYPE_St }, /* St */ - { NULL, TYPE_Va }, /* Va */ - { parse_mdoc_body, TYPE_Va }, /* Vt */ - { parse_mdoc_Xr, 0 }, /* Xr */ - { NULL, 0 }, /* %A */ - { NULL, 0 }, /* %B */ - { NULL, 0 }, /* %D */ - { NULL, 0 }, /* %I */ - { NULL, 0 }, /* %J */ - { NULL, 0 }, /* %N */ - { NULL, 0 }, /* %O */ - { NULL, 0 }, /* %P */ - { NULL, 0 }, /* %R */ - { NULL, 0 }, /* %T */ - { NULL, 0 }, /* %V */ - { NULL, 0 }, /* Ac */ - { NULL, 0 }, /* Ao */ - { NULL, 0 }, /* Aq */ - { NULL, TYPE_At }, /* At */ - { NULL, 0 }, /* Bc */ - { NULL, 0 }, /* Bf */ - { NULL, 0 }, /* Bo */ - { NULL, 0 }, /* Bq */ - { NULL, TYPE_Bsx }, /* Bsx */ - { NULL, TYPE_Bx }, /* Bx */ - { NULL, 0 }, /* Db */ - { NULL, 0 }, /* Dc */ - { NULL, 0 }, /* Do */ - { NULL, 0 }, /* Dq */ - { NULL, 0 }, /* Ec */ - { NULL, 0 }, /* Ef */ - { NULL, TYPE_Em }, /* Em */ - { NULL, 0 }, /* Eo */ - { NULL, TYPE_Fx }, /* Fx */ - { NULL, TYPE_Ms }, /* Ms */ - { NULL, 0 }, /* No */ - { NULL, 0 }, /* Ns */ - { NULL, TYPE_Nx }, /* Nx */ - { NULL, TYPE_Ox }, /* Ox */ - { NULL, 0 }, /* Pc */ - { NULL, 0 }, /* Pf */ - { NULL, 0 }, /* Po */ - { NULL, 0 }, /* Pq */ - { NULL, 0 }, /* Qc */ - { NULL, 0 }, /* Ql */ - { NULL, 0 }, /* Qo */ - { NULL, 0 }, /* Qq */ - { NULL, 0 }, /* Re */ - { NULL, 0 }, /* Rs */ - { NULL, 0 }, /* Sc */ - { NULL, 0 }, /* So */ - { NULL, 0 }, /* Sq */ - { NULL, 0 }, /* Sm */ - { NULL, 0 }, /* Sx */ - { NULL, TYPE_Sy }, /* Sy */ - { NULL, TYPE_Tn }, /* Tn */ - { NULL, 0 }, /* Ux */ - { NULL, 0 }, /* Xc */ - { NULL, 0 }, /* Xo */ - { parse_mdoc_Fo, 0 }, /* Fo */ - { NULL, 0 }, /* Fc */ - { NULL, 0 }, /* Oo */ - { NULL, 0 }, /* Oc */ - { NULL, 0 }, /* Bk */ - { NULL, 0 }, /* Ek */ - { NULL, 0 }, /* Bt */ - { NULL, 0 }, /* Hf */ - { NULL, 0 }, /* Fr */ - { NULL, 0 }, /* Ud */ - { NULL, TYPE_Lb }, /* Lb */ - { NULL, 0 }, /* Lp */ - { NULL, TYPE_Lk }, /* Lk */ - { NULL, TYPE_Mt }, /* Mt */ - { NULL, 0 }, /* Brq */ - { NULL, 0 }, /* Bro */ - { NULL, 0 }, /* Brc */ - { NULL, 0 }, /* %C */ - { NULL, 0 }, /* Es */ - { NULL, 0 }, /* En */ - { NULL, TYPE_Dx }, /* Dx */ - { NULL, 0 }, /* %Q */ - { NULL, 0 }, /* br */ - { NULL, 0 }, /* sp */ - { NULL, 0 }, /* %U */ - { NULL, 0 }, /* Ta */ - { NULL, 0 }, /* ll */ + { NULL, 0, 0 }, /* Ap */ + { NULL, 0, NODE_NOPRT }, /* Dd */ + { NULL, 0, NODE_NOPRT }, /* Dt */ + { NULL, 0, NODE_NOPRT }, /* Os */ + { parse_mdoc_Sh, TYPE_Sh, 0 }, /* Sh */ + { parse_mdoc_head, TYPE_Ss, 0 }, /* Ss */ + { NULL, 0, 0 }, /* Pp */ + { NULL, 0, 0 }, /* D1 */ + { NULL, 0, 0 }, /* Dl */ + { NULL, 0, 0 }, /* Bd */ + { NULL, 0, 0 }, /* Ed */ + { NULL, 0, 0 }, /* Bl */ + { NULL, 0, 0 }, /* El */ + { NULL, 0, 0 }, /* It */ + { NULL, 0, 0 }, /* Ad */ + { NULL, TYPE_An, 0 }, /* An */ + { NULL, TYPE_Ar, 0 }, /* Ar */ + { NULL, TYPE_Cd, 0 }, /* Cd */ + { NULL, TYPE_Cm, 0 }, /* Cm */ + { NULL, TYPE_Dv, 0 }, /* Dv */ + { NULL, TYPE_Er, 0 }, /* Er */ + { NULL, TYPE_Ev, 0 }, /* Ev */ + { NULL, 0, 0 }, /* Ex */ + { NULL, TYPE_Fa, 0 }, /* Fa */ + { parse_mdoc_Fd, 0, 0 }, /* Fd */ + { NULL, TYPE_Fl, 0 }, /* Fl */ + { parse_mdoc_Fn, 0, 0 }, /* Fn */ + { NULL, TYPE_Ft, 0 }, /* Ft */ + { NULL, TYPE_Ic, 0 }, /* Ic */ + { NULL, TYPE_In, 0 }, /* In */ + { NULL, TYPE_Li, 0 }, /* Li */ + { parse_mdoc_Nd, 0, 0 }, /* Nd */ + { parse_mdoc_Nm, 0, 0 }, /* Nm */ + { NULL, 0, 0 }, /* Op */ + { NULL, 0, 0 }, /* Ot */ + { NULL, TYPE_Pa, NODE_NOSRC }, /* Pa */ + { NULL, 0, 0 }, /* Rv */ + { NULL, TYPE_St, 0 }, /* St */ + { parse_mdoc_Va, TYPE_Va, 0 }, /* Va */ + { parse_mdoc_Va, TYPE_Vt, 0 }, /* Vt */ + { parse_mdoc_Xr, 0, 0 }, /* Xr */ + { NULL, 0, 0 }, /* %A */ + { NULL, 0, 0 }, /* %B */ + { NULL, 0, 0 }, /* %D */ + { NULL, 0, 0 }, /* %I */ + { NULL, 0, 0 }, /* %J */ + { NULL, 0, 0 }, /* %N */ + { NULL, 0, 0 }, /* %O */ + { NULL, 0, 0 }, /* %P */ + { NULL, 0, 0 }, /* %R */ + { NULL, 0, 0 }, /* %T */ + { NULL, 0, 0 }, /* %V */ + { NULL, 0, 0 }, /* Ac */ + { NULL, 0, 0 }, /* Ao */ + { NULL, 0, 0 }, /* Aq */ + { NULL, TYPE_At, 0 }, /* At */ + { NULL, 0, 0 }, /* Bc */ + { NULL, 0, 0 }, /* Bf */ + { NULL, 0, 0 }, /* Bo */ + { NULL, 0, 0 }, /* Bq */ + { NULL, TYPE_Bsx, NODE_NOSRC }, /* Bsx */ + { NULL, TYPE_Bx, NODE_NOSRC }, /* Bx */ + { NULL, 0, 0 }, /* Db */ + { NULL, 0, 0 }, /* Dc */ + { NULL, 0, 0 }, /* Do */ + { NULL, 0, 0 }, /* Dq */ + { NULL, 0, 0 }, /* Ec */ + { NULL, 0, 0 }, /* Ef */ + { NULL, TYPE_Em, 0 }, /* Em */ + { NULL, 0, 0 }, /* Eo */ + { NULL, TYPE_Fx, NODE_NOSRC }, /* Fx */ + { NULL, TYPE_Ms, 0 }, /* Ms */ + { NULL, 0, 0 }, /* No */ + { NULL, 0, 0 }, /* Ns */ + { NULL, TYPE_Nx, NODE_NOSRC }, /* Nx */ + { NULL, TYPE_Ox, NODE_NOSRC }, /* Ox */ + { NULL, 0, 0 }, /* Pc */ + { NULL, 0, 0 }, /* Pf */ + { NULL, 0, 0 }, /* Po */ + { NULL, 0, 0 }, /* Pq */ + { NULL, 0, 0 }, /* Qc */ + { NULL, 0, 0 }, /* Ql */ + { NULL, 0, 0 }, /* Qo */ + { NULL, 0, 0 }, /* Qq */ + { NULL, 0, 0 }, /* Re */ + { NULL, 0, 0 }, /* Rs */ + { NULL, 0, 0 }, /* Sc */ + { NULL, 0, 0 }, /* So */ + { NULL, 0, 0 }, /* Sq */ + { NULL, 0, 0 }, /* Sm */ + { NULL, 0, 0 }, /* Sx */ + { NULL, TYPE_Sy, 0 }, /* Sy */ + { NULL, TYPE_Tn, 0 }, /* Tn */ + { NULL, 0, NODE_NOSRC }, /* Ux */ + { NULL, 0, 0 }, /* Xc */ + { NULL, 0, 0 }, /* Xo */ + { parse_mdoc_Fo, 0, 0 }, /* Fo */ + { NULL, 0, 0 }, /* Fc */ + { NULL, 0, 0 }, /* Oo */ + { NULL, 0, 0 }, /* Oc */ + { NULL, 0, 0 }, /* Bk */ + { NULL, 0, 0 }, /* Ek */ + { NULL, 0, 0 }, /* Bt */ + { NULL, 0, 0 }, /* Hf */ + { NULL, 0, 0 }, /* Fr */ + { NULL, 0, 0 }, /* Ud */ + { NULL, TYPE_Lb, NODE_NOSRC }, /* Lb */ + { NULL, 0, 0 }, /* Lp */ + { NULL, TYPE_Lk, 0 }, /* Lk */ + { NULL, TYPE_Mt, NODE_NOSRC }, /* Mt */ + { NULL, 0, 0 }, /* Brq */ + { NULL, 0, 0 }, /* Bro */ + { NULL, 0, 0 }, /* Brc */ + { NULL, 0, 0 }, /* %C */ + { NULL, 0, 0 }, /* Es */ + { NULL, 0, 0 }, /* En */ + { NULL, TYPE_Dx, NODE_NOSRC }, /* Dx */ + { NULL, 0, 0 }, /* %Q */ + { NULL, 0, 0 }, /* br */ + { NULL, 0, 0 }, /* sp */ + { NULL, 0, 0 }, /* %U */ + { NULL, 0, 0 }, /* Ta */ + { NULL, 0, 0 }, /* ll */ }; @@ -336,10 +350,24 @@ mandocdb(int argc, char *argv[]) { struct manconf conf; struct mparse *mp; - const char *path_arg; + const char *path_arg, *progname; size_t j, sz; int ch, i; +#if HAVE_PLEDGE + if (pledge("stdio rpath wpath cpath fattr flock proc exec", NULL) == -1) { + warn("pledge"); + return (int)MANDOCLEVEL_SYSERR; + } +#endif + +#if HAVE_SANDBOX_INIT + if (sandbox_init(kSBXProfileNoInternet, SANDBOX_NAMED, NULL) == -1) { + warnx("sandbox_init"); + return (int)MANDOCLEVEL_SYSERR; + } +#endif + memset(&conf, 0, sizeof(conf)); memset(stmts, 0, STMT__MAX * sizeof(sqlite3_stmt *)); @@ -413,15 +441,23 @@ mandocdb(int argc, char *argv[]) argc -= optind; argv += optind; +#if HAVE_PLEDGE + if (nodb) { + if (pledge("stdio rpath", NULL) == -1) { + warn("pledge"); + return (int)MANDOCLEVEL_SYSERR; + } + } +#endif + if (OP_CONFFILE == op && argc > 0) { warnx("-C: Too many arguments"); goto usage; } exitcode = (int)MANDOCLEVEL_OK; - mchars = mchars_alloc(); - mp = mparse_alloc(mparse_options, MANDOCLEVEL_BADARG, NULL, - mchars, NULL); + mchars_alloc(); + mp = mparse_alloc(mparse_options, MANDOCLEVEL_BADARG, NULL, NULL); mandoc_ohash_init(&mpages, 6, offsetof(struct mpage, inodev)); mandoc_ohash_init(&mlinks, 6, offsetof(struct mlink, file)); @@ -439,6 +475,15 @@ mandocdb(int argc, char *argv[]) * The existing database is usable. Process * all files specified on the command-line. */ +#if HAVE_PLEDGE + if (!nodb) { + if (pledge("stdio rpath wpath cpath fattr flock", NULL) == -1) { + warn("pledge"); + exitcode = (int)MANDOCLEVEL_SYSERR; + goto out; + } + } +#endif use_all = 1; for (i = 0; i < argc; i++) filescan(argv[i]); @@ -522,24 +567,38 @@ mandocdb(int argc, char *argv[]) out: manconf_free(&conf); mparse_free(mp); - mchars_free(mchars); + mchars_free(); mpages_free(); ohash_delete(&mpages); ohash_delete(&mlinks); return exitcode; usage: + progname = getprogname(); fprintf(stderr, "usage: %s [-aDnpQ] [-C file] [-Tutf8]\n" " %s [-aDnpQ] [-Tutf8] dir ...\n" " %s [-DnpQ] [-Tutf8] -d dir [file ...]\n" " %s [-Dnp] -u dir [file ...]\n" " %s [-Q] -t file ...\n", - __progname, __progname, __progname, - __progname, __progname); + progname, progname, progname, progname, progname); return (int)MANDOCLEVEL_BADARG; } /* + * To get a singly linked list in alpha order while inserting entries + * at the beginning, process directory entries in reverse alpha order. + */ +static int +#if HAVE_FTS_COMPARE_CONST +fts_compare(const FTSENT *const *a, const FTSENT *const *b) +#else +fts_compare(const FTSENT **a, const FTSENT **b) +#endif +{ + return -strcmp((*a)->fts_name, (*b)->fts_name); +} + +/* * Scan a directory tree rooted at "basedir" for manpages. * We use fts(), scanning directory parts along the way for clues to our * section and architecture. @@ -551,7 +610,7 @@ usage: * or * [./]cat
[/]/.0 * - * TODO: accomodate for multi-language directories. + * TODO: accommodate for multi-language directories. */ static int treescan(void) @@ -566,10 +625,10 @@ treescan(void) const char *argv[2]; argv[0] = "."; - argv[1] = (char *)NULL; + argv[1] = NULL; - f = fts_open((char * const *)argv, - FTS_PHYSICAL | FTS_NOCHDIR, NULL); + f = fts_open((char * const *)argv, FTS_PHYSICAL | FTS_NOCHDIR, + fts_compare); if (f == NULL) { exitcode = (int)MANDOCLEVEL_SYSERR; say("", "&fts_open"); @@ -849,6 +908,20 @@ filescan(const char *file) } /* + * In test mode or when the original name is absolute + * but outside our tree, guess the base directory. + */ + + if (op == OP_TEST || (start == buf && *start == '/')) { + if (strncmp(buf, "man/", 4) == 0) + start = buf + 4; + else if ((start = strstr(buf, "/man/")) != NULL) + start += 5; + else + start = buf; + } + + /* * First try to guess our directory structure. * If we find a separator, try to look for man* or cat*. * If we find one of these and what's underneath is a directory, @@ -934,6 +1007,8 @@ mlink_add(struct mlink *mlink, const struct stat *st) mpage = mandoc_calloc(1, sizeof(struct mpage)); mpage->inodev.st_ino = inodev.st_ino; mpage->inodev.st_dev = inodev.st_dev; + mpage->next = mpage_head; + mpage_head = mpage; ohash_insert(&mpages, slot, mpage); } else mlink->next = mpage->mlinks; @@ -957,20 +1032,18 @@ mpages_free(void) { struct mpage *mpage; struct mlink *mlink; - unsigned int slot; - mpage = ohash_first(&mpages, &slot); - while (NULL != mpage) { - while (NULL != (mlink = mpage->mlinks)) { + while ((mpage = mpage_head) != NULL) { + while ((mlink = mpage->mlinks) != NULL) { mpage->mlinks = mlink->next; mlink_free(mlink); } + mpage_head = mpage->next; free(mpage->sec); free(mpage->arch); free(mpage->title); free(mpage->desc); free(mpage); - mpage = ohash_next(&mpages, &slot); } } @@ -1091,18 +1164,14 @@ mpages_merge(struct mparse *mp) char *sodest; char *cp; int fd; - unsigned int pslot; if ( ! nodb) SQL_EXEC("BEGIN TRANSACTION"); - mpage = ohash_first(&mpages, &pslot); - while (mpage != NULL) { + for (mpage = mpage_head; mpage != NULL; mpage = mpage->next) { mlinks_undupe(mpage); - if ((mlink = mpage->mlinks) == NULL) { - mpage = ohash_next(&mpages, &pslot); + if ((mlink = mpage->mlinks) == NULL) continue; - } name_mask = NAME_MASK; mandoc_ohash_init(&names, 4, offsetof(struct str, key)); @@ -1111,8 +1180,7 @@ mpages_merge(struct mparse *mp) man = NULL; sodest = NULL; - mparse_open(mp, &fd, mlink->file); - if (fd == -1) { + if ((fd = mparse_open(mp, mlink->file)) == -1) { say(mlink->file, "&open"); goto nextpage; } @@ -1123,6 +1191,8 @@ mpages_merge(struct mparse *mp) */ if (mlink->dform != FORM_CAT || mlink->fform != FORM_CAT) { mparse_readfd(mp, fd, mlink->file); + close(fd); + fd = -1; mparse_result(mp, &man, &sodest); } @@ -1168,6 +1238,7 @@ mpages_merge(struct mparse *mp) } goto nextpage; } else if (man != NULL && man->macroset == MACROSET_MDOC) { + mdoc_validate(man); mpage->form = FORM_SRC; mpage->sec = man->meta.msec; mpage->sec = mandoc_strdup( @@ -1177,16 +1248,35 @@ mpages_merge(struct mparse *mp) mpage->arch == NULL ? "" : mpage->arch); mpage->title = mandoc_strdup(man->meta.title); } else if (man != NULL && man->macroset == MACROSET_MAN) { - mpage->form = FORM_SRC; - mpage->sec = mandoc_strdup(man->meta.msec); - mpage->arch = mandoc_strdup(mlink->arch); - mpage->title = mandoc_strdup(man->meta.title); - } else { + man_validate(man); + if (*man->meta.msec != '\0' || + *man->meta.msec != '\0') { + mpage->form = FORM_SRC; + mpage->sec = mandoc_strdup(man->meta.msec); + mpage->arch = mandoc_strdup(mlink->arch); + mpage->title = mandoc_strdup(man->meta.title); + } else + man = NULL; + } + + assert(mpage->desc == NULL); + if (man == NULL) { mpage->form = FORM_CAT; mpage->sec = mandoc_strdup(mlink->dsec); mpage->arch = mandoc_strdup(mlink->arch); mpage->title = mandoc_strdup(mlink->name); + parse_cat(mpage, fd); + } else if (man->macroset == MACROSET_MDOC) + parse_mdoc(mpage, &man->meta, man->first); + else + parse_man(mpage, &man->meta, man->first); + if (mpage->desc == NULL) { + mpage->desc = mandoc_strdup(mlink->name); + if (warnings) + say(mlink->file, "No one-line description, " + "using filename \"%s\"", mlink->name); } + putkey(mpage, mpage->sec, TYPE_sec); if (*mpage->arch != '\0') putkey(mpage, mpage->arch, TYPE_arch); @@ -1201,28 +1291,16 @@ mpages_merge(struct mparse *mp) putkey(mpage, mlink->name, NAME_FILE); } - assert(mpage->desc == NULL); - if (man != NULL && man->macroset == MACROSET_MDOC) - parse_mdoc(mpage, &man->meta, man->first); - else if (man != NULL) - parse_man(mpage, &man->meta, man->first); - else - parse_cat(mpage, fd); - if (mpage->desc == NULL) - mpage->desc = mandoc_strdup(mpage->mlinks->name); - if (warnings && !use_all) for (mlink = mpage->mlinks; mlink; mlink = mlink->next) mlink_check(mpage, mlink); dbadd(mpage); - mlink = mpage->mlinks; nextpage: ohash_delete(&strings); ohash_delete(&names); - mpage = ohash_next(&mpages, &pslot); } if (0 == nodb) @@ -1268,24 +1346,48 @@ static void parse_cat(struct mpage *mpage, int fd) { FILE *stream; - char *line, *p, *title; - size_t len, plen, titlesz; + struct mlink *mlink; + char *line, *p, *title, *sec; + size_t linesz, plen, titlesz; + ssize_t len; + int offs; - stream = (-1 == fd) ? - fopen(mpage->mlinks->file, "r") : - fdopen(fd, "r"); - if (NULL == stream) { - if (-1 != fd) + mlink = mpage->mlinks; + stream = fd == -1 ? fopen(mlink->file, "r") : fdopen(fd, "r"); + if (stream == NULL) { + if (fd != -1) close(fd); if (warnings) - say(mpage->mlinks->file, "&fopen"); + say(mlink->file, "&fopen"); return; } + line = NULL; + linesz = 0; + + /* Parse the section number from the header line. */ + + while (getline(&line, &linesz, stream) != -1) { + if (*line == '\n') + continue; + if ((sec = strchr(line, '(')) == NULL) + break; + if ((p = strchr(++sec, ')')) == NULL) + break; + free(mpage->sec); + mpage->sec = mandoc_strndup(sec, p - sec); + if (warnings && *mlink->dsec != '\0' && + strcasecmp(mpage->sec, mlink->dsec)) + say(mlink->file, + "Section \"%s\" manual in %s directory", + mpage->sec, mlink->dsec); + break; + } + /* Skip to first blank line. */ - while (NULL != (line = fgetln(stream, &len))) - if ('\n' == *line) + while (line == NULL || *line != '\n') + if (getline(&line, &linesz, stream) == -1) break; /* @@ -1293,8 +1395,8 @@ parse_cat(struct mpage *mpage, int fd) * is the first section header. Skip to it. */ - while (NULL != (line = fgetln(stream, &len))) - if ('\n' != *line && ' ' != *line) + while (getline(&line, &linesz, stream) != -1) + if (*line != '\n' && *line != ' ') break; /* @@ -1307,20 +1409,20 @@ parse_cat(struct mpage *mpage, int fd) titlesz = 0; title = NULL; - while (NULL != (line = fgetln(stream, &len))) { - if (' ' != *line || '\n' != line[len - 1]) + while ((len = getline(&line, &linesz, stream)) != -1) { + if (*line != ' ') break; - while (len > 0 && isspace((unsigned char)*line)) { - line++; - len--; - } - if (1 == len) + offs = 0; + while (isspace((unsigned char)line[offs])) + offs++; + if (line[offs] == '\0') continue; - title = mandoc_realloc(title, titlesz + len); - memcpy(title + titlesz, line, len); - titlesz += len; + title = mandoc_realloc(title, titlesz + len - offs); + memcpy(title + titlesz, line + offs, len - offs); + titlesz += len - offs; title[titlesz - 1] = ' '; } + free(line); /* * If no page content can be found, or the input line @@ -1331,15 +1433,13 @@ parse_cat(struct mpage *mpage, int fd) if (NULL == title || '\0' == *title) { if (warnings) - say(mpage->mlinks->file, - "Cannot find NAME section"); + say(mlink->file, "Cannot find NAME section"); fclose(stream); free(title); return; } - title = mandoc_realloc(title, titlesz + 1); - title[titlesz] = '\0'; + title[titlesz - 1] = '\0'; /* * Skip to the first dash. @@ -1352,8 +1452,8 @@ parse_cat(struct mpage *mpage, int fd) /* Skip to next word. */ ; } else { if (warnings) - say(mpage->mlinks->file, - "No dash in title line"); + say(mlink->file, "No dash in title line, " + "reusing \"%s\" as one-line description", title); p = title; } @@ -1397,12 +1497,14 @@ putkey(const struct mpage *mpage, char *value, uint64_ */ static void putmdockey(const struct mpage *mpage, - const struct roff_node *n, uint64_t m) + const struct roff_node *n, uint64_t m, int taboo) { for ( ; NULL != n; n = n->next) { + if (n->flags & taboo) + continue; if (NULL != n->child) - putmdockey(mpage, n->child, m); + putmdockey(mpage, n->child, m, taboo); if (n->type == ROFFT_TEXT) putkey(mpage, n->string, m); } @@ -1417,7 +1519,7 @@ parse_man(struct mpage *mpage, const struct roff_meta char byte; size_t sz; - if (NULL == n) + if (n == NULL) return; /* @@ -1429,13 +1531,12 @@ parse_man(struct mpage *mpage, const struct roff_meta if (n->type == ROFFT_BODY && n->tok == MAN_SH) { body = n; - assert(body->parent); - if (NULL != (head = body->parent->head) && - 1 == head->nchild && - NULL != (head = (head->child)) && + if ((head = body->parent->head) != NULL && + (head = head->child) != NULL && + head->next == NULL && head->type == ROFFT_TEXT && - 0 == strcmp(head->string, "NAME") && - NULL != body->child) { + strcmp(head->string, "NAME") == 0 && + body->child != NULL) { /* * Suck the entire NAME section into memory. @@ -1541,6 +1642,8 @@ parse_mdoc(struct mpage *mpage, const struct roff_meta assert(NULL != n); for (n = n->child; NULL != n; n = n->next) { + if (n->flags & mdocs[n->tok].taboo) + continue; switch (n->type) { case ROFFT_ELEM: case ROFFT_BLOCK: @@ -1552,7 +1655,7 @@ parse_mdoc(struct mpage *mpage, const struct roff_meta break; if (mdocs[n->tok].mask) putmdockey(mpage, n->child, - mdocs[n->tok].mask); + mdocs[n->tok].mask, mdocs[n->tok].taboo); break; default: assert(n->type != ROFFT_ROOT); @@ -1660,6 +1763,31 @@ parse_mdoc_Fo(struct mpage *mpage, const struct roff_m } static int +parse_mdoc_Va(struct mpage *mpage, const struct roff_meta *meta, + const struct roff_node *n) +{ + char *cp; + + if (n->type != ROFFT_ELEM && n->type != ROFFT_BODY) + return 0; + + if (n->child != NULL && + n->child->next == NULL && + n->child->type == ROFFT_TEXT) + return 1; + + cp = NULL; + deroff(&cp, n); + if (cp != NULL) { + putkey(mpage, cp, TYPE_Vt | (n->tok == MDOC_Va || + n->type == ROFFT_BODY ? TYPE_Va : 0)); + free(cp); + } + + return 0; +} + +static int parse_mdoc_Xr(struct mpage *mpage, const struct roff_meta *meta, const struct roff_node *n) { @@ -1695,17 +1823,17 @@ parse_mdoc_Nm(struct mpage *mpage, const struct roff_m { if (SEC_NAME == n->sec) - putmdockey(mpage, n->child, NAME_TITLE); + putmdockey(mpage, n->child, NAME_TITLE, 0); else if (n->sec == SEC_SYNOPSIS && n->type == ROFFT_HEAD) { if (n->child == NULL) putkey(mpage, meta->name, NAME_SYN); else - putmdockey(mpage, n->child, NAME_SYN); + putmdockey(mpage, n->child, NAME_SYN, 0); } if ( ! (mpage->name_head_done || n->child == NULL || n->child->string == NULL || strcasecmp(n->child->string, meta->title))) { - putkey(mpage, n->child->string, ROFFT_HEAD); + putkey(mpage, n->child->string, NAME_HEAD); mpage->name_head_done = 1; } return 0; @@ -1727,14 +1855,6 @@ parse_mdoc_head(struct mpage *mpage, const struct roff return n->type == ROFFT_HEAD; } -static int -parse_mdoc_body(struct mpage *mpage, const struct roff_meta *meta, - const struct roff_node *n) -{ - - return n->type == ROFFT_BODY; -} - /* * Add a string to the hash table for the current manual. * Each string has a bitmask telling which macros it belongs to. @@ -1761,7 +1881,8 @@ putkeys(const struct mpage *mpage, char *cp, size_t sz name_mask &= ~NAME_FIRST; if (debug > 1) say(mpage->mlinks->file, - "Adding name %*s, bits=%d", sz, cp, v); + "Adding name %*s, bits=0x%llx", (int)sz, cp, + (unsigned long long)v); } else { htab = &strings; if (debug > 1) @@ -1769,7 +1890,7 @@ putkeys(const struct mpage *mpage, char *cp, size_t sz if ((uint64_t)1 << i & v) say(mpage->mlinks->file, "Adding key %s=%*s", - mansearch_keynames[i], sz, cp); + mansearch_keynames[i], (int)sz, cp); } end = cp + sz; @@ -1928,7 +2049,7 @@ render_string(char **public, size_t *psz) */ if (write_utf8) { - unicode = mchars_spec2cp(mchars, seq, seqlen); + unicode = mchars_spec2cp(seq, seqlen); if (unicode <= 0) continue; addsz = utf8(unicode, utfbuf); @@ -1936,7 +2057,7 @@ render_string(char **public, size_t *psz) continue; addcp = utfbuf; } else { - addcp = mchars_spec2str(mchars, seq, seqlen, &addsz); + addcp = mchars_spec2str(seq, seqlen, &addsz); if (addcp == NULL) continue; if (*addcp == ASCII_NBRSP) {