diff options
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | Makefile.depend | 24 | ||||
-rwxr-xr-x | configure | 2 | ||||
-rw-r--r-- | configure.local.example | 5 | ||||
-rw-r--r-- | main.c | 33 | ||||
-rw-r--r-- | manconf.h | 5 | ||||
-rw-r--r-- | mandoc.1 | 8 | ||||
-rw-r--r-- | mandoc.h | 1 | ||||
-rw-r--r-- | mandoc_headers.3 | 12 | ||||
-rw-r--r-- | mandoc_xr.c | 112 | ||||
-rw-r--r-- | mandoc_xr.h | 30 | ||||
-rw-r--r-- | manpath.c | 9 | ||||
-rw-r--r-- | mansearch.c | 12 | ||||
-rw-r--r-- | mdoc_validate.c | 6 | ||||
-rw-r--r-- | read.c | 1 |
15 files changed, 244 insertions, 19 deletions
@@ -94,6 +94,7 @@ SRCS = att.c \ mandoc.c \ mandoc_aux.c \ mandoc_ohash.c \ + mandoc_xr.c \ mandocd.c \ mandocdb.c \ manpath.c \ @@ -180,6 +181,7 @@ DISTFILES = INSTALL \ mandoc_html.3 \ mandoc_malloc.3 \ mandoc_ohash.h \ + mandoc_xr.h \ mandocd.8 \ mansearch.3 \ mansearch.h \ @@ -229,6 +231,7 @@ LIBMANDOC_OBJS = $(LIBMAN_OBJS) \ mandoc.o \ mandoc_aux.o \ mandoc_ohash.o \ + mandoc_xr.o \ msec.o \ preconv.o \ read.o diff --git a/Makefile.depend b/Makefile.depend index 61d967af..c3d85adb 100644 --- a/Makefile.depend +++ b/Makefile.depend @@ -1,4 +1,4 @@ -att.o: att.c config.h roff.h mdoc.h libmdoc.h +att.o: att.c config.h mandoc.h roff.h mdoc.h libmdoc.h catman.o: catman.c config.h compat_fts.h cgi.o: cgi.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h main.h manconf.h mansearch.h cgi.h chars.o: chars.c config.h mandoc.h mandoc_aux.h mandoc_ohash.h compat_ohash.h libmandoc.h @@ -11,6 +11,7 @@ compat_mkdtemp.o: compat_mkdtemp.c config.h compat_ohash.o: compat_ohash.c config.h compat_ohash.h compat_progname.o: compat_progname.c config.h compat_reallocarray.o: compat_reallocarray.c config.h +compat_recallocarray.o: compat_recallocarray.c config.h compat_strcasestr.o: compat_strcasestr.c config.h compat_stringlist.o: compat_stringlist.c config.h compat_stringlist.h compat_strlcat.o: compat_strlcat.c config.h @@ -24,44 +25,45 @@ dba_read.o: dba_read.c mandoc_aux.h mansearch.h dba_array.h dba.h dbm.h dba_write.o: dba_write.c config.h dba_write.h dbm.o: dbm.c config.h mansearch.h dbm_map.h dbm.h dbm_map.o: dbm_map.c config.h mansearch.h dbm_map.h dbm.h -demandoc.o: demandoc.c config.h roff.h man.h mdoc.h mandoc.h +demandoc.o: demandoc.c config.h mandoc.h roff.h man.h mdoc.h eqn.o: eqn.c config.h mandoc.h mandoc_aux.h libmandoc.h libroff.h eqn_html.o: eqn_html.c config.h mandoc.h out.h html.h eqn_term.o: eqn_term.c config.h mandoc.h out.h term.h html.o: html.c config.h mandoc_aux.h mandoc.h roff.h out.h html.h manconf.h main.h -lib.o: lib.c config.h roff.h mdoc.h libmdoc.h lib.in -main.o: main.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h tag.h main.h manconf.h mansearch.h +lib.o: lib.c config.h mandoc.h roff.h mdoc.h libmdoc.h lib.in +main.o: main.c config.h mandoc_aux.h mandoc.h mandoc_xr.h roff.h mdoc.h man.h tag.h main.h manconf.h mansearch.h man.o: man.c config.h mandoc_aux.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.h -man_html.o: man_html.c config.h mandoc_aux.h roff.h man.h out.h html.h main.h +man_html.o: man_html.c config.h mandoc_aux.h mandoc.h roff.h man.h out.h html.h main.h man_macro.o: man_macro.c config.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.h man_term.o: man_term.c config.h mandoc_aux.h mandoc.h roff.h man.h out.h term.h main.h man_validate.o: man_validate.c config.h mandoc_aux.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.h -mandoc.o: mandoc.c config.h mandoc.h mandoc_aux.h libmandoc.h +mandoc.o: mandoc.c config.h mandoc_aux.h mandoc.h roff.h libmandoc.h mandoc_aux.o: mandoc_aux.c config.h mandoc.h mandoc_aux.h mandoc_ohash.o: mandoc_ohash.c mandoc_aux.h mandoc_ohash.h compat_ohash.h +mandoc_xr.o: mandoc_xr.c mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc_xr.h mandocd.o: mandocd.c config.h mandoc.h roff.h mdoc.h man.h main.h manconf.h mandocdb.o: mandocdb.c config.h compat_fts.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc.h roff.h mdoc.h man.h manconf.h mansearch.h dba_array.h dba.h manpath.o: manpath.c config.h mandoc_aux.h manconf.h mansearch.o: mansearch.c config.h mandoc.h mandoc_aux.h mandoc_ohash.h compat_ohash.h manconf.h mansearch.h dbm.h mdoc.o: mdoc.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h mdoc_argv.o: mdoc_argv.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h -mdoc_html.o: mdoc_html.c config.h mandoc_aux.h roff.h mdoc.h out.h html.h main.h +mdoc_html.o: mdoc_html.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h out.h html.h main.h mdoc_macro.o: mdoc_macro.c config.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h mdoc_man.o: mdoc_man.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h out.h main.h mdoc_markdown.o: mdoc_markdown.c mandoc_aux.h mandoc.h roff.h mdoc.h main.h mdoc_state.o: mdoc_state.c mandoc.h roff.h mdoc.h libmandoc.h libmdoc.h mdoc_term.o: mdoc_term.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h out.h term.h tag.h main.h -mdoc_validate.o: mdoc_validate.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h +mdoc_validate.o: mdoc_validate.c config.h mandoc_aux.h mandoc.h mandoc_xr.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h msec.o: msec.c config.h mandoc.h libmandoc.h msec.in out.o: out.c config.h mandoc_aux.h mandoc.h out.h preconv.o: preconv.c config.h mandoc.h libmandoc.h read.o: read.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h libmandoc.h roff_int.h roff.o: roff.c config.h mandoc.h mandoc_aux.h mandoc_ohash.h compat_ohash.h roff.h libmandoc.h roff_int.h libroff.h predefs.in -roff_html.o: roff_html.c roff.h out.h html.h -roff_term.o: roff_term.c roff.h out.h term.h +roff_html.o: roff_html.c mandoc.h roff.h out.h html.h +roff_term.o: roff_term.c mandoc.h roff.h out.h term.h roff_validate.o: roff_validate.c mandoc.h roff.h libmandoc.h roff_int.h soelim.o: soelim.c config.h compat_stringlist.h -st.o: st.c config.h roff.h mdoc.h libmdoc.h st.in +st.o: st.c config.h mandoc.h roff.h mdoc.h libmdoc.h st.in tag.o: tag.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h tag.h tbl.o: tbl.c config.h mandoc.h mandoc_aux.h libmandoc.h libroff.h tbl_data.o: tbl_data.c config.h mandoc.h mandoc_aux.h libmandoc.h libroff.h @@ -35,6 +35,7 @@ echo "config.log: writing..." SOURCEDIR=`dirname "$0"` +MANPATH_BASE="/usr/share/man:/usr/X11R6/man" MANPATH_DEFAULT="/usr/share/man:/usr/X11R6/man:/usr/local/man" OSNAME= UTF8_LOCALE= @@ -359,6 +360,7 @@ __HEREDOC__ echo echo "#define MAN_CONF_FILE \"/etc/${MANM_MANCONF}\"" +echo "#define MANPATH_BASE \"${MANPATH_BASE}\"" echo "#define MANPATH_DEFAULT \"${MANPATH_DEFAULT}\"" [ -n "${OSNAME}" ] && echo "#define OSNAME \"${OSNAME}\"" [ -n "${UTF8_LOCALE}" ] && echo "#define UTF8_LOCALE \"${UTF8_LOCALE}\"" diff --git a/configure.local.example b/configure.local.example index 324fe38b..045e7a30 100644 --- a/configure.local.example +++ b/configure.local.example @@ -62,6 +62,11 @@ UTF8_LOCALE=en_US.UTF-8 MANPATH_DEFAULT="/usr/share/man:/usr/X11R6/man:/usr/local/man" +# Validation of cross references with mandoc -Tlint only looks +# for manual pages in the following directories: + +MANPATH_BASE="/usr/share/man:/usr/X11R6/man" + # In manual pages written in the mdoc(7) language, the operating system # version is displayed in the page footer line. If an operating system # is specified as an argument to the .Os macro, that is always used. @@ -43,6 +43,7 @@ #include "mandoc_aux.h" #include "mandoc.h" +#include "mandoc_xr.h" #include "roff.h" #include "mdoc.h" #include "man.h" @@ -86,6 +87,7 @@ struct curparse { int mandocdb(int, char *[]); +static void check_xr(const char *); static int fs_lookup(const struct manpaths *, size_t ipath, const char *, const char *, const char *, @@ -517,6 +519,7 @@ main(int argc, char *argv[]) break; } } + mandoc_xr_free(); mparse_free(curp.mp); mchars_free(); @@ -747,6 +750,8 @@ parse(struct curparse *curp, int fd, const char *file) if (man == NULL) return; + if (curp->mmin < MANDOCERR_STYLE) + mandoc_xr_reset(); if (man->macroset == MACROSET_MDOC) { if (curp->outtype != OUTT_TREE || !curp->outopts->noval) mdoc_validate(man); @@ -798,10 +803,38 @@ parse(struct curparse *curp, int fd, const char *file) break; } } + check_xr(file); mparse_updaterc(curp->mp, &rc); } static void +check_xr(const char *file) +{ + static struct manpaths paths; + struct mansearch search; + struct mandoc_xr *xr; + char *cp; + size_t sz; + + if (paths.sz == 0) + manpath_base(&paths); + + for (xr = mandoc_xr_get(); xr != NULL; xr = xr->next) { + search.arch = NULL; + search.sec = xr->sec; + search.outkey = NULL; + search.argmode = ARG_NAME; + search.firstmatch = 1; + if (mansearch(&search, &paths, 1, &xr->name, NULL, &sz)) + continue; + mandoc_asprintf(&cp, "Xr %s %s", xr->name, xr->sec); + mmsg(MANDOCERR_XR_BAD, MANDOCLEVEL_STYLE, + file, xr->line, xr->pos + 1, cp); + free(cp); + } +} + +static void outdata_alloc(struct curparse *curp) { switch (curp->outtype) { @@ -1,6 +1,6 @@ -/* $OpenBSD$ */ +/* $Id$ */ /* - * Copyright (c) 2011, 2015 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2011, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv> * * Permission to use, copy, modify, and distribute this software for any @@ -47,3 +47,4 @@ struct manconf { void manconf_parse(struct manconf *, const char *, char *, char *); int manconf_output(struct manoutput *, const char *, int); void manconf_free(struct manconf *); +void manpath_base(struct manpaths *); @@ -836,6 +836,14 @@ generated by CVS or .Ic NetBSD keyword substitution as conventionally used in these operating systems. +.It Sy "referenced manual not found" +.Pq mdoc +An +.Ic \&Xr +macro references a manual page that is not found in the base system. +The path to look for base system manuals is configurable at compile +time and defaults to +.Pa /usr/share/man : /usr/X11R6/man . .El .Ss Style suggestions .Bl -ohang @@ -51,6 +51,7 @@ enum mandocerr { MANDOCERR_ARCH_BAD, /* unknown architecture: Dt ... arch */ MANDOCERR_OS_ARG, /* operating system explicitly specified: Os ... */ MANDOCERR_RCS_MISSING, /* RCS id missing */ + MANDOCERR_XR_BAD, /* referenced manual not found: Xr name sec */ MANDOCERR_STYLE, /* ===== start of style suggestions ===== */ diff --git a/mandoc_headers.3 b/mandoc_headers.3 index ecc98e2e..e964aece 100644 --- a/mandoc_headers.3 +++ b/mandoc_headers.3 @@ -123,6 +123,15 @@ Uses the type from .Pa roff.h as an opaque type for function prototypes. +.It Qq Pa mandoc_xr.h +Provides +.Vt struct mandoc_xr +and the functions +.Fn mandoc_xr_reset , +.Fn mandoc_xr_add , +.Fn mandoc_xr_get , +and +.Fn mandoc_xr_free . .It Qq Pa roff.h Requires .Qq Pa mandoc_ohash.h @@ -540,8 +549,9 @@ Provides and the functions .Fn manconf_parse , .Fn manconf_output , +.Fn manconf_free , and -.Fn manconf_free . +.Fn manpath_base . .It Qq Pa mansearch.h Requires .In sys/types.h diff --git a/mandoc_xr.c b/mandoc_xr.c new file mode 100644 index 00000000..d69c9c80 --- /dev/null +++ b/mandoc_xr.c @@ -0,0 +1,112 @@ +/* $Id$ */ +/* + * Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include <sys/types.h> + +#include <assert.h> +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "mandoc_aux.h" +#include "mandoc_ohash.h" +#include "mandoc_xr.h" + +static struct ohash *xr_hash = NULL; +static struct mandoc_xr *xr_first = NULL; +static struct mandoc_xr *xr_last = NULL; + +static void mandoc_xr_clear(void); + + +static void +mandoc_xr_clear(void) +{ + struct mandoc_xr *xr; + unsigned int slot; + + if (xr_hash == NULL) + return; + for (xr = ohash_first(xr_hash, &slot); xr != NULL; + xr = ohash_next(xr_hash, &slot)) + free(xr); + ohash_delete(xr_hash); +} + +void +mandoc_xr_reset(void) +{ + if (xr_hash == NULL) + xr_hash = mandoc_malloc(sizeof(*xr_hash)); + else + mandoc_xr_clear(); + mandoc_ohash_init(xr_hash, 5, + offsetof(struct mandoc_xr, hashkey)); + xr_first = xr_last = NULL; +} + +void +mandoc_xr_add(const char *sec, const char *name, int line, int pos) +{ + struct mandoc_xr *xr; + const char *pend; + size_t ssz, nsz, tsz; + unsigned int slot; + uint32_t hv; + + if (xr_hash == NULL) + return; + + ssz = strlen(sec) + 1; + nsz = strlen(name) + 1; + tsz = ssz + nsz; + xr = mandoc_malloc(sizeof(*xr) + tsz); + xr->next = NULL; + xr->sec = xr->hashkey; + xr->name = xr->hashkey + ssz; + xr->line = line; + xr->pos = pos; + memcpy(xr->sec, sec, ssz); + memcpy(xr->name, name, nsz); + + pend = xr->hashkey + tsz; + hv = ohash_interval(xr->hashkey, &pend); + slot = ohash_lookup_memory(xr_hash, xr->hashkey, tsz, hv); + if (ohash_find(xr_hash, slot) == NULL) { + ohash_insert(xr_hash, slot, xr); + if (xr_first == NULL) + xr_first = xr; + else + xr_last->next = xr; + xr_last = xr; + } else + free(xr); +} + +struct mandoc_xr * +mandoc_xr_get(void) +{ + return xr_first; +} + +void +mandoc_xr_free(void) +{ + mandoc_xr_clear(); + free(xr_hash); + xr_hash = NULL; +} diff --git a/mandoc_xr.h b/mandoc_xr.h new file mode 100644 index 00000000..81601cdb --- /dev/null +++ b/mandoc_xr.h @@ -0,0 +1,30 @@ +/* $Id$ */ +/* + * Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +struct mandoc_xr { + struct mandoc_xr *next; + char *sec; + char *name; + int line; + int pos; + char hashkey[]; +}; + +void mandoc_xr_reset(void); +void mandoc_xr_add(const char *, const char *, int, int); +struct mandoc_xr *mandoc_xr_get(void); +void mandoc_xr_free(void); @@ -1,4 +1,4 @@ -/* $Id$ */ +/* $Id$ */ /* * Copyright (c) 2011, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv> @@ -91,6 +91,13 @@ manconf_parse(struct manconf *conf, const char *file, manpath_parseline(&conf->manpath, defp, 0); } +void +manpath_base(struct manpaths *dirs) +{ + char path_base[] = MANPATH_BASE; + manpath_parseline(dirs, path_base, 0); +} + /* * Parse a FULL pathname from a colon-separated list of arrays. */ diff --git a/mansearch.c b/mansearch.c index 26a7c23f..ddfe2f5d 100644 --- a/mansearch.c +++ b/mansearch.c @@ -104,7 +104,8 @@ mansearch(const struct mansearch *search, } cur = maxres = 0; - *res = NULL; + if (res != NULL) + *res = NULL; outkey = KEY_Nd; if (search->outkey != NULL) @@ -173,6 +174,10 @@ mansearch(const struct mansearch *search, lstmatch(search->arch, page->arch) == 0) continue; + if (res == NULL) { + cur = 1; + break; + } if (cur + 1 > maxres) { maxres += 1024; *res = mandoc_reallocarray(*res, @@ -204,12 +209,13 @@ mansearch(const struct mansearch *search, if (cur && search->firstmatch) break; } - qsort(*res, cur, sizeof(struct manpage), manpage_compare); + if (res != NULL) + qsort(*res, cur, sizeof(struct manpage), manpage_compare); if (chdir_status && getcwd_status && chdir(buf) == -1) warn("%s", buf); exprfree(e); *sz = cur; - return 1; + return res != NULL || cur; } /* diff --git a/mdoc_validate.c b/mdoc_validate.c index ceaaed7d..a15ce33e 100644 --- a/mdoc_validate.c +++ b/mdoc_validate.c @@ -33,6 +33,7 @@ #include "mandoc_aux.h" #include "mandoc.h" +#include "mandoc_xr.h" #include "roff.h" #include "mdoc.h" #include "libmandoc.h" @@ -2336,8 +2337,11 @@ post_xr(POST_ARGS) if (nch->next == NULL) { mandoc_vmsg(MANDOCERR_XR_NOSEC, mdoc->parse, n->line, n->pos, "Xr %s", nch->string); - } else + } else { assert(nch->next == n->last); + mandoc_xr_add(nch->next->string, nch->string, + nch->line, nch->pos); + } post_delim(mdoc); } @@ -93,6 +93,7 @@ static const char * const mandocerrs[MANDOCERR_MAX] = { "unknown architecture", "operating system explicitly specified", "RCS id missing", + "referenced manual not found", "generic style suggestion", |