summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@openbsd.org>2017-07-01 09:47:30 +0000
committerIngo Schwarze <schwarze@openbsd.org>2017-07-01 09:47:30 +0000
commita288316b2989716c6f4ed17dce8e778e9b6de9d7 (patch)
treefd723758e0cdfb5ee949c3eceaa129843f13d59b
parent17984e1e0b09558f8bfb0a8ee9e49bc97e4a554e (diff)
downloadmandoc-a288316b2989716c6f4ed17dce8e778e9b6de9d7.tar.gz
Basic reporting of .Xrs to manual pages that don't exist
in the base system, inspired by mdoclint(1). We are able to do this because (1) the -mdoc parser, the -Tlint validator, and the man(1) manual page lookup code are all in the same program and (2) the mandoc.db(5) database format allows fast lookup. Feedback from, previous versions tested by, and OK jmc@. A few features will be added to this in the tree, step by step.
-rw-r--r--Makefile3
-rw-r--r--Makefile.depend24
-rwxr-xr-xconfigure2
-rw-r--r--configure.local.example5
-rw-r--r--main.c33
-rw-r--r--manconf.h5
-rw-r--r--mandoc.18
-rw-r--r--mandoc.h1
-rw-r--r--mandoc_headers.312
-rw-r--r--mandoc_xr.c112
-rw-r--r--mandoc_xr.h30
-rw-r--r--manpath.c9
-rw-r--r--mansearch.c12
-rw-r--r--mdoc_validate.c6
-rw-r--r--read.c1
15 files changed, 244 insertions, 19 deletions
diff --git a/Makefile b/Makefile
index 958a8b45..0f2deec6 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/configure b/configure
index 4d1a26a4..8d1576b0 100755
--- a/configure
+++ b/configure
@@ -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.
diff --git a/main.c b/main.c
index f028f93c..f8c78f90 100644
--- a/main.c
+++ b/main.c
@@ -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) {
diff --git a/manconf.h b/manconf.h
index f5c678e8..cb3a883a 100644
--- a/manconf.h
+++ b/manconf.h
@@ -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 *);
diff --git a/mandoc.1 b/mandoc.1
index 1981cc4a..c68335a5 100644
--- a/mandoc.1
+++ b/mandoc.1
@@ -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
diff --git a/mandoc.h b/mandoc.h
index 97e37afd..416702a0 100644
--- a/mandoc.h
+++ b/mandoc.h
@@ -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);
diff --git a/manpath.c b/manpath.c
index fa0791ba..7b6f0c1a 100644
--- a/manpath.c
+++ b/manpath.c
@@ -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);
}
diff --git a/read.c b/read.c
index dedb234d..2327b6ee 100644
--- a/read.c
+++ b/read.c
@@ -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",