version 1.231, 2016/10/18 14:15:33 |
version 1.261, 2018/12/14 01:18:26 |
|
|
/* $Id$ */ |
/* $Id$ */ |
/* |
/* |
* Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv> |
* Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv> |
* Copyright (c) 2011-2016 Ingo Schwarze <schwarze@openbsd.org> |
* Copyright (c) 2011-2018 Ingo Schwarze <schwarze@openbsd.org> |
* Copyright (c) 2016 Ed Maste <emaste@freebsd.org> |
* Copyright (c) 2016 Ed Maste <emaste@freebsd.org> |
* |
* |
* Permission to use, copy, modify, and distribute this software for any |
* Permission to use, copy, modify, and distribute this software for any |
|
|
#include "config.h" |
#include "config.h" |
|
|
#include <sys/types.h> |
#include <sys/types.h> |
|
#include <sys/mman.h> |
#include <sys/stat.h> |
#include <sys/stat.h> |
#include <sys/wait.h> |
|
|
|
#include <assert.h> |
#include <assert.h> |
#include <ctype.h> |
#include <ctype.h> |
|
|
#include "roff.h" |
#include "roff.h" |
#include "mdoc.h" |
#include "mdoc.h" |
#include "man.h" |
#include "man.h" |
|
#include "mandoc_parse.h" |
#include "manconf.h" |
#include "manconf.h" |
#include "mansearch.h" |
#include "mansearch.h" |
#include "dba_array.h" |
#include "dba_array.h" |
Line 110 typedef int (*mdoc_fp)(struct mpage *, const struct ro |
|
Line 111 typedef int (*mdoc_fp)(struct mpage *, const struct ro |
|
struct mdoc_handler { |
struct mdoc_handler { |
mdoc_fp fp; /* optional handler */ |
mdoc_fp fp; /* optional handler */ |
uint64_t mask; /* set unless handler returns 0 */ |
uint64_t mask; /* set unless handler returns 0 */ |
|
int taboo; /* node flags that must not be set */ |
}; |
}; |
|
|
|
|
Line 120 static void dbadd_mlink(const struct mlink *mlink); |
|
Line 122 static void dbadd_mlink(const struct mlink *mlink); |
|
static void dbprune(struct dba *); |
static void dbprune(struct dba *); |
static void dbwrite(struct dba *); |
static void dbwrite(struct dba *); |
static void filescan(const char *); |
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 **); |
static int fts_compare(const FTSENT **, const FTSENT **); |
|
#endif |
static void mlink_add(struct mlink *, const struct stat *); |
static void mlink_add(struct mlink *, const struct stat *); |
static void mlink_check(struct mpage *, struct mlink *); |
static void mlink_check(struct mpage *, struct mlink *); |
static void mlink_free(struct mlink *); |
static void mlink_free(struct mlink *); |
Line 134 static void parse_mdoc(struct mpage *, const struct r |
|
Line 140 static void parse_mdoc(struct mpage *, const struct r |
|
const struct roff_node *); |
const struct roff_node *); |
static int parse_mdoc_head(struct mpage *, const struct roff_meta *, |
static int parse_mdoc_head(struct mpage *, const struct roff_meta *, |
const struct roff_node *); |
const struct roff_node *); |
|
static int parse_mdoc_Fa(struct mpage *, const struct roff_meta *, |
|
const struct roff_node *); |
static int parse_mdoc_Fd(struct mpage *, const struct roff_meta *, |
static int parse_mdoc_Fd(struct mpage *, const struct roff_meta *, |
const struct roff_node *); |
const struct roff_node *); |
static void parse_mdoc_fname(struct mpage *, const struct roff_node *); |
static void parse_mdoc_fname(struct mpage *, const struct roff_node *); |
Line 154 static int parse_mdoc_Xr(struct mpage *, const struct |
|
Line 162 static int parse_mdoc_Xr(struct mpage *, const struct |
|
static void putkey(const struct mpage *, char *, uint64_t); |
static void putkey(const struct mpage *, char *, uint64_t); |
static void putkeys(const struct mpage *, char *, size_t, uint64_t); |
static void putkeys(const struct mpage *, char *, size_t, uint64_t); |
static void putmdockey(const struct mpage *, |
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 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))); |
__attribute__((__format__ (__printf__, 2, 3))); |
static int set_basedir(const char *, int); |
static int set_basedir(const char *, int); |
static int treescan(void); |
static int treescan(void); |
static size_t utf8(unsigned int, char [7]); |
static size_t utf8(unsigned int, char [7]); |
Line 178 static struct ohash names; /* table of all names */ |
|
Line 186 static struct ohash names; /* table of all names */ |
|
static struct ohash strings; /* table of all strings */ |
static struct ohash strings; /* table of all strings */ |
static uint64_t name_mask; |
static uint64_t name_mask; |
|
|
static const struct mdoc_handler mdocs[MDOC_MAX] = { |
static const struct mdoc_handler mdoc_handlers[MDOC_MAX - MDOC_Dd] = { |
{ NULL, 0 }, /* Ap */ |
{ NULL, 0, NODE_NOPRT }, /* Dd */ |
{ NULL, 0 }, /* Dd */ |
{ NULL, 0, NODE_NOPRT }, /* Dt */ |
{ NULL, 0 }, /* Dt */ |
{ NULL, 0, NODE_NOPRT }, /* Os */ |
{ NULL, 0 }, /* Os */ |
{ parse_mdoc_Sh, TYPE_Sh, 0 }, /* Sh */ |
{ parse_mdoc_Sh, TYPE_Sh }, /* Sh */ |
{ parse_mdoc_head, TYPE_Ss, 0 }, /* Ss */ |
{ parse_mdoc_head, TYPE_Ss }, /* Ss */ |
{ NULL, 0, 0 }, /* Pp */ |
{ NULL, 0 }, /* Pp */ |
{ NULL, 0, 0 }, /* D1 */ |
{ NULL, 0 }, /* D1 */ |
{ NULL, 0, 0 }, /* Dl */ |
{ NULL, 0 }, /* Dl */ |
{ NULL, 0, 0 }, /* Bd */ |
{ NULL, 0 }, /* Bd */ |
{ NULL, 0, 0 }, /* Ed */ |
{ NULL, 0 }, /* Ed */ |
{ NULL, 0, 0 }, /* Bl */ |
{ NULL, 0 }, /* Bl */ |
{ NULL, 0, 0 }, /* El */ |
{ NULL, 0 }, /* El */ |
{ NULL, 0, 0 }, /* It */ |
{ NULL, 0 }, /* It */ |
{ NULL, 0, 0 }, /* Ad */ |
{ NULL, 0 }, /* Ad */ |
{ NULL, TYPE_An, 0 }, /* An */ |
{ NULL, TYPE_An }, /* An */ |
{ NULL, 0, 0 }, /* Ap */ |
{ NULL, TYPE_Ar }, /* Ar */ |
{ NULL, TYPE_Ar, 0 }, /* Ar */ |
{ NULL, TYPE_Cd }, /* Cd */ |
{ NULL, TYPE_Cd, 0 }, /* Cd */ |
{ NULL, TYPE_Cm }, /* Cm */ |
{ NULL, TYPE_Cm, 0 }, /* Cm */ |
{ NULL, TYPE_Dv }, /* Dv */ |
{ NULL, TYPE_Dv, 0 }, /* Dv */ |
{ NULL, TYPE_Er }, /* Er */ |
{ NULL, TYPE_Er, 0 }, /* Er */ |
{ NULL, TYPE_Ev }, /* Ev */ |
{ NULL, TYPE_Ev, 0 }, /* Ev */ |
{ NULL, 0 }, /* Ex */ |
{ NULL, 0, 0 }, /* Ex */ |
{ NULL, TYPE_Fa }, /* Fa */ |
{ parse_mdoc_Fa, 0, 0 }, /* Fa */ |
{ parse_mdoc_Fd, 0 }, /* Fd */ |
{ parse_mdoc_Fd, 0, 0 }, /* Fd */ |
{ NULL, TYPE_Fl }, /* Fl */ |
{ NULL, TYPE_Fl, 0 }, /* Fl */ |
{ parse_mdoc_Fn, 0 }, /* Fn */ |
{ parse_mdoc_Fn, 0, 0 }, /* Fn */ |
{ NULL, TYPE_Ft }, /* Ft */ |
{ NULL, TYPE_Ft | TYPE_Vt, 0 }, /* Ft */ |
{ NULL, TYPE_Ic }, /* Ic */ |
{ NULL, TYPE_Ic, 0 }, /* Ic */ |
{ NULL, TYPE_In }, /* In */ |
{ NULL, TYPE_In, 0 }, /* In */ |
{ NULL, TYPE_Li }, /* Li */ |
{ NULL, TYPE_Li, 0 }, /* Li */ |
{ parse_mdoc_Nd, 0 }, /* Nd */ |
{ parse_mdoc_Nd, 0, 0 }, /* Nd */ |
{ parse_mdoc_Nm, 0 }, /* Nm */ |
{ parse_mdoc_Nm, 0, 0 }, /* Nm */ |
{ NULL, 0 }, /* Op */ |
{ NULL, 0, 0 }, /* Op */ |
{ NULL, 0 }, /* Ot */ |
{ NULL, 0, 0 }, /* Ot */ |
{ NULL, TYPE_Pa }, /* Pa */ |
{ NULL, TYPE_Pa, NODE_NOSRC }, /* Pa */ |
{ NULL, 0 }, /* Rv */ |
{ NULL, 0, 0 }, /* Rv */ |
{ NULL, TYPE_St }, /* St */ |
{ NULL, TYPE_St, 0 }, /* St */ |
{ parse_mdoc_Va, TYPE_Va }, /* Va */ |
{ parse_mdoc_Va, TYPE_Va, 0 }, /* Va */ |
{ parse_mdoc_Va, TYPE_Vt }, /* Vt */ |
{ parse_mdoc_Va, TYPE_Vt, 0 }, /* Vt */ |
{ parse_mdoc_Xr, 0 }, /* Xr */ |
{ parse_mdoc_Xr, 0, 0 }, /* Xr */ |
{ NULL, 0 }, /* %A */ |
{ NULL, 0, 0 }, /* %A */ |
{ NULL, 0 }, /* %B */ |
{ NULL, 0, 0 }, /* %B */ |
{ NULL, 0 }, /* %D */ |
{ NULL, 0, 0 }, /* %D */ |
{ NULL, 0 }, /* %I */ |
{ NULL, 0, 0 }, /* %I */ |
{ NULL, 0 }, /* %J */ |
{ NULL, 0, 0 }, /* %J */ |
{ NULL, 0 }, /* %N */ |
{ NULL, 0, 0 }, /* %N */ |
{ NULL, 0 }, /* %O */ |
{ NULL, 0, 0 }, /* %O */ |
{ NULL, 0 }, /* %P */ |
{ NULL, 0, 0 }, /* %P */ |
{ NULL, 0 }, /* %R */ |
{ NULL, 0, 0 }, /* %R */ |
{ NULL, 0 }, /* %T */ |
{ NULL, 0, 0 }, /* %T */ |
{ NULL, 0 }, /* %V */ |
{ NULL, 0, 0 }, /* %V */ |
{ NULL, 0 }, /* Ac */ |
{ NULL, 0, 0 }, /* Ac */ |
{ NULL, 0 }, /* Ao */ |
{ NULL, 0, 0 }, /* Ao */ |
{ NULL, 0 }, /* Aq */ |
{ NULL, 0, 0 }, /* Aq */ |
{ NULL, TYPE_At }, /* At */ |
{ NULL, TYPE_At, 0 }, /* At */ |
{ NULL, 0 }, /* Bc */ |
{ NULL, 0, 0 }, /* Bc */ |
{ NULL, 0 }, /* Bf */ |
{ NULL, 0, 0 }, /* Bf */ |
{ NULL, 0 }, /* Bo */ |
{ NULL, 0, 0 }, /* Bo */ |
{ NULL, 0 }, /* Bq */ |
{ NULL, 0, 0 }, /* Bq */ |
{ NULL, TYPE_Bsx }, /* Bsx */ |
{ NULL, TYPE_Bsx, NODE_NOSRC }, /* Bsx */ |
{ NULL, TYPE_Bx }, /* Bx */ |
{ NULL, TYPE_Bx, NODE_NOSRC }, /* Bx */ |
{ NULL, 0 }, /* Db */ |
{ NULL, 0, 0 }, /* Db */ |
{ NULL, 0 }, /* Dc */ |
{ NULL, 0, 0 }, /* Dc */ |
{ NULL, 0 }, /* Do */ |
{ NULL, 0, 0 }, /* Do */ |
{ NULL, 0 }, /* Dq */ |
{ NULL, 0, 0 }, /* Dq */ |
{ NULL, 0 }, /* Ec */ |
{ NULL, 0, 0 }, /* Ec */ |
{ NULL, 0 }, /* Ef */ |
{ NULL, 0, 0 }, /* Ef */ |
{ NULL, TYPE_Em }, /* Em */ |
{ NULL, TYPE_Em, 0 }, /* Em */ |
{ NULL, 0 }, /* Eo */ |
{ NULL, 0, 0 }, /* Eo */ |
{ NULL, TYPE_Fx }, /* Fx */ |
{ NULL, TYPE_Fx, NODE_NOSRC }, /* Fx */ |
{ NULL, TYPE_Ms }, /* Ms */ |
{ NULL, TYPE_Ms, 0 }, /* Ms */ |
{ NULL, 0 }, /* No */ |
{ NULL, 0, 0 }, /* No */ |
{ NULL, 0 }, /* Ns */ |
{ NULL, 0, 0 }, /* Ns */ |
{ NULL, TYPE_Nx }, /* Nx */ |
{ NULL, TYPE_Nx, NODE_NOSRC }, /* Nx */ |
{ NULL, TYPE_Ox }, /* Ox */ |
{ NULL, TYPE_Ox, NODE_NOSRC }, /* Ox */ |
{ NULL, 0 }, /* Pc */ |
{ NULL, 0, 0 }, /* Pc */ |
{ NULL, 0 }, /* Pf */ |
{ NULL, 0, 0 }, /* Pf */ |
{ NULL, 0 }, /* Po */ |
{ NULL, 0, 0 }, /* Po */ |
{ NULL, 0 }, /* Pq */ |
{ NULL, 0, 0 }, /* Pq */ |
{ NULL, 0 }, /* Qc */ |
{ NULL, 0, 0 }, /* Qc */ |
{ NULL, 0 }, /* Ql */ |
{ NULL, 0, 0 }, /* Ql */ |
{ NULL, 0 }, /* Qo */ |
{ NULL, 0, 0 }, /* Qo */ |
{ NULL, 0 }, /* Qq */ |
{ NULL, 0, 0 }, /* Qq */ |
{ NULL, 0 }, /* Re */ |
{ NULL, 0, 0 }, /* Re */ |
{ NULL, 0 }, /* Rs */ |
{ NULL, 0, 0 }, /* Rs */ |
{ NULL, 0 }, /* Sc */ |
{ NULL, 0, 0 }, /* Sc */ |
{ NULL, 0 }, /* So */ |
{ NULL, 0, 0 }, /* So */ |
{ NULL, 0 }, /* Sq */ |
{ NULL, 0, 0 }, /* Sq */ |
{ NULL, 0 }, /* Sm */ |
{ NULL, 0, 0 }, /* Sm */ |
{ NULL, 0 }, /* Sx */ |
{ NULL, 0, 0 }, /* Sx */ |
{ NULL, TYPE_Sy }, /* Sy */ |
{ NULL, TYPE_Sy, 0 }, /* Sy */ |
{ NULL, TYPE_Tn }, /* Tn */ |
{ NULL, TYPE_Tn, 0 }, /* Tn */ |
{ NULL, 0 }, /* Ux */ |
{ NULL, 0, NODE_NOSRC }, /* Ux */ |
{ NULL, 0 }, /* Xc */ |
{ NULL, 0, 0 }, /* Xc */ |
{ NULL, 0 }, /* Xo */ |
{ NULL, 0, 0 }, /* Xo */ |
{ parse_mdoc_Fo, 0 }, /* Fo */ |
{ parse_mdoc_Fo, 0, 0 }, /* Fo */ |
{ NULL, 0 }, /* Fc */ |
{ NULL, 0, 0 }, /* Fc */ |
{ NULL, 0 }, /* Oo */ |
{ NULL, 0, 0 }, /* Oo */ |
{ NULL, 0 }, /* Oc */ |
{ NULL, 0, 0 }, /* Oc */ |
{ NULL, 0 }, /* Bk */ |
{ NULL, 0, 0 }, /* Bk */ |
{ NULL, 0 }, /* Ek */ |
{ NULL, 0, 0 }, /* Ek */ |
{ NULL, 0 }, /* Bt */ |
{ NULL, 0, 0 }, /* Bt */ |
{ NULL, 0 }, /* Hf */ |
{ NULL, 0, 0 }, /* Hf */ |
{ NULL, 0 }, /* Fr */ |
{ NULL, 0, 0 }, /* Fr */ |
{ NULL, 0 }, /* Ud */ |
{ NULL, 0, 0 }, /* Ud */ |
{ NULL, TYPE_Lb }, /* Lb */ |
{ NULL, TYPE_Lb, NODE_NOSRC }, /* Lb */ |
{ NULL, 0 }, /* Lp */ |
{ NULL, 0, 0 }, /* Lp */ |
{ NULL, TYPE_Lk }, /* Lk */ |
{ NULL, TYPE_Lk, 0 }, /* Lk */ |
{ NULL, TYPE_Mt }, /* Mt */ |
{ NULL, TYPE_Mt, NODE_NOSRC }, /* Mt */ |
{ NULL, 0 }, /* Brq */ |
{ NULL, 0, 0 }, /* Brq */ |
{ NULL, 0 }, /* Bro */ |
{ NULL, 0, 0 }, /* Bro */ |
{ NULL, 0 }, /* Brc */ |
{ NULL, 0, 0 }, /* Brc */ |
{ NULL, 0 }, /* %C */ |
{ NULL, 0, 0 }, /* %C */ |
{ NULL, 0 }, /* Es */ |
{ NULL, 0, 0 }, /* Es */ |
{ NULL, 0 }, /* En */ |
{ NULL, 0, 0 }, /* En */ |
{ NULL, TYPE_Dx }, /* Dx */ |
{ NULL, TYPE_Dx, NODE_NOSRC }, /* Dx */ |
{ NULL, 0 }, /* %Q */ |
{ NULL, 0, 0 }, /* %Q */ |
{ NULL, 0 }, /* br */ |
{ NULL, 0, 0 }, /* %U */ |
{ NULL, 0 }, /* sp */ |
{ NULL, 0, 0 }, /* Ta */ |
{ NULL, 0 }, /* %U */ |
|
{ NULL, 0 }, /* Ta */ |
|
{ NULL, 0 }, /* ll */ |
|
}; |
}; |
|
|
|
|
Line 316 mandocdb(int argc, char *argv[]) |
|
Line 321 mandocdb(int argc, char *argv[]) |
|
int ch, i; |
int ch, i; |
|
|
#if HAVE_PLEDGE |
#if HAVE_PLEDGE |
if (pledge("stdio rpath wpath cpath fattr flock proc exec", NULL) == -1) { |
if (pledge("stdio rpath wpath cpath", NULL) == -1) { |
warn("pledge"); |
warn("pledge"); |
return (int)MANDOCLEVEL_SYSERR; |
return (int)MANDOCLEVEL_SYSERR; |
} |
} |
Line 417 mandocdb(int argc, char *argv[]) |
|
Line 422 mandocdb(int argc, char *argv[]) |
|
|
|
exitcode = (int)MANDOCLEVEL_OK; |
exitcode = (int)MANDOCLEVEL_OK; |
mchars_alloc(); |
mchars_alloc(); |
mp = mparse_alloc(mparse_options, MANDOCLEVEL_BADARG, NULL, NULL); |
mp = mparse_alloc(mparse_options, MANDOC_OS_OTHER, NULL); |
mandoc_ohash_init(&mpages, 6, offsetof(struct mpage, inodev)); |
mandoc_ohash_init(&mpages, 6, offsetof(struct mpage, inodev)); |
mandoc_ohash_init(&mlinks, 6, offsetof(struct mlink, file)); |
mandoc_ohash_init(&mlinks, 6, offsetof(struct mlink, file)); |
|
|
Line 436 mandocdb(int argc, char *argv[]) |
|
Line 441 mandocdb(int argc, char *argv[]) |
|
* The existing database is usable. Process |
* The existing database is usable. Process |
* all files specified on the command-line. |
* 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; |
use_all = 1; |
for (i = 0; i < argc; i++) |
for (i = 0; i < argc; i++) |
filescan(argv[i]); |
filescan(argv[i]); |
|
|
* at the beginning, process directory entries in reverse alpha order. |
* at the beginning, process directory entries in reverse alpha order. |
*/ |
*/ |
static int |
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) |
fts_compare(const FTSENT **a, const FTSENT **b) |
|
#endif |
{ |
{ |
return -strcmp((*a)->fts_name, (*b)->fts_name); |
return -strcmp((*a)->fts_name, (*b)->fts_name); |
} |
} |
|
|
const char *argv[2]; |
const char *argv[2]; |
|
|
argv[0] = "."; |
argv[0] = "."; |
argv[1] = (char *)NULL; |
argv[1] = NULL; |
|
|
f = fts_open((char * const *)argv, FTS_PHYSICAL | FTS_NOCHDIR, |
f = fts_open((char * const *)argv, FTS_PHYSICAL | FTS_NOCHDIR, |
fts_compare); |
fts_compare); |
Line 863 filescan(const char *file) |
|
Line 863 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. |
* First try to guess our directory structure. |
* If we find a separator, try to look for man* or cat*. |
* 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, |
* If we find one of these and what's underneath is a directory, |
Line 1130 mpages_merge(struct dba *dba, struct mparse *mp) |
|
Line 1144 mpages_merge(struct dba *dba, struct mparse *mp) |
|
if (mlink->dform != FORM_CAT || mlink->fform != FORM_CAT) { |
if (mlink->dform != FORM_CAT || mlink->fform != FORM_CAT) { |
mparse_readfd(mp, fd, mlink->file); |
mparse_readfd(mp, fd, mlink->file); |
close(fd); |
close(fd); |
|
fd = -1; |
mparse_result(mp, &man, &sodest); |
mparse_result(mp, &man, &sodest); |
} |
} |
|
|
Line 1186 mpages_merge(struct dba *dba, struct mparse *mp) |
|
Line 1201 mpages_merge(struct dba *dba, struct mparse *mp) |
|
mpage->title = mandoc_strdup(man->meta.title); |
mpage->title = mandoc_strdup(man->meta.title); |
} else if (man != NULL && man->macroset == MACROSET_MAN) { |
} else if (man != NULL && man->macroset == MACROSET_MAN) { |
man_validate(man); |
man_validate(man); |
mpage->form = FORM_SRC; |
if (*man->meta.msec != '\0' || |
mpage->sec = mandoc_strdup(man->meta.msec); |
*man->meta.title != '\0') { |
mpage->arch = mandoc_strdup(mlink->arch); |
mpage->form = FORM_SRC; |
mpage->title = mandoc_strdup(man->meta.title); |
mpage->sec = mandoc_strdup(man->meta.msec); |
} else { |
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->form = FORM_CAT; |
mpage->sec = mandoc_strdup(mlink->dsec); |
mpage->sec = mandoc_strdup(mlink->dsec); |
mpage->arch = mandoc_strdup(mlink->arch); |
mpage->arch = mandoc_strdup(mlink->arch); |
mpage->title = mandoc_strdup(mlink->name); |
mpage->title = mandoc_strdup(mlink->name); |
} |
parse_cat(mpage, fd); |
|
} else if (man->macroset == MACROSET_MDOC) |
assert(mpage->desc == NULL); |
|
if (man != NULL && man->macroset == MACROSET_MDOC) |
|
parse_mdoc(mpage, &man->meta, man->first); |
parse_mdoc(mpage, &man->meta, man->first); |
else if (man != NULL) |
|
parse_man(mpage, &man->meta, man->first); |
|
else |
else |
parse_cat(mpage, fd); |
parse_man(mpage, &man->meta, man->first); |
if (mpage->desc == NULL) |
if (mpage->desc == NULL) { |
mpage->desc = mandoc_strdup(mpage->mlinks->name); |
mpage->desc = mandoc_strdup(mlink->name); |
|
if (warnings) |
|
say(mlink->file, "No one-line description, " |
|
"using filename \"%s\"", mlink->name); |
|
} |
|
|
if (warnings && !use_all) |
for (mlink = mpage->mlinks; |
for (mlink = mpage->mlinks; mlink; |
mlink != NULL; |
mlink = mlink->next) |
mlink = mlink->next) { |
|
putkey(mpage, mlink->name, NAME_FILE); |
|
if (warnings && !use_all) |
mlink_check(mpage, mlink); |
mlink_check(mpage, mlink); |
|
} |
|
|
dbadd(dba, mpage); |
dbadd(dba, mpage); |
mlink = mpage->mlinks; |
|
|
|
nextpage: |
nextpage: |
ohash_delete(&strings); |
ohash_delete(&strings); |
|
|
parse_cat(struct mpage *mpage, int fd) |
parse_cat(struct mpage *mpage, int fd) |
{ |
{ |
FILE *stream; |
FILE *stream; |
char *line, *p, *title; |
struct mlink *mlink; |
|
char *line, *p, *title, *sec; |
size_t linesz, plen, titlesz; |
size_t linesz, plen, titlesz; |
ssize_t len; |
ssize_t len; |
int offs; |
int offs; |
|
|
stream = (-1 == fd) ? |
mlink = mpage->mlinks; |
fopen(mpage->mlinks->file, "r") : |
stream = fd == -1 ? fopen(mlink->file, "r") : fdopen(fd, "r"); |
fdopen(fd, "r"); |
if (stream == NULL) { |
if (NULL == stream) { |
if (fd != -1) |
if (-1 != fd) |
|
close(fd); |
close(fd); |
if (warnings) |
if (warnings) |
say(mpage->mlinks->file, "&fopen"); |
say(mlink->file, "&fopen"); |
return; |
return; |
} |
} |
|
|
line = NULL; |
line = NULL; |
linesz = 0; |
linesz = 0; |
|
|
/* Skip to first blank line. */ |
/* Parse the section number from the header line. */ |
|
|
while (getline(&line, &linesz, stream) != -1) |
while (getline(&line, &linesz, stream) != -1) { |
if (*line == '\n') |
if (*line == '\n') |
|
continue; |
|
if ((sec = strchr(line, '(')) == NULL) |
break; |
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 (line == NULL || *line != '\n') |
|
if (getline(&line, &linesz, stream) == -1) |
|
break; |
|
|
/* |
/* |
* Assume the first line that is not indented |
* Assume the first line that is not indented |
* is the first section header. Skip to it. |
* is the first section header. Skip to it. |
Line 1293 parse_cat(struct mpage *mpage, int fd) |
|
Line 1336 parse_cat(struct mpage *mpage, int fd) |
|
|
|
if (NULL == title || '\0' == *title) { |
if (NULL == title || '\0' == *title) { |
if (warnings) |
if (warnings) |
say(mpage->mlinks->file, |
say(mlink->file, "Cannot find NAME section"); |
"Cannot find NAME section"); |
|
fclose(stream); |
fclose(stream); |
free(title); |
free(title); |
return; |
return; |
Line 1313 parse_cat(struct mpage *mpage, int fd) |
|
Line 1355 parse_cat(struct mpage *mpage, int fd) |
|
/* Skip to next word. */ ; |
/* Skip to next word. */ ; |
} else { |
} else { |
if (warnings) |
if (warnings) |
say(mpage->mlinks->file, |
say(mlink->file, "No dash in title line, " |
"No dash in title line"); |
"reusing \"%s\" as one-line description", title); |
p = title; |
p = title; |
} |
} |
|
|
Line 1332 parse_cat(struct mpage *mpage, int fd) |
|
Line 1374 parse_cat(struct mpage *mpage, int fd) |
|
plen -= 2; |
plen -= 2; |
} |
} |
|
|
mpage->desc = mandoc_strdup(p); |
/* |
|
* Cut off excessive one-line descriptions. |
|
* Bad pages are not worth better heuristics. |
|
*/ |
|
|
|
mpage->desc = mandoc_strndup(p, 150); |
fclose(stream); |
fclose(stream); |
free(title); |
free(title); |
} |
} |
Line 1351 putkey(const struct mpage *mpage, char *value, uint64_ |
|
Line 1398 putkey(const struct mpage *mpage, char *value, uint64_ |
|
*/ |
*/ |
static void |
static void |
putmdockey(const struct mpage *mpage, |
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) { |
for ( ; NULL != n; n = n->next) { |
|
if (n->flags & taboo) |
|
continue; |
if (NULL != n->child) |
if (NULL != n->child) |
putmdockey(mpage, n->child, m); |
putmdockey(mpage, n->child, m, taboo); |
if (n->type == ROFFT_TEXT) |
if (n->type == ROFFT_TEXT) |
putkey(mpage, n->string, m); |
putkey(mpage, n->string, m); |
} |
} |
Line 1474 parse_man(struct mpage *mpage, const struct roff_meta |
|
Line 1523 parse_man(struct mpage *mpage, const struct roff_meta |
|
while (' ' == *start) |
while (' ' == *start) |
start++; |
start++; |
|
|
mpage->desc = mandoc_strdup(start); |
/* |
|
* Cut off excessive one-line descriptions. |
|
* Bad pages are not worth better heuristics. |
|
*/ |
|
|
|
mpage->desc = mandoc_strndup(start, 150); |
free(title); |
free(title); |
return; |
return; |
} |
} |
|
|
parse_mdoc(struct mpage *mpage, const struct roff_meta *meta, |
parse_mdoc(struct mpage *mpage, const struct roff_meta *meta, |
const struct roff_node *n) |
const struct roff_node *n) |
{ |
{ |
|
const struct mdoc_handler *handler; |
|
|
assert(NULL != n); |
for (n = n->child; n != NULL; n = n->next) { |
for (n = n->child; NULL != n; n = n->next) { |
if (n->tok == TOKEN_NONE || n->tok < ROFF_MAX) |
|
continue; |
|
assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX); |
|
handler = mdoc_handlers + (n->tok - MDOC_Dd); |
|
if (n->flags & handler->taboo) |
|
continue; |
|
|
switch (n->type) { |
switch (n->type) { |
case ROFFT_ELEM: |
case ROFFT_ELEM: |
case ROFFT_BLOCK: |
case ROFFT_BLOCK: |
case ROFFT_HEAD: |
case ROFFT_HEAD: |
case ROFFT_BODY: |
case ROFFT_BODY: |
case ROFFT_TAIL: |
case ROFFT_TAIL: |
if (NULL != mdocs[n->tok].fp) |
if (handler->fp != NULL && |
if (0 == (*mdocs[n->tok].fp)(mpage, meta, n)) |
(*handler->fp)(mpage, meta, n) == 0) |
break; |
break; |
if (mdocs[n->tok].mask) |
if (handler->mask) |
putmdockey(mpage, n->child, |
putmdockey(mpage, n->child, |
mdocs[n->tok].mask); |
handler->mask, handler->taboo); |
break; |
break; |
default: |
default: |
assert(n->type != ROFFT_ROOT); |
|
continue; |
continue; |
} |
} |
if (NULL != n->child) |
if (NULL != n->child) |
Line 1517 parse_mdoc(struct mpage *mpage, const struct roff_meta |
|
Line 1577 parse_mdoc(struct mpage *mpage, const struct roff_meta |
|
} |
} |
|
|
static int |
static int |
|
parse_mdoc_Fa(struct mpage *mpage, const struct roff_meta *meta, |
|
const struct roff_node *n) |
|
{ |
|
uint64_t mask; |
|
|
|
mask = TYPE_Fa; |
|
if (n->sec == SEC_SYNOPSIS) |
|
mask |= TYPE_Vt; |
|
|
|
putmdockey(mpage, n->child, mask, 0); |
|
return 0; |
|
} |
|
|
|
static int |
parse_mdoc_Fd(struct mpage *mpage, const struct roff_meta *meta, |
parse_mdoc_Fd(struct mpage *mpage, const struct roff_meta *meta, |
const struct roff_node *n) |
const struct roff_node *n) |
{ |
{ |
|
|
parse_mdoc_Fn(struct mpage *mpage, const struct roff_meta *meta, |
parse_mdoc_Fn(struct mpage *mpage, const struct roff_meta *meta, |
const struct roff_node *n) |
const struct roff_node *n) |
{ |
{ |
|
uint64_t mask; |
|
|
if (n->child == NULL) |
if (n->child == NULL) |
return 0; |
return 0; |
|
|
parse_mdoc_fname(mpage, n->child); |
parse_mdoc_fname(mpage, n->child); |
|
|
for (n = n->child->next; n != NULL; n = n->next) |
n = n->child->next; |
if (n->type == ROFFT_TEXT) |
if (n != NULL && n->type == ROFFT_TEXT) { |
putkey(mpage, n->string, TYPE_Fa); |
mask = TYPE_Fa; |
|
if (n->sec == SEC_SYNOPSIS) |
|
mask |= TYPE_Vt; |
|
putmdockey(mpage, n, mask, 0); |
|
} |
|
|
return 0; |
return 0; |
} |
} |
Line 1673 parse_mdoc_Nm(struct mpage *mpage, const struct roff_m |
|
Line 1752 parse_mdoc_Nm(struct mpage *mpage, const struct roff_m |
|
{ |
{ |
|
|
if (SEC_NAME == n->sec) |
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) { |
else if (n->sec == SEC_SYNOPSIS && n->type == ROFFT_HEAD) { |
if (n->child == NULL) |
if (n->child == NULL) |
putkey(mpage, meta->name, NAME_SYN); |
putkey(mpage, meta->name, NAME_SYN); |
else |
else |
putmdockey(mpage, n->child, NAME_SYN); |
putmdockey(mpage, n->child, NAME_SYN, 0); |
} |
} |
if ( ! (mpage->name_head_done || |
if ( ! (mpage->name_head_done || |
n->child == NULL || n->child->string == NULL || |
n->child == NULL || n->child->string == NULL || |
Line 1731 putkeys(const struct mpage *mpage, char *cp, size_t sz |
|
Line 1810 putkeys(const struct mpage *mpage, char *cp, size_t sz |
|
name_mask &= ~NAME_FIRST; |
name_mask &= ~NAME_FIRST; |
if (debug > 1) |
if (debug > 1) |
say(mpage->mlinks->file, |
say(mpage->mlinks->file, |
"Adding name %*s, bits=0x%llu", (int)sz, cp, v); |
"Adding name %*s, bits=0x%llx", (int)sz, cp, |
|
(unsigned long long)v); |
} else { |
} else { |
htab = &strings; |
htab = &strings; |
if (debug > 1) |
if (debug > 1) |
Line 2063 dbprune(struct dba *dba) |
|
Line 2143 dbprune(struct dba *dba) |
|
static void |
static void |
dbwrite(struct dba *dba) |
dbwrite(struct dba *dba) |
{ |
{ |
char tfn[32]; |
struct stat sb1, sb2; |
int status; |
char tfn[33], *cp1, *cp2; |
pid_t child; |
off_t i; |
|
int fd1, fd2; |
|
|
|
/* |
|
* Do not write empty databases, and delete existing ones |
|
* when makewhatis -u causes them to become empty. |
|
*/ |
|
|
|
dba_array_start(dba->pages); |
|
if (dba_array_next(dba->pages) == NULL) { |
|
if (unlink(MANDOC_DB) == -1 && errno != ENOENT) |
|
say(MANDOC_DB, "&unlink"); |
|
return; |
|
} |
|
|
|
/* |
|
* Build the database in a temporary file, |
|
* then atomically move it into place. |
|
*/ |
|
|
if (dba_write(MANDOC_DB "~", dba) != -1) { |
if (dba_write(MANDOC_DB "~", dba) != -1) { |
if (rename(MANDOC_DB "~", MANDOC_DB) == -1) { |
if (rename(MANDOC_DB "~", MANDOC_DB) == -1) { |
exitcode = (int)MANDOCLEVEL_SYSERR; |
exitcode = (int)MANDOCLEVEL_SYSERR; |
Line 2076 dbwrite(struct dba *dba) |
|
Line 2174 dbwrite(struct dba *dba) |
|
return; |
return; |
} |
} |
|
|
|
/* |
|
* We lack write permission and cannot replace the database |
|
* file, but let's at least check whether the data changed. |
|
*/ |
|
|
(void)strlcpy(tfn, "/tmp/mandocdb.XXXXXXXX", sizeof(tfn)); |
(void)strlcpy(tfn, "/tmp/mandocdb.XXXXXXXX", sizeof(tfn)); |
if (mkdtemp(tfn) == NULL) { |
if (mkdtemp(tfn) == NULL) { |
exitcode = (int)MANDOCLEVEL_SYSERR; |
exitcode = (int)MANDOCLEVEL_SYSERR; |
say("", "&%s", tfn); |
say("", "&%s", tfn); |
return; |
return; |
} |
} |
|
cp1 = cp2 = MAP_FAILED; |
|
fd1 = fd2 = -1; |
(void)strlcat(tfn, "/" MANDOC_DB, sizeof(tfn)); |
(void)strlcat(tfn, "/" MANDOC_DB, sizeof(tfn)); |
if (dba_write(tfn, dba) == -1) { |
if (dba_write(tfn, dba) == -1) { |
exitcode = (int)MANDOCLEVEL_SYSERR; |
|
say(tfn, "&dba_write"); |
say(tfn, "&dba_write"); |
goto out; |
goto err; |
} |
} |
|
if ((fd1 = open(MANDOC_DB, O_RDONLY, 0)) == -1) { |
switch (child = fork()) { |
say(MANDOC_DB, "&open"); |
case -1: |
goto err; |
exitcode = (int)MANDOCLEVEL_SYSERR; |
|
say("", "&fork cmp"); |
|
return; |
|
case 0: |
|
execlp("cmp", "cmp", "-s", tfn, MANDOC_DB, (char *)NULL); |
|
say("", "&exec cmp"); |
|
exit(0); |
|
default: |
|
break; |
|
} |
} |
if (waitpid(child, &status, 0) == -1) { |
if ((fd2 = open(tfn, O_RDONLY, 0)) == -1) { |
exitcode = (int)MANDOCLEVEL_SYSERR; |
say(tfn, "&open"); |
say("", "&wait cmp"); |
goto err; |
} else if (WIFSIGNALED(status)) { |
|
exitcode = (int)MANDOCLEVEL_SYSERR; |
|
say("", "cmp died from signal %d", WTERMSIG(status)); |
|
} else if (WEXITSTATUS(status)) { |
|
exitcode = (int)MANDOCLEVEL_SYSERR; |
|
say(MANDOC_DB, |
|
"Data changed, but cannot replace database"); |
|
} |
} |
|
if (fstat(fd1, &sb1) == -1) { |
|
say(MANDOC_DB, "&fstat"); |
|
goto err; |
|
} |
|
if (fstat(fd2, &sb2) == -1) { |
|
say(tfn, "&fstat"); |
|
goto err; |
|
} |
|
if (sb1.st_size != sb2.st_size) |
|
goto err; |
|
if ((cp1 = mmap(NULL, sb1.st_size, PROT_READ, MAP_PRIVATE, |
|
fd1, 0)) == MAP_FAILED) { |
|
say(MANDOC_DB, "&mmap"); |
|
goto err; |
|
} |
|
if ((cp2 = mmap(NULL, sb2.st_size, PROT_READ, MAP_PRIVATE, |
|
fd2, 0)) == MAP_FAILED) { |
|
say(tfn, "&mmap"); |
|
goto err; |
|
} |
|
for (i = 0; i < sb1.st_size; i++) |
|
if (cp1[i] != cp2[i]) |
|
goto err; |
|
goto out; |
|
|
|
err: |
|
exitcode = (int)MANDOCLEVEL_SYSERR; |
|
say(MANDOC_DB, "Data changed, but cannot replace database"); |
|
|
out: |
out: |
|
if (cp1 != MAP_FAILED) |
|
munmap(cp1, sb1.st_size); |
|
if (cp2 != MAP_FAILED) |
|
munmap(cp2, sb2.st_size); |
|
if (fd1 != -1) |
|
close(fd1); |
|
if (fd2 != -1) |
|
close(fd2); |
|
unlink(tfn); |
*strrchr(tfn, '/') = '\0'; |
*strrchr(tfn, '/') = '\0'; |
switch (child = fork()) { |
rmdir(tfn); |
case -1: |
|
exitcode = (int)MANDOCLEVEL_SYSERR; |
|
say("", "&fork rm"); |
|
return; |
|
case 0: |
|
execlp("rm", "rm", "-rf", tfn, (char *)NULL); |
|
say("", "&exec rm"); |
|
exit((int)MANDOCLEVEL_SYSERR); |
|
default: |
|
break; |
|
} |
|
if (waitpid(child, &status, 0) == -1) { |
|
exitcode = (int)MANDOCLEVEL_SYSERR; |
|
say("", "&wait rm"); |
|
} else if (WIFSIGNALED(status) || WEXITSTATUS(status)) { |
|
exitcode = (int)MANDOCLEVEL_SYSERR; |
|
say("", "%s: Cannot remove temporary directory", tfn); |
|
} |
|
} |
} |
|
|
static int |
static int |