--- old/usr/src/cmd/mandoc/Makefile.common	Thu Aug  9 15:28:33 2018
+++ new/usr/src/cmd/mandoc/Makefile.common	Thu Aug  9 15:28:33 2018
@@ -76,8 +76,11 @@
 
 OBJS +=		compat_ohash.o
 
+# XXX gcc 4.4.4 false positive
+roff.o :=	CERRWARN += -_gcc=-Wno-uninitialized
+
 CFLAGS +=	$(CC_VERBOSE)
-CSTD =	$(CSTD_GNU99)
+CSTD=		$(CSTD_GNU99)
 
 CPPFLAGS +=	-DOSNAME="\"illumos\"" -D_FILE_OFFSET_BITS=64
 
--- old/usr/src/cmd/mandoc/chars.c	Thu Aug  9 15:28:33 2018
+++ new/usr/src/cmd/mandoc/chars.c	Thu Aug  9 15:28:33 2018
@@ -1,4 +1,4 @@
-/*	$Id: chars.c,v 1.71 2017/06/14 20:57:07 schwarze Exp $ */
+/*	$Id: chars.c,v 1.73 2017/08/23 13:01:29 schwarze Exp $ */
 /*
  * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2011, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@@ -70,17 +70,17 @@
 	/* Text markers. */
 	{ "ci",			"O",		0x25cb	},
 	{ "bu",			"+\bo",		0x2022	},
-	{ "dd",			"|\b=",		0x2021	},
-	{ "dg",			"|\b-",		0x2020	},
+	{ "dd",			"<**>",		0x2021	},
+	{ "dg",			"<*>",		0x2020	},
 	{ "lz",			"<>",		0x25ca	},
 	{ "sq",			"[]",		0x25a1	},
-	{ "ps",			"<par>",	0x00b6	},
-	{ "sc",			"<sec>",	0x00a7	},
+	{ "ps",			"<paragraph>",	0x00b6	},
+	{ "sc",			"<section>",	0x00a7	},
 	{ "lh",			"<=",		0x261c	},
 	{ "rh",			"=>",		0x261e	},
 	{ "at",			"@",		0x0040	},
 	{ "sh",			"#",		0x0023	},
-	{ "CR",			"_|",		0x21b5	},
+	{ "CR",			"<cr>",		0x21b5	},
 	{ "OK",			"\\/",		0x2713	},
 	{ "CL",			"<club>",	0x2663	},
 	{ "SP",			"<spade>",	0x2660	},
@@ -173,11 +173,11 @@
 	{ "OR",			"v",		0x2228	},
 	{ "no",			"~",		0x00ac	},
 	{ "tno",		"~",		0x00ac	},
-	{ "te",			"3",		0x2203	},
-	{ "fa",			"-\bV",		0x2200	},
-	{ "st",			"-)",		0x220b	},
-	{ "tf",			".:.",		0x2234	},
-	{ "3d",			".:.",		0x2234	},
+	{ "te",			"<there\037exists>", 0x2203 },
+	{ "fa",			"<for\037all>",	0x2200	},
+	{ "st",			"<such\037that>", 0x220b },
+	{ "tf",			"<therefore>",	0x2234	},
+	{ "3d",			"<therefore>",	0x2234	},
 	{ "or",			"|",		0x007c	},
 
 	/* Mathematicals. */
@@ -193,8 +193,8 @@
 	{ "tmu",		"x",		0x00d7	},
 	{ "c*",			"O\bx",		0x2297	},
 	{ "c+",			"O\b+",		0x2295	},
-	{ "di",			"-:-",		0x00f7	},
-	{ "tdi",		"-:-",		0x00f7	},
+	{ "di",			"/",		0x00f7	},
+	{ "tdi",		"/",		0x00f7	},
 	{ "f/",			"/",		0x2044	},
 	{ "**",			"*",		0x2217	},
 	{ "<=",			"<=",		0x2264	},
@@ -210,38 +210,38 @@
 	{ "=~",			"=~",		0x2245	},
 	{ "~~",			"~~",		0x2248	},
 	{ "~=",			"~=",		0x2248	},
-	{ "pt",			"oc",		0x221d	},
+	{ "pt",			"<proportional\037to>", 0x221d },
 	{ "es",			"{}",		0x2205	},
-	{ "mo",			"E",		0x2208	},
-	{ "nm",			"!E",		0x2209	},
-	{ "sb",			"(=",		0x2282	},
-	{ "nb",			"(!=",		0x2284	},
-	{ "sp",			"=)",		0x2283	},
-	{ "nc",			"!=)",		0x2285	},
-	{ "ib",			"(=\b_",	0x2286	},
-	{ "ip",			"=\b_)",	0x2287	},
-	{ "ca",			"(^)",		0x2229	},
-	{ "cu",			"U",		0x222a	},
-	{ "/_",			"_\b/",		0x2220	},
-	{ "pp",			"_\b|",		0x22a5	},
-	{ "is",			"'\b,\bI",	0x222b	},
-	{ "integral",		"'\b,\bI",	0x222b	},
-	{ "sum",		"E",		0x2211	},
-	{ "product",		"TT",		0x220f	},
-	{ "coproduct",		"U",		0x2210	},
-	{ "gr",			"V",		0x2207	},
-	{ "sr",			"\\/",		0x221a	},
-	{ "sqrt",		"\\/",		0x221a	},
+	{ "mo",			"<element\037of>", 0x2208 },
+	{ "nm",			"<not\037element\037of>", 0x2209 },
+	{ "sb",			"<proper\037subset>", 0x2282 },
+	{ "nb",			"<not\037subset>", 0x2284 },
+	{ "sp",			"<proper\037superset>", 0x2283 },
+	{ "nc",			"<not\037superset>", 0x2285 },
+	{ "ib",			"<subset\037or\037equal>", 0x2286 },
+	{ "ip",			"<superset\037or\037equal>", 0x2287 },
+	{ "ca",			"<intersection>", 0x2229 },
+	{ "cu",			"<union>",	0x222a	},
+	{ "/_",			"<angle>",	0x2220	},
+	{ "pp",			"<perpendicular>", 0x22a5 },
+	{ "is",			"<integral>",	0x222b	},
+	{ "integral",		"<integral>",	0x222b	},
+	{ "sum",		"<sum>",	0x2211	},
+	{ "product",		"<product>",	0x220f	},
+	{ "coproduct",		"<coproduct>",	0x2210	},
+	{ "gr",			"<nabla>",	0x2207	},
+	{ "sr",			"<sqrt>",	0x221a	},
+	{ "sqrt",		"<sqrt>",	0x221a	},
 	{ "lc",			"|~",		0x2308	},
 	{ "rc",			"~|",		0x2309	},
 	{ "lf",			"|_",		0x230a	},
 	{ "rf",			"_|",		0x230b	},
-	{ "if",			"oo",		0x221e	},
-	{ "Ah",			"N",		0x2135	},
-	{ "Im",			"I",		0x2111	},
-	{ "Re",			"R",		0x211c	},
+	{ "if",			"<infinity>",	0x221e	},
+	{ "Ah",			"<Aleph>",	0x2135	},
+	{ "Im",			"<Im>",		0x2111	},
+	{ "Re",			"<Re>",		0x211c	},
 	{ "wp",			"P",		0x2118	},
-	{ "pd",			"a",		0x2202	},
+	{ "pd",			"<del>",	0x2202	},
 	{ "-h",			"/h",		0x210f	},
 	{ "hbar",		"/h",		0x210f	},
 	{ "12",			"1/2",		0x00bd	},
@@ -251,9 +251,9 @@
 	{ "38",			"3/8",		0x215C	},
 	{ "58",			"5/8",		0x215D	},
 	{ "78",			"7/8",		0x215E	},
-	{ "S1",			"1",		0x00B9	},
-	{ "S2",			"2",		0x00B2	},
-	{ "S3",			"3",		0x00B3	},
+	{ "S1",			"^1",		0x00B9	},
+	{ "S2",			"^2",		0x00B2	},
+	{ "S3",			"^3",		0x00B3	},
 
 	/* Ligatures. */
 	{ "ff",			"ff",		0xfb00	},
@@ -346,8 +346,8 @@
 	{ "oa",			"o\ba",		0x00e5	},
 
 	/* Special letters. */
-	{ "-D",			"-\bD",		0x00d0	},
-	{ "Sd",			"d",		0x00f0	},
+	{ "-D",			"Dh",		0x00d0	},
+	{ "Sd",			"dh",		0x00f0	},
 	{ "TP",			"Th",		0x00de	},
 	{ "Tp",			"th",		0x00fe	},
 	{ ".i",			"i",		0x0131	},
@@ -364,11 +364,11 @@
 	{ "Fn",			",\bf",		0x0192	},
 
 	/* Units. */
-	{ "de",			"<deg>",	0x00b0	},
-	{ "%0",			"%o",		0x2030	},
+	{ "de",			"<degree>",	0x00b0	},
+	{ "%0",			"<permille>",	0x2030	},
 	{ "fm",			"\'",		0x2032	},
 	{ "sd",			"''",		0x2033	},
-	{ "mc",			",\bu",		0x00b5	},
+	{ "mc",			"<micro>",	0x00b5	},
 	{ "Of",			"_\ba",		0x00aa	},
 	{ "Om",			"_\bo",		0x00ba	},
 
@@ -375,57 +375,57 @@
 	/* Greek characters. */
 	{ "*A",			"A",		0x0391	},
 	{ "*B",			"B",		0x0392	},
-	{ "*G",			"G",		0x0393	},
-	{ "*D",			"_\b/_\b\\",	0x0394	},
+	{ "*G",			"<Gamma>",	0x0393	},
+	{ "*D",			"<Delta>",	0x0394	},
 	{ "*E",			"E",		0x0395	},
 	{ "*Z",			"Z",		0x0396	},
 	{ "*Y",			"H",		0x0397	},
-	{ "*H",			"-\bO",		0x0398	},
+	{ "*H",			"<Theta>",	0x0398	},
 	{ "*I",			"I",		0x0399	},
 	{ "*K",			"K",		0x039a	},
-	{ "*L",			"/\\",		0x039b	},
+	{ "*L",			"<Lambda>",	0x039b	},
 	{ "*M",			"M",		0x039c	},
 	{ "*N",			"N",		0x039d	},
-	{ "*C",			"_\bH",		0x039e	},
+	{ "*C",			"<Xi>",		0x039e	},
 	{ "*O",			"O",		0x039f	},
-	{ "*P",			"TT",		0x03a0	},
+	{ "*P",			"<Pi>",		0x03a0	},
 	{ "*R",			"P",		0x03a1	},
-	{ "*S",			"S",		0x03a3	},
+	{ "*S",			"<Sigma>",	0x03a3	},
 	{ "*T",			"T",		0x03a4	},
 	{ "*U",			"Y",		0x03a5	},
-	{ "*F",			"I\bO",		0x03a6	},
+	{ "*F",			"<Phi>",	0x03a6	},
 	{ "*X",			"X",		0x03a7	},
-	{ "*Q",			"I\bY",		0x03a8	},
-	{ "*W",			"_\bO",		0x03a9	},
-	{ "*a",			"a",		0x03b1	},
-	{ "*b",			"B",		0x03b2	},
-	{ "*g",			"y",		0x03b3	},
-	{ "*d",			"d",		0x03b4	},
-	{ "*e",			"e",		0x03b5	},
-	{ "*z",			",\bC",		0x03b6	},
-	{ "*y",			"n",		0x03b7	},
-	{ "*h",			"-\b0",		0x03b8	},
-	{ "*i",			"i",		0x03b9	},
-	{ "*k",			"k",		0x03ba	},
-	{ "*l",			">\b\\",	0x03bb	},
-	{ "*m",			",\bu",		0x03bc	},
-	{ "*n",			"v",		0x03bd	},
-	{ "*c",			",\bE",		0x03be	},
+	{ "*Q",			"<Psi>",	0x03a8	},
+	{ "*W",			"<Omega>",	0x03a9	},
+	{ "*a",			"<alpha>",	0x03b1	},
+	{ "*b",			"<beta>",	0x03b2	},
+	{ "*g",			"<gamma>",	0x03b3	},
+	{ "*d",			"<delta>",	0x03b4	},
+	{ "*e",			"<epsilon>",	0x03b5	},
+	{ "*z",			"<zeta>",	0x03b6	},
+	{ "*y",			"<eta>",	0x03b7	},
+	{ "*h",			"<theta>",	0x03b8	},
+	{ "*i",			"<iota>",	0x03b9	},
+	{ "*k",			"<kappa>",	0x03ba	},
+	{ "*l",			"<lambda>",	0x03bb	},
+	{ "*m",			"<mu>",		0x03bc	},
+	{ "*n",			"<nu>",		0x03bd	},
+	{ "*c",			"<xi>",		0x03be	},
 	{ "*o",			"o",		0x03bf	},
-	{ "*p",			"-\bn",		0x03c0	},
-	{ "*r",			"p",		0x03c1	},
-	{ "*s",			"-\bo",		0x03c3	},
-	{ "*t",			"~\bt",		0x03c4	},
-	{ "*u",			"u",		0x03c5	},
-	{ "*f",			"|\bo",		0x03d5	},
-	{ "*x",			"x",		0x03c7	},
-	{ "*q",			"|\bu",		0x03c8	},
-	{ "*w",			"w",		0x03c9	},
-	{ "+h",			"-\b0",		0x03d1	},
-	{ "+f",			"|\bo",		0x03c6	},
-	{ "+p",			"-\bw",		0x03d6	},
-	{ "+e",			"e",		0x03f5	},
-	{ "ts",			"s",		0x03c2	},
+	{ "*p",			"<pi>",		0x03c0	},
+	{ "*r",			"<rho>",	0x03c1	},
+	{ "*s",			"<sigma>",	0x03c3	},
+	{ "*t",			"<tau>",	0x03c4	},
+	{ "*u",			"<upsilon>",	0x03c5	},
+	{ "*f",			"<phi>",	0x03d5	},
+	{ "*x",			"<chi>",	0x03c7	},
+	{ "*q",			"<psi>",	0x03c8	},
+	{ "*w",			"<omega>",	0x03c9	},
+	{ "+h",			"<theta>",	0x03d1	},
+	{ "+f",			"<phi>",	0x03c6	},
+	{ "+p",			"<pi>",		0x03d6	},
+	{ "+e",			"<epsilon>",	0x03f5	},
+	{ "ts",			"<sigma>",	0x03c2	},
 };
 
 static	struct ohash	  mchars;
--- old/usr/src/cmd/mandoc/config.h	Thu Aug  9 15:28:33 2018
+++ new/usr/src/cmd/mandoc/config.h	Thu Aug  9 15:28:33 2018
@@ -1,32 +1,48 @@
 #ifndef MANDOC_CONFIG_H
-#define	MANDOC_CONFIG_H
+#define MANDOC_CONFIG_H
 
 #include <sys/types.h>
 
-#define	MAN_CONF_FILE "/etc/man.conf"
-#define	MANPATH_BASE "/usr/share/man"
-#define	MANPATH_DEFAULT "/usr/share/man:/usr/gnu/share/man"
+#define MAN_CONF_FILE "/etc/man.conf"
+#define MANPATH_BASE "/usr/share/man"
+#define MANPATH_DEFAULT "/usr/share/man:/usr/gnu/share/man"
+#define UTF8_LOCALE "en_US.UTF-8"
+#define EFTYPE EINVAL
+#define O_DIRECTORY 0
+#define HAVE_CMSG_XPG42 0
+#define HAVE_DIRENT_NAMLEN 0
+#define HAVE_ENDIAN 1
+#define HAVE_ERR 1
+#define HAVE_FTS 1
+#define HAVE_FTS_COMPARE_CONST 0
+#define HAVE_GETLINE 1
+#define HAVE_GETSUBOPT 1
+#define HAVE_ISBLANK 1
+#define HAVE_MKDTEMP 1
+#define HAVE_NTOHL 1
+#define HAVE_PLEDGE 0
+#define HAVE_PROGNAME 1
+#define HAVE_REALLOCARRAY 1
+#define HAVE_RECALLOCARRAY 1
+#define HAVE_REWB_BSD 1
+#define HAVE_REWB_SYSV 1
+#define HAVE_SANDBOX_INIT 0
+#define HAVE_STRCASESTR 1
+#define HAVE_STRINGLIST 0
+#define HAVE_STRLCAT 1
+#define HAVE_STRLCPY 1
+#define HAVE_STRNDUP 1
+#define HAVE_STRPTIME 1
+#define HAVE_STRSEP 1
+#define HAVE_STRTONUM 1
+#define HAVE_SYS_ENDIAN 0
+#define HAVE_VASPRINTF 1
+#define HAVE_WCHAR 1
+#define HAVE_OHASH 0
 
-#define	UTF8_LOCALE "en_US.UTF-8"
-#define	EFTYPE EINVAL
+#define BINM_APROPOS "apropos"
+#define BINM_MAKEWHATIS "man -w"
+#define BINM_MAN "man"
+#define BINM_WHATIS "whatis"
 
-#define	HAVE_ENDIAN 1
-#define	HAVE_ERR 1
-#define	HAVE_FTS 1
-#define	HAVE_NTOHL 1
-#define	HAVE_OHASH 0
-#define	HAVE_PLEDGE 0
-#define	HAVE_PROGNAME 1
-#define	HAVE_REWB_BSD 1
-#define	HAVE_REWB_SYSV 1
-#define	HAVE_SANDBOX_INIT 0
-#define	HAVE_STRPTIME 1
-#define	HAVE_SYS_ENDIAN 0
-#define	HAVE_WCHAR 1
-
-#define	BINM_APROPOS "apropos"
-#define	BINM_MAN "man"
-#define	BINM_WHATIS "whatis"
-#define	BINM_MAKEWHATIS "man -w"
-
 #endif /* MANDOC_CONFIG_H */
--- old/usr/src/cmd/mandoc/eqn_term.c	Thu Aug  9 15:28:33 2018
+++ new/usr/src/cmd/mandoc/eqn_term.c	Thu Aug  9 15:28:33 2018
@@ -1,4 +1,4 @@
-/*	$Id: eqn_term.c,v 1.13 2017/07/08 14:51:04 schwarze Exp $ */
+/*	$Id: eqn_term.c,v 1.17 2017/08/23 21:56:20 schwarze Exp $ */
 /*
  * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@@ -20,6 +20,7 @@
 #include <sys/types.h>
 
 #include <assert.h>
+#include <ctype.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -51,6 +52,7 @@
 eqn_box(struct termp *p, const struct eqn_box *bp)
 {
 	const struct eqn_box *child;
+	const char *cp;
 	int delim;
 
 	/* Delimiters around this box? */
@@ -67,7 +69,16 @@
 	     ((bp->parent->type == EQN_LIST && bp->expectargs == 1) ||
 	      (bp->parent->type == EQN_SUBEXPR &&
 	       bp->pos != EQNPOS_SQRT)))))) {
-		if (bp->parent->type == EQN_SUBEXPR && bp->prev != NULL)
+		if ((bp->parent->type == EQN_SUBEXPR && bp->prev != NULL) ||
+		    (bp->type == EQN_LIST &&
+		     bp->first != NULL &&
+		     bp->first->type != EQN_PILE &&
+		     bp->first->type != EQN_MATRIX &&
+		     bp->prev != NULL &&
+		     (bp->prev->type == EQN_LIST ||
+		      (bp->prev->type == EQN_TEXT &&
+		       (*bp->prev->text == '\\' ||
+		        isalpha((unsigned char)*bp->prev->text))))))
 			p->flags |= TERMP_NOSPACE;
 		term_word(p, bp->left != NULL ? bp->left : "(");
 		p->flags |= TERMP_NOSPACE;
@@ -80,8 +91,17 @@
 	if (bp->font != EQNFONT_NONE)
 		term_fontpush(p, fontmap[(int)bp->font]);
 
-	if (bp->text != NULL)
+	if (bp->text != NULL) {
+		if (strchr("!\"'),.:;?]}", *bp->text) != NULL)
+			p->flags |= TERMP_NOSPACE;
 		term_word(p, bp->text);
+		if ((cp = strchr(bp->text, '\0')) > bp->text &&
+		    (strchr("\"'([{", cp[-1]) != NULL ||
+		     (bp->prev == NULL && (cp[-1] == '-' ||
+		      (cp >= bp->text + 5 &&
+		       strcmp(cp - 5, "\\[mi]") == 0)))))
+			p->flags |= TERMP_NOSPACE;
+	}
 
 	/* Special box types. */
 
@@ -98,9 +118,9 @@
 		term_word(p, bp->pos == EQNPOS_OVER ? "/" :
 		    (bp->pos == EQNPOS_SUP ||
 		     bp->pos == EQNPOS_TO) ? "^" : "_");
-		p->flags |= TERMP_NOSPACE;
 		child = child->next;
 		if (child != NULL) {
+			p->flags |= TERMP_NOSPACE;
 			eqn_box(p, child);
 			if (bp->pos == EQNPOS_FROMTO ||
 			    bp->pos == EQNPOS_SUBSUP) {
--- old/usr/src/cmd/mandoc/html.c	Thu Aug  9 15:28:34 2018
+++ new/usr/src/cmd/mandoc/html.c	Thu Aug  9 15:28:34 2018
@@ -1,7 +1,7 @@
-/*	$Id: html.c,v 1.219 2017/07/15 17:57:51 schwarze Exp $ */
+/*	$Id: html.c,v 1.238 2018/06/25 16:54:59 schwarze Exp $ */
 /*
  * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011-2015, 2017, 2018 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
@@ -22,6 +22,7 @@
 #include <assert.h>
 #include <ctype.h>
 #include <stdarg.h>
+#include <stddef.h>
 #include <stdio.h>
 #include <stdint.h>
 #include <stdlib.h>
@@ -29,6 +30,7 @@
 #include <unistd.h>
 
 #include "mandoc_aux.h"
+#include "mandoc_ohash.h"
 #include "mandoc.h"
 #include "roff.h"
 #include "out.h"
@@ -59,6 +61,7 @@
 	{"meta",	HTML_NOSTACK | HTML_AUTOCLOSE | HTML_NLALL},
 	{"title",	HTML_NLAROUND},
 	{"div",		HTML_NLAROUND},
+	{"div",		0},
 	{"h1",		HTML_NLAROUND},
 	{"h2",		HTML_NLAROUND},
 	{"span",	0},
@@ -66,8 +69,6 @@
 	{"br",		HTML_NOSTACK | HTML_AUTOCLOSE | HTML_NLALL},
 	{"a",		0},
 	{"table",	HTML_NLALL | HTML_INDENT},
-	{"colgroup",	HTML_NLALL | HTML_INDENT},
-	{"col",		HTML_NOSTACK | HTML_AUTOCLOSE | HTML_NLALL},
 	{"tr",		HTML_NLALL | HTML_INDENT},
 	{"td",		HTML_NLAROUND},
 	{"li",		HTML_NLAROUND | HTML_INDENT},
@@ -103,20 +104,9 @@
 	{"mover",	0},
 };
 
-static	const char	*const roffscales[SCALE_MAX] = {
-	"cm", /* SCALE_CM */
-	"in", /* SCALE_IN */
-	"pc", /* SCALE_PC */
-	"pt", /* SCALE_PT */
-	"em", /* SCALE_EM */
-	"em", /* SCALE_MM */
-	"ex", /* SCALE_EN */
-	"ex", /* SCALE_BU */
-	"em", /* SCALE_VS */
-	"ex", /* SCALE_FS */
-};
+/* Avoid duplicate HTML id= attributes. */
+static	struct ohash	 id_unique;
 
-static	void	 a2width(const char *, struct roffsu *);
 static	void	 print_byte(struct html *, char);
 static	void	 print_endword(struct html *);
 static	void	 print_indent(struct html *);
@@ -143,6 +133,8 @@
 	if (outopts->fragment)
 		h->oflags |= HTML_FRAGMENT;
 
+	mandoc_ohash_init(&id_unique, 4, 0);
+
 	return h;
 }
 
@@ -151,15 +143,22 @@
 {
 	struct tag	*tag;
 	struct html	*h;
+	char		*cp;
+	unsigned int	 slot;
 
 	h = (struct html *)p;
-
 	while ((tag = h->tag) != NULL) {
 		h->tag = tag->next;
 		free(tag);
 	}
-
 	free(h);
+
+	cp = ohash_first(&id_unique, &slot);
+	while (cp != NULL) {
+		free(cp);
+		cp = ohash_next(&id_unique, &slot);
+	}
+	ohash_delete(&id_unique);
 }
 
 void
@@ -168,9 +167,14 @@
 	struct tag	*t;
 
 	print_otag(h, TAG_META, "?", "charset", "utf-8");
+	if (h->style != NULL) {
+		print_otag(h, TAG_LINK, "?h??", "rel", "stylesheet",
+		    h->style, "type", "text/css", "media", "all");
+		return;
+	}
 
 	/*
-	 * Print a default style-sheet.
+	 * Print a minimal embedded style sheet.
 	 */
 
 	t = print_otag(h, TAG_STYLE, "");
@@ -181,11 +185,23 @@
 	print_text(h, "td.head-vol { text-align: center; }");
 	print_endline(h);
 	print_text(h, "div.Pp { margin: 1ex 0ex; }");
+	print_endline(h);
+	print_text(h, "div.Nd, div.Bf, div.Op { display: inline; }");
+	print_endline(h);
+	print_text(h, "span.Pa, span.Ad { font-style: italic; }");
+	print_endline(h);
+	print_text(h, "span.Ms { font-weight: bold; }");
+	print_endline(h);
+	print_text(h, "dl.Bl-diag ");
+	print_byte(h, '>');
+	print_text(h, " dt { font-weight: bold; }");
+	print_endline(h);
+	print_text(h, "code.Nm, code.Fl, code.Cm, code.Ic, "
+	    "code.In, code.Fd, code.Fn,");
+	print_endline(h);
+	print_text(h, "code.Cd { font-weight: bold; "
+	    "font-family: inherit; }");
 	print_tagq(h, t);
-
-	if (h->style)
-		print_otag(h, TAG_LINK, "?h??", "rel", "stylesheet",
-		    h->style, "type", "text/css", "media", "all");
 }
 
 static void
@@ -239,10 +255,12 @@
 }
 
 char *
-html_make_id(const struct roff_node *n)
+html_make_id(const struct roff_node *n, int unique)
 {
 	const struct roff_node	*nch;
-	char			*buf, *cp;
+	char			*buf, *bufs, *cp;
+	unsigned int		 slot;
+	int			 suffix;
 
 	for (nch = n->child; nch != NULL; nch = nch->next)
 		if (nch->type != ROFFT_TEXT)
@@ -250,65 +268,46 @@
 
 	buf = NULL;
 	deroff(&buf, n);
+	if (buf == NULL)
+		return NULL;
 
-	/* http://www.w3.org/TR/html5/dom.html#the-id-attribute */
+	/*
+	 * In ID attributes, only use ASCII characters that are
+	 * permitted in URL-fragment strings according to the
+	 * explicit list at:
+	 * https://url.spec.whatwg.org/#url-fragment-string
+	 */
 
 	for (cp = buf; *cp != '\0'; cp++)
-		if (*cp == ' ')
+		if (isalnum((unsigned char)*cp) == 0 &&
+		    strchr("!$&'()*+,-./:;=?@_~", *cp) == NULL)
 			*cp = '_';
 
-	return buf;
-}
+	if (unique == 0)
+		return buf;
 
-int
-html_strlen(const char *cp)
-{
-	size_t		 rsz;
-	int		 skip, sz;
+	/* Avoid duplicate HTML id= attributes. */
 
-	/*
-	 * Account for escaped sequences within string length
-	 * calculations.  This follows the logic in term_strlen() as we
-	 * must calculate the width of produced strings.
-	 * Assume that characters are always width of "1".  This is
-	 * hacky, but it gets the job done for approximation of widths.
-	 */
-
-	sz = 0;
-	skip = 0;
-	while (1) {
-		rsz = strcspn(cp, "\\");
-		if (rsz) {
-			cp += rsz;
-			if (skip) {
-				skip = 0;
-				rsz--;
+	bufs = NULL;
+	suffix = 1;
+	slot = ohash_qlookup(&id_unique, buf);
+	cp = ohash_find(&id_unique, slot);
+	if (cp != NULL) {
+		while (cp != NULL) {
+			free(bufs);
+			if (++suffix > 127) {
+				free(buf);
+				return NULL;
 			}
-			sz += rsz;
+			mandoc_asprintf(&bufs, "%s_%d", buf, suffix);
+			slot = ohash_qlookup(&id_unique, bufs);
+			cp = ohash_find(&id_unique, slot);
 		}
-		if ('\0' == *cp)
-			break;
-		cp++;
-		switch (mandoc_escape(&cp, NULL, NULL)) {
-		case ESCAPE_ERROR:
-			return sz;
-		case ESCAPE_UNICODE:
-		case ESCAPE_NUMBERED:
-		case ESCAPE_SPECIAL:
-		case ESCAPE_OVERSTRIKE:
-			if (skip)
-				skip = 0;
-			else
-				sz++;
-			break;
-		case ESCAPE_SKIPCHAR:
-			skip = 1;
-			break;
-		default:
-			break;
-		}
+		free(buf);
+		buf = bufs;
 	}
-	return sz;
+	ohash_insert(&id_unique, slot, buf);
+	return buf;
 }
 
 static int
@@ -490,13 +489,10 @@
 print_otag(struct html *h, enum htmltag tag, const char *fmt, ...)
 {
 	va_list		 ap;
-	struct roffsu	 mysu, *su;
-	char		 numbuf[16];
 	struct tag	*t;
 	const char	*attr;
 	char		*arg1, *arg2;
-	double		 v;
-	int		 i, have_style, tflags;
+	int		 tflags;
 
 	tflags = htmltags[tag].flags;
 
@@ -536,17 +532,12 @@
 
 	va_start(ap, fmt);
 
-	have_style = 0;
 	while (*fmt != '\0') {
-		if (*fmt == 's') {
-			have_style = 1;
-			fmt++;
-			break;
-		}
 
-		/* Parse a non-style attribute and its arguments. */
+		/* Parse attributes and arguments. */
 
 		arg1 = va_arg(ap, char *);
+		arg2 = NULL;
 		switch (*fmt++) {
 		case 'c':
 			attr = "class";
@@ -557,6 +548,10 @@
 		case 'i':
 			attr = "id";
 			break;
+		case 's':
+			attr = "style";
+			arg2 = va_arg(ap, char *);
+			break;
 		case '?':
 			attr = arg1;
 			arg1 = va_arg(ap, char *);
@@ -564,13 +559,12 @@
 		default:
 			abort();
 		}
-		arg2 = NULL;
 		if (*fmt == 'M')
 			arg2 = va_arg(ap, char *);
 		if (arg1 == NULL)
 			continue;
 
-		/* Print the non-style attributes. */
+		/* Print the attributes. */
 
 		print_byte(h, ' ');
 		print_word(h, attr);
@@ -597,114 +591,19 @@
 			fmt++;
 			break;
 		default:
-			print_encode(h, arg1, NULL, 1);
-			break;
-		}
-		print_byte(h, '"');
-	}
-
-	/* Print out styles. */
-
-	while (*fmt != '\0') {
-		arg1 = NULL;
-		su = NULL;
-
-		/* First letter: input argument type. */
-
-		switch (*fmt++) {
-		case 'h':
-			i = va_arg(ap, int);
-			su = &mysu;
-			SCALE_HS_INIT(su, i);
-			break;
-		case 's':
-			arg1 = va_arg(ap, char *);
-			break;
-		case 'u':
-			su = va_arg(ap, struct roffsu *);
-			break;
-		case 'w':
-			if ((arg2 = va_arg(ap, char *)) != NULL) {
-				su = &mysu;
-				a2width(arg2, su);
+			if (arg2 == NULL)
+				print_encode(h, arg1, NULL, 1);
+			else {
+				print_word(h, arg1);
+				print_byte(h, ':');
+				print_byte(h, ' ');
+				print_word(h, arg2);
+				print_byte(h, ';');
 			}
-			if (*fmt == '*') {
-				if (su != NULL && su->unit == SCALE_EN &&
-				    su->scale > 5.9 && su->scale < 6.1)
-					su = NULL;
-				fmt++;
-			}
-			if (*fmt == '+') {
-				if (su != NULL) {
-					/* Make even bold text fit. */
-					su->scale *= 1.2;
-					/* Add padding. */
-					su->scale += 3.0;
-				}
-				fmt++;
-			}
-			if (*fmt == '-') {
-				if (su != NULL)
-					su->scale *= -1.0;
-				fmt++;
-			}
 			break;
-		default:
-			abort();
 		}
-
-		/* Second letter: style name. */
-
-		switch (*fmt++) {
-		case 'h':
-			attr = "height";
-			break;
-		case 'i':
-			attr = "text-indent";
-			break;
-		case 'l':
-			attr = "margin-left";
-			break;
-		case 'w':
-			attr = "width";
-			break;
-		case 'W':
-			attr = "min-width";
-			break;
-		case '?':
-			attr = arg1;
-			arg1 = va_arg(ap, char *);
-			break;
-		default:
-			abort();
-		}
-		if (su == NULL && arg1 == NULL)
-			continue;
-
-		if (have_style == 1)
-			print_word(h, " style=\"");
-		else
-			print_byte(h, ' ');
-		print_word(h, attr);
-		print_byte(h, ':');
-		print_byte(h, ' ');
-		if (su != NULL) {
-			v = su->scale;
-			if (su->unit == SCALE_MM && (v /= 100.0) == 0.0)
-				v = 1.0;
-			else if (su->unit == SCALE_BU)
-				v /= 24.0;
-			(void)snprintf(numbuf, sizeof(numbuf), "%.2f", v);
-			print_word(h, numbuf);
-			print_word(h, roffscales[su->unit]);
-		} else
-			print_word(h, arg1);
-		print_byte(h, ';');
-		have_style = 2;
-	}
-	if (have_style == 2)
 		print_byte(h, '"');
-
+	}
 	va_end(ap);
 
 	/* Accommodate for "well-formed" singleton escaping. */
@@ -769,6 +668,32 @@
 }
 
 void
+print_gen_comment(struct html *h, struct roff_node *n)
+{
+	int	 wantblank;
+
+	print_word(h, "<!-- This is an automatically generated file."
+	    "  Do not edit.");
+	h->indent = 1;
+	wantblank = 0;
+	while (n != NULL && n->type == ROFFT_COMMENT) {
+		if (strstr(n->string, "-->") == NULL &&
+		    (wantblank || *n->string != '\0')) {
+			print_endline(h);
+			print_indent(h);
+			print_word(h, n->string);
+			wantblank = *n->string != '\0';
+		}
+		n = n->next;
+	}
+	if (wantblank)
+		print_endline(h);
+	print_word(h, " -->");
+	print_endline(h);
+	h->indent = 0;
+}
+
+void
 print_text(struct html *h, const char *word)
 {
 	if (h->col && (h->flags & HTML_NOSPACE) == 0) {
@@ -958,22 +883,4 @@
 {
 	while (*cp != '\0')
 		print_byte(h, *cp++);
-}
-
-/*
- * Calculate the scaling unit passed in a `-width' argument.  This uses
- * either a native scaling unit (e.g., 1i, 2m) or the string length of
- * the value.
- */
-static void
-a2width(const char *p, struct roffsu *su)
-{
-	const char	*end;
-
-	end = a2roffsu(p, su, SCALE_MAX);
-	if (end == NULL || *end != '\0') {
-		su->unit = SCALE_EN;
-		su->scale = html_strlen(p);
-	} else if (su->scale < 0.0)
-		su->scale = 0.0;
 }
--- old/usr/src/cmd/mandoc/html.h	Thu Aug  9 15:28:34 2018
+++ new/usr/src/cmd/mandoc/html.h	Thu Aug  9 15:28:34 2018
@@ -1,7 +1,7 @@
-/*	$Id: html.h,v 1.87 2017/07/08 14:51:04 schwarze Exp $ */
+/*	$Id: html.h,v 1.92 2018/06/25 16:54:59 schwarze Exp $ */
 /*
  * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2017, 2018 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
@@ -23,6 +23,7 @@
 	TAG_META,
 	TAG_TITLE,
 	TAG_DIV,
+	TAG_IDIV,
 	TAG_H1,
 	TAG_H2,
 	TAG_SPAN,
@@ -30,8 +31,6 @@
 	TAG_BR,
 	TAG_A,
 	TAG_TABLE,
-	TAG_COLGROUP,
-	TAG_COL,
 	TAG_TR,
 	TAG_TD,
 	TAG_LI,
@@ -119,6 +118,7 @@
 
 void		  roff_html_pre(struct html *, const struct roff_node *);
 
+void		  print_gen_comment(struct html *, struct roff_node *);
 void		  print_gen_decls(struct html *);
 void		  print_gen_head(struct html *);
 struct tag	 *print_otag(struct html *, enum htmltag, const char *, ...);
@@ -131,5 +131,4 @@
 void		  print_paragraph(struct html *);
 void		  print_endline(struct html *);
 
-char		 *html_make_id(const struct roff_node *);
-int		  html_strlen(const char *);
+char		 *html_make_id(const struct roff_node *, int);
--- old/usr/src/cmd/mandoc/libmandoc.h	Thu Aug  9 15:28:34 2018
+++ new/usr/src/cmd/mandoc/libmandoc.h	Thu Aug  9 15:28:34 2018
@@ -1,4 +1,4 @@
-/*	$Id: libmandoc.h,v 1.70 2017/07/08 17:52:49 schwarze Exp $ */
+/*	$Id: libmandoc.h,v 1.71 2018/04/09 22:27:04 schwarze Exp $ */
 /*
  * Copyright (c) 2009, 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@@ -66,7 +66,7 @@
 enum rofferr	 roff_parseln(struct roff *, int, struct buf *, int *);
 void		 roff_endparse(struct roff *);
 void		 roff_setreg(struct roff *, const char *, int, char sign);
-int		 roff_getreg(const struct roff *, const char *);
+int		 roff_getreg(struct roff *, const char *);
 char		*roff_strdup(const struct roff *, const char *);
 int		 roff_getcontrol(const struct roff *,
 			const char *, int *);
--- old/usr/src/cmd/mandoc/main.c	Thu Aug  9 15:28:34 2018
+++ new/usr/src/cmd/mandoc/main.c	Thu Aug  9 15:28:34 2018
@@ -1,7 +1,7 @@
-/*	$Id: main.c,v 1.301 2017/07/26 10:21:55 schwarze Exp $ */
+/*	$Id: main.c,v 1.306 2018/05/14 14:10:23 schwarze Exp $ */
 /*
  * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010-2012, 2014-2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2012, 2014-2018 Ingo Schwarze <schwarze@openbsd.org>
  * Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -19,7 +19,9 @@
 #include "config.h"
 
 #include <sys/types.h>
+#include <sys/ioctl.h>
 #include <sys/param.h>	/* MACHINE */
+#include <sys/termios.h>
 #include <sys/wait.h>
 
 #include <assert.h>
@@ -120,6 +122,7 @@
 	struct manconf	 conf;
 	struct mansearch search;
 	struct curparse	 curp;
+	struct winsize	 ws;
 	struct tag_files *tag_files;
 	struct manpage	*res, *resp;
 	const char	*progname, *sec, *thisarg;
@@ -129,7 +132,7 @@
 	size_t		 i, sz;
 	int		 prio, best_prio;
 	enum outmode	 outmode;
-	int		 fd;
+	int		 fd, startdir;
 	int		 show_usage;
 	int		 options;
 	int		 use_pager;
@@ -316,6 +319,16 @@
 	    !isatty(STDOUT_FILENO))
 		use_pager = 0;
 
+	if (use_pager &&
+	    (conf.output.width == 0 || conf.output.indent == 0) &&
+	    ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1 &&
+	    ws.ws_col > 1) {
+		if (conf.output.width == 0 && ws.ws_col < 79)
+			conf.output.width = ws.ws_col - 1;
+		if (conf.output.indent == 0 && ws.ws_col < 66)
+			conf.output.indent = 3;
+	}
+
 #if HAVE_PLEDGE
 	if (!use_pager)
 		if (pledge("stdio rpath", NULL) == -1)
@@ -374,15 +387,34 @@
 		    argc, argv, &res, &sz))
 			usage(search.argmode);
 
-		if (sz == 0) {
-			if (search.argmode == ARG_NAME)
-				fs_search(&search, &conf.manpath,
-				    argc, argv, &res, &sz);
-			else
-				warnx("nothing appropriate");
+		if (sz == 0 && search.argmode == ARG_NAME)
+			fs_search(&search, &conf.manpath,
+			    argc, argv, &res, &sz);
+
+		if (search.argmode == ARG_NAME) {
+			for (c = 0; c < argc; c++) {
+				if (strchr(argv[c], '/') == NULL)
+					continue;
+				if (access(argv[c], R_OK) == -1) {
+					warn("%s", argv[c]);
+					continue;
+				}
+				res = mandoc_reallocarray(res,
+				    sz + 1, sizeof(*res));
+				res[sz].file = mandoc_strdup(argv[c]);
+				res[sz].names = NULL;
+				res[sz].output = NULL;
+				res[sz].ipath = SIZE_MAX;
+				res[sz].bits = 0;
+				res[sz].sec = 10;
+				res[sz].form = FORM_SRC;
+				sz++;
+			}
 		}
 
 		if (sz == 0) {
+			if (search.argmode != ARG_NAME)
+				warnx("nothing appropriate");
 			rc = MANDOCLEVEL_BADARG;
 			goto out;
 		}
@@ -466,7 +498,29 @@
 		parse(&curp, STDIN_FILENO, "<stdin>");
 	}
 
+	/*
+	 * Remember the original working directory, if possible.
+	 * This will be needed if some names on the command line
+	 * are page names and some are relative file names.
+	 * Do not error out if the current directory is not
+	 * readable: Maybe it won't be needed after all.
+	 */
+	startdir = open(".", O_RDONLY | O_DIRECTORY);
+
 	while (argc > 0) {
+
+		/*
+		 * Changing directories is not needed in ARG_FILE mode.
+		 * Do it on a best-effort basis.  Even in case of
+		 * failure, some functionality may still work.
+		 */
+		if (resp != NULL) {
+			if (resp->ipath != SIZE_MAX)
+				(void)chdir(conf.manpath.paths[resp->ipath]);
+			else if (startdir != -1)
+				(void)fchdir(startdir);
+		}
+
 		fd = mparse_open(curp.mp, resp != NULL ? resp->file : *argv);
 		if (fd != -1) {
 			if (use_pager) {
@@ -476,14 +530,23 @@
 
 			if (resp == NULL)
 				parse(&curp, fd, *argv);
-			else if (resp->form == FORM_SRC) {
-				/* For .so only; ignore failure. */
-				(void)chdir(conf.manpath.paths[resp->ipath]);
+			else if (resp->form == FORM_SRC)
 				parse(&curp, fd, resp->file);
-			} else
+			else
 				passthrough(resp->file, fd,
 				    conf.output.synopsisonly);
 
+			if (ferror(stdout)) {
+				if (tag_files != NULL) {
+					warn("%s", tag_files->ofn);
+					tag_unlink();
+					tag_files = NULL;
+				} else
+					warn("stdout");
+				rc = MANDOCLEVEL_SYSERR;
+				break;
+			}
+
 			if (argc > 1 && curp.outtype <= OUTT_UTF8) {
 				if (curp.outdata == NULL)
 					outdata_alloc(&curp);
@@ -502,6 +565,10 @@
 		if (--argc)
 			mparse_reset(curp.mp);
 	}
+	if (startdir != -1) {
+		(void)fchdir(startdir);
+		close(startdir);
+	}
 
 	if (curp.outdata != NULL) {
 		switch (curp.outtype) {
@@ -722,7 +789,8 @@
 				    cfg->firstmatch)
 					return 1;
 		}
-		if (res != NULL && *ressz == lastsz)
+		if (res != NULL && *ressz == lastsz &&
+		    strchr(*argv, '/') == NULL)
 			warnx("No entry for %s in the manual.", *argv);
 		lastsz = *ressz;
 		argv++;
@@ -1173,7 +1241,7 @@
 	if (dup2(tag_files->ofd, STDOUT_FILENO) == -1)
 		err((int)MANDOCLEVEL_SYSERR, "pager stdout");
 	close(tag_files->ofd);
-	close(tag_files->tfd);
+	assert(tag_files->tfd == -1);
 
 	/* Do not start the pager before controlling the terminal. */
 
--- old/usr/src/cmd/mandoc/man_html.c	Thu Aug  9 15:28:35 2018
+++ new/usr/src/cmd/mandoc/man_html.c	Thu Aug  9 15:28:35 2018
@@ -1,7 +1,7 @@
-/*	$Id: man_html.c,v 1.145 2017/06/25 11:42:02 schwarze Exp $ */
+/*	$Id: man_html.c,v 1.153 2018/07/27 17:49:31 schwarze Exp $ */
 /*
  * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2013,2014,2015,2017,2018 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
@@ -35,8 +35,6 @@
 
 /* FIXME: have PD set the default vspace width. */
 
-#define	INDENT		  5
-
 #define	MAN_ARGS	  const struct roff_meta *man, \
 			  const struct roff_node *n, \
 			  struct html *h
@@ -48,12 +46,11 @@
 
 static	void		  print_bvspace(struct html *,
 				const struct roff_node *);
-static	void		  print_man_head(MAN_ARGS);
+static	void		  print_man_head(const struct roff_meta *,
+				struct html *);
 static	void		  print_man_nodelist(MAN_ARGS);
 static	void		  print_man_node(MAN_ARGS);
 static	int		  fillmode(struct html *, int);
-static	int		  a2width(const struct roff_node *,
-				struct roffsu *);
 static	int		  man_B_pre(MAN_ARGS);
 static	int		  man_HP_pre(MAN_ARGS);
 static	int		  man_IP_pre(MAN_ARGS);
@@ -68,8 +65,10 @@
 static	int		  man_alt_pre(MAN_ARGS);
 static	int		  man_ign_pre(MAN_ARGS);
 static	int		  man_in_pre(MAN_ARGS);
-static	void		  man_root_post(MAN_ARGS);
-static	void		  man_root_pre(MAN_ARGS);
+static	void		  man_root_post(const struct roff_meta *,
+				struct html *);
+static	void		  man_root_pre(const struct roff_meta *,
+				struct html *);
 
 static	const struct htmlman __mans[MAN_MAX - MAN_TH] = {
 	{ NULL, NULL }, /* TH */
@@ -138,30 +137,34 @@
 void
 html_man(void *arg, const struct roff_man *man)
 {
-	struct html	*h;
-	struct tag	*t;
+	struct html		*h;
+	struct roff_node	*n;
+	struct tag		*t;
 
 	h = (struct html *)arg;
+	n = man->first->child;
 
 	if ((h->oflags & HTML_FRAGMENT) == 0) {
 		print_gen_decls(h);
 		print_otag(h, TAG_HTML, "");
+		if (n->type == ROFFT_COMMENT)
+			print_gen_comment(h, n);
 		t = print_otag(h, TAG_HEAD, "");
-		print_man_head(&man->meta, man->first, h);
+		print_man_head(&man->meta, h);
 		print_tagq(h, t);
 		print_otag(h, TAG_BODY, "");
 	}
 
-	man_root_pre(&man->meta, man->first, h);
+	man_root_pre(&man->meta, h);
 	t = print_otag(h, TAG_DIV, "c", "manual-text");
-	print_man_nodelist(&man->meta, man->first->child, h);
+	print_man_nodelist(&man->meta, n, h);
 	print_tagq(h, t);
-	man_root_post(&man->meta, man->first, h);
+	man_root_post(&man->meta, h);
 	print_tagq(h, NULL);
 }
 
 static void
-print_man_head(MAN_ARGS)
+print_man_head(const struct roff_meta *man, struct html *h)
 {
 	char	*cp;
 
@@ -262,6 +265,8 @@
 			break;
 		print_paragraph(h);
 		return;
+	case ROFFT_COMMENT:
+		return;
 	default:
 		break;
 	}
@@ -359,16 +364,8 @@
 	return had;
 }
 
-static int
-a2width(const struct roff_node *n, struct roffsu *su)
-{
-	if (n->type != ROFFT_TEXT)
-		return 0;
-	return a2roffsu(n->string, su, SCALE_EN) != NULL;
-}
-
 static void
-man_root_pre(MAN_ARGS)
+man_root_pre(const struct roff_meta *man, struct html *h)
 {
 	struct tag	*t, *tt;
 	char		*title;
@@ -396,7 +393,7 @@
 }
 
 static void
-man_root_post(MAN_ARGS)
+man_root_post(const struct roff_meta *man, struct html *h)
 {
 	struct tag	*t, *tt;
 
@@ -419,11 +416,10 @@
 	char	*id;
 
 	if (n->type == ROFFT_HEAD) {
-		id = html_make_id(n);
+		id = html_make_id(n, 1);
 		print_otag(h, TAG_H1, "cTi", "Sh", id);
 		if (id != NULL)
-			print_otag(h, TAG_A, "chR", "selflink", id);
-		free(id);
+			print_otag(h, TAG_A, "chR", "permalink", id);
 	}
 	return 1;
 }
@@ -489,11 +485,10 @@
 	char	*id;
 
 	if (n->type == ROFFT_HEAD) {
-		id = html_make_id(n);
+		id = html_make_id(n, 1);
 		print_otag(h, TAG_H2, "cTi", "Ss", id);
 		if (id != NULL)
-			print_otag(h, TAG_A, "chR", "selflink", id);
-		free(id);
+			print_otag(h, TAG_A, "chR", "permalink", id);
 	}
 	return 1;
 }
@@ -516,7 +511,7 @@
 	const struct roff_node	*nn;
 
 	if (n->type == ROFFT_BODY) {
-		print_otag(h, TAG_DD, "c", "It-tag");
+		print_otag(h, TAG_DD, "");
 		return 1;
 	} else if (n->type != ROFFT_HEAD) {
 		print_otag(h, TAG_DL, "c", "Bl-tag");
@@ -525,7 +520,7 @@
 
 	/* FIXME: width specification. */
 
-	print_otag(h, TAG_DT, "c", "It-tag");
+	print_otag(h, TAG_DT, "");
 
 	/* For IP, only print the first header element. */
 
@@ -550,24 +545,13 @@
 static int
 man_HP_pre(MAN_ARGS)
 {
-	struct roffsu	 sum, sui;
-	const struct roff_node *np;
-
 	if (n->type == ROFFT_HEAD)
 		return 0;
-	else if (n->type != ROFFT_BLOCK)
-		return 1;
 
-	np = n->head->child;
-
-	if (np == NULL || !a2width(np, &sum))
-		SCALE_HS_INIT(&sum, INDENT);
-
-	sui.unit = sum.unit;
-	sui.scale = -sum.scale;
-
-	print_bvspace(h, n);
-	print_otag(h, TAG_DIV, "csului", "Pp", &sum, &sui);
+	if (n->type == ROFFT_BLOCK) {
+		print_bvspace(h, n);
+		print_otag(h, TAG_DIV, "c", "HP");
+	}
 	return 1;
 }
 
@@ -629,18 +613,10 @@
 static int
 man_RS_pre(MAN_ARGS)
 {
-	struct roffsu	 su;
-
 	if (n->type == ROFFT_HEAD)
 		return 0;
-	else if (n->type == ROFFT_BODY)
-		return 1;
-
-	SCALE_HS_INIT(&su, INDENT);
-	if (n->head->child)
-		a2width(n->head->child, &su);
-
-	print_otag(h, TAG_DIV, "sul", &su);
+	if (n->type == ROFFT_BLOCK)
+		print_otag(h, TAG_DIV, "c", "Bd-indent");
 	return 1;
 }
 
--- old/usr/src/cmd/mandoc/man_term.c	Thu Aug  9 15:28:35 2018
+++ new/usr/src/cmd/mandoc/man_term.c	Thu Aug  9 15:28:35 2018
@@ -1,7 +1,7 @@
-/*	$Id: man_term.c,v 1.209 2017/07/31 15:19:06 schwarze Exp $ */
+/*	$Id: man_term.c,v 1.211 2018/06/10 15:12:35 schwarze Exp $ */
 /*
  * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2015, 2017, 2018 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
@@ -675,7 +675,8 @@
 			n = n->prev;
 		} while (n != NULL && n->tok >= MAN_TH &&
 		    termacts[n->tok].flags & MAN_NOTEXT);
-		if (n == NULL || (n->tok == MAN_SS && n->body->child == NULL))
+		if (n == NULL || n->type == ROFFT_COMMENT ||
+		    (n->tok == MAN_SS && n->body->child == NULL))
 			break;
 
 		for (i = 0; i < mt->pardist; i++)
@@ -737,7 +738,8 @@
 			n = n->prev;
 		} while (n != NULL && n->tok >= MAN_TH &&
 		    termacts[n->tok].flags & MAN_NOTEXT);
-		if (n == NULL || (n->tok == MAN_SH && n->body->child == NULL))
+		if (n == NULL || n->type == ROFFT_COMMENT ||
+		    (n->tok == MAN_SH && n->body->child == NULL))
 			break;
 
 		for (i = 0; i < mt->pardist; i++)
@@ -885,7 +887,8 @@
 
 		term_word(p, n->string);
 		goto out;
-
+	case ROFFT_COMMENT:
+		return;
 	case ROFFT_EQN:
 		if ( ! (n->flags & NODE_LINE))
 			p->flags |= TERMP_NOSPACE;
@@ -1029,6 +1032,18 @@
 
 	term_word(p, title);
 	term_flushln(p);
+
+	/*
+	 * Reset the terminal state for more output after the footer:
+	 * Some output modes, in particular PostScript and PDF, print
+	 * the header and the footer into a buffer such that it can be
+	 * reused for multiple output pages, then go on to format the
+	 * main text.
+	 */
+
+        p->tcol->offset = 0;
+        p->flags = 0;
+
 	free(title);
 }
 
--- old/usr/src/cmd/mandoc/man_validate.c	Thu Aug  9 15:28:35 2018
+++ new/usr/src/cmd/mandoc/man_validate.c	Thu Aug  9 15:28:35 2018
@@ -1,7 +1,7 @@
 /*	$OpenBSD$ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2012-2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2012-2018 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
@@ -120,6 +120,7 @@
 	case ROFFT_ROOT:
 		check_root(man, n);
 		break;
+	case ROFFT_COMMENT:
 	case ROFFT_EQN:
 	case ROFFT_TBL:
 		break;
@@ -149,10 +150,9 @@
 static void
 check_root(CHKARGS)
 {
-
 	assert((man->flags & (MAN_BLINE | MAN_ELINE)) == 0);
 
-	if (NULL == man->first->child)
+	if (n->last == NULL || n->last->type == ROFFT_COMMENT)
 		mandoc_msg(MANDOCERR_DOC_EMPTY, man->parse,
 		    n->line, n->pos, NULL);
 	else
--- old/usr/src/cmd/mandoc/mandoc.c	Thu Aug  9 15:28:36 2018
+++ new/usr/src/cmd/mandoc/mandoc.c	Thu Aug  9 15:28:36 2018
@@ -1,7 +1,7 @@
-/*	$Id: mandoc.c,v 1.103 2017/07/03 13:40:19 schwarze Exp $ */
+/*	$Id: mandoc.c,v 1.104 2018/07/28 18:34:15 schwarze Exp $ */
 /*
  * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011-2015, 2017, 2018 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
@@ -541,6 +541,9 @@
 		if (t > time(NULL) + 86400)
 			mandoc_msg(MANDOCERR_DATE_FUTURE, man->parse,
 			    ln, pos, cp);
+		else if (*in != '$' && strcmp(in, cp) != 0)
+			mandoc_msg(MANDOCERR_DATE_NORM, man->parse,
+			    ln, pos, cp);
 		return cp;
 	}
 
--- old/usr/src/cmd/mandoc/mandoc.h	Thu Aug  9 15:28:36 2018
+++ new/usr/src/cmd/mandoc/mandoc.h	Thu Aug  9 15:28:36 2018
@@ -1,7 +1,7 @@
-/*	$Id: mandoc.h,v 1.245 2017/07/08 14:51:04 schwarze Exp $ */
+/*	$Id: mandoc.h,v 1.248 2018/07/28 18:34:15 schwarze Exp $ */
 /*
  * Copyright (c) 2010, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010-2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2018 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
@@ -56,9 +56,10 @@
 	MANDOCERR_STYLE, /* ===== start of style suggestions ===== */
 
 	MANDOCERR_DATE_LEGACY, /* legacy man(7) date format: Dd ... */
+	MANDOCERR_DATE_NORM, /* normalizing date format to: ... */
 	MANDOCERR_TITLE_CASE, /* lower case character in document title */
 	MANDOCERR_RCS_REP, /* duplicate RCS id: ... */
-	MANDOCERR_SEC_TYPO,  /* typo in section name: Sh ... */
+	MANDOCERR_SEC_TYPO,  /* possible typo in section name: Sh ... */
 	MANDOCERR_ARG_QUOTE, /* unterminated quoted argument */
 	MANDOCERR_MACRO_USELESS, /* useless macro: macro */
 	MANDOCERR_BX, /* consider using OS macro: macro */
@@ -68,6 +69,7 @@
 	MANDOCERR_DELIM_NB, /* no blank before trailing delimiter: macro ... */
 	MANDOCERR_FI_SKIP, /* fill mode already enabled, skipping: fi */
 	MANDOCERR_NF_SKIP, /* fill mode already disabled, skipping: nf */
+	MANDOCERR_DASHDASH, /* verbatim "--", maybe consider using \(em */
 	MANDOCERR_FUNC, /* function name without markup: name() */
 	MANDOCERR_SPACE_EOL, /* whitespace at end of input line */
 	MANDOCERR_COMMENT_BAD, /* bad comment style */
--- old/usr/src/cmd/mandoc/mandoc_aux.c	Thu Aug  9 15:28:36 2018
+++ new/usr/src/cmd/mandoc/mandoc_aux.c	Thu Aug  9 15:28:36 2018
@@ -1,4 +1,4 @@
-/*	$Id: mandoc_aux.c,v 1.10 2017/06/12 19:05:47 schwarze Exp $ */
+/*	$Id: mandoc_aux.c,v 1.11 2018/02/07 20:04:57 schwarze Exp $ */
 /*
  * Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@@ -111,8 +111,8 @@
 {
 	char	*p;
 
-	p = mandoc_malloc(sz + 1);
-	memcpy(p, ptr, sz);
-	p[(int)sz] = '\0';
+	p = strndup(ptr, sz);
+	if (p == NULL)
+		err((int)MANDOCLEVEL_SYSERR, NULL);
 	return p;
 }
--- old/usr/src/cmd/mandoc/mandocdb.c	Thu Aug  9 15:28:36 2018
+++ new/usr/src/cmd/mandoc/mandocdb.c	Thu Aug  9 15:28:36 2018
@@ -1,4 +1,4 @@
-/*	$Id: mandocdb.c,v 1.253 2017/07/28 14:48:25 schwarze Exp $ */
+/*	$Id: mandocdb.c,v 1.258 2018/02/23 18:25:57 schwarze Exp $ */
 /*
  * Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2011-2017 Ingo Schwarze <schwarze@openbsd.org>
@@ -19,8 +19,8 @@
 #include "config.h"
 
 #include <sys/types.h>
+#include <sys/mman.h>
 #include <sys/stat.h>
-#include <sys/wait.h>
 
 #include <assert.h>
 #include <ctype.h>
@@ -139,6 +139,8 @@
 			const struct roff_node *);
 static	int	 parse_mdoc_head(struct mpage *, const struct roff_meta *,
 			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 *,
 			const struct roff_node *);
 static	void	 parse_mdoc_fname(struct mpage *, const struct roff_node *);
@@ -207,11 +209,11 @@
 	{ NULL, TYPE_Er, 0 },  /* Er */
 	{ NULL, TYPE_Ev, 0 },  /* Ev */
 	{ NULL, 0, 0 },  /* Ex */
-	{ NULL, TYPE_Fa, 0 },  /* Fa */
+	{ parse_mdoc_Fa, 0, 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_Ft | TYPE_Vt, 0 },  /* Ft */
 	{ NULL, TYPE_Ic, 0 },  /* Ic */
 	{ NULL, TYPE_In, 0 },  /* In */
 	{ NULL, TYPE_Li, 0 },  /* Li */
@@ -319,7 +321,7 @@
 	int		  ch, i;
 
 #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");
 		return (int)MANDOCLEVEL_SYSERR;
 	}
@@ -440,15 +442,6 @@
 			 * 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]);
@@ -1382,7 +1375,12 @@
 		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);
 	free(title);
 }
@@ -1526,7 +1524,12 @@
 			while (' ' == *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);
 			return;
 		}
@@ -1572,6 +1575,20 @@
 }
 
 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,
 	const struct roff_node *n)
 {
@@ -1640,6 +1657,7 @@
 parse_mdoc_Fn(struct mpage *mpage, const struct roff_meta *meta,
 	const struct roff_node *n)
 {
+	uint64_t mask;
 
 	if (n->child == NULL)
 		return 0;
@@ -1646,9 +1664,13 @@
 
 	parse_mdoc_fname(mpage, n->child);
 
-	for (n = n->child->next; n != NULL; n = n->next)
-		if (n->type == ROFFT_TEXT)
-			putkey(mpage, n->string, TYPE_Fa);
+	n = n->child->next;
+	if (n != NULL && n->type == ROFFT_TEXT) {
+		mask = TYPE_Fa;
+		if (n->sec == SEC_SYNOPSIS)
+			mask |= TYPE_Vt;
+		putmdockey(mpage, n, mask, 0);
+	}
 
 	return 0;
 }
@@ -2119,9 +2141,10 @@
 static void
 dbwrite(struct dba *dba)
 {
-	char		 tfn[32];
-	int		 status;
-	pid_t		 child;
+	struct stat	 sb1, sb2;
+	char		 tfn[33], *cp1, *cp2;
+	off_t		 i;
+	int		 fd1, fd2;
 
 	/*
 	 * Do not write empty databases, and delete existing ones
@@ -2160,59 +2183,62 @@
 		say("", "&%s", tfn);
 		return;
 	}
-
+	cp1 = cp2 = MAP_FAILED;
+	fd1 = fd2 = -1;
 	(void)strlcat(tfn, "/" MANDOC_DB, sizeof(tfn));
 	if (dba_write(tfn, dba) == -1) {
-		exitcode = (int)MANDOCLEVEL_SYSERR;
 		say(tfn, "&dba_write");
-		goto out;
+		goto err;
 	}
-
-	switch (child = fork()) {
-	case -1:
-		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 ((fd1 = open(MANDOC_DB, O_RDONLY, 0)) == -1) {
+		say(MANDOC_DB, "&open");
+		goto err;
 	}
-	if (waitpid(child, &status, 0) == -1) {
-		exitcode = (int)MANDOCLEVEL_SYSERR;
-		say("", "&wait cmp");
-	} 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 ((fd2 = open(tfn, O_RDONLY, 0)) == -1) {
+		say(tfn, "&open");
+		goto err;
 	}
+	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:
+	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';
-	switch (child = fork()) {
-	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);
-	}
+	rmdir(tfn);
 }
 
 static int
--- old/usr/src/cmd/mandoc/mansearch.c	Thu Aug  9 15:28:37 2018
+++ new/usr/src/cmd/mandoc/mansearch.c	Thu Aug  9 15:28:37 2018
@@ -1,4 +1,4 @@
-/*	$Id: mansearch.c,v 1.76 2017/08/02 13:29:04 schwarze Exp $ */
+/*	$Id: mansearch.c,v 1.77 2017/08/22 17:50:11 schwarze Exp $ */
 /*
  * Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2013-2017 Ingo Schwarze <schwarze@openbsd.org>
@@ -188,6 +188,16 @@
 			mpage = *res + cur;
 			mandoc_asprintf(&mpage->file, "%s/%s",
 			    paths->paths[i], page->file + 1);
+			if (access(chdir_status ? page->file + 1 :
+			    mpage->file, R_OK) == -1) {
+				warn("%s", mpage->file);
+				warnx("outdated mandoc.db contains "
+				    "bogus %s entry, run makewhatis %s", 
+				    page->file + 1, paths->paths[i]);
+				free(mpage->file);
+				free(rp);
+				continue;
+			}
 			mpage->names = buildnames(page);
 			mpage->output = buildoutput(outkey, page);
 			mpage->ipath = i;
--- old/usr/src/cmd/mandoc/mdoc.c	Thu Aug  9 15:28:37 2018
+++ new/usr/src/cmd/mandoc/mdoc.c	Thu Aug  9 15:28:37 2018
@@ -1,4 +1,4 @@
-/*	$Id: mdoc.c,v 1.267 2017/06/17 13:06:16 schwarze Exp $ */
+/*	$Id: mdoc.c,v 1.268 2017/08/11 16:56:21 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010, 2012-2017 Ingo Schwarze <schwarze@openbsd.org>
@@ -297,8 +297,8 @@
 		if (end - c < 3)
 			break;
 		if (c[1] != ' ' ||
-		    isalpha((unsigned char)c[-2]) == 0 ||
-		    isalpha((unsigned char)c[-1]) == 0 ||
+		    isalnum((unsigned char)c[-2]) == 0 ||
+		    isalnum((unsigned char)c[-1]) == 0 ||
 		    (c[-2] == 'n' && c[-1] == 'c') ||
 		    (c[-2] == 'v' && c[-1] == 's'))
 			continue;
--- old/usr/src/cmd/mandoc/mdoc_html.c	Thu Aug  9 15:28:37 2018
+++ new/usr/src/cmd/mandoc/mdoc_html.c	Thu Aug  9 15:28:37 2018
@@ -1,7 +1,7 @@
-/*	$Id: mdoc_html.c,v 1.294 2017/07/15 17:57:51 schwarze Exp $ */
+/*	$Id: mdoc_html.c,v 1.310 2018/07/27 17:49:31 schwarze Exp $ */
 /*
  * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2014, 2015, 2016, 2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2014,2015,2016,2017,2018 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
@@ -34,8 +34,6 @@
 #include "html.h"
 #include "main.h"
 
-#define	INDENT		 5
-
 #define	MDOC_ARGS	  const struct roff_meta *meta, \
 			  struct roff_node *n, \
 			  struct html *h
@@ -50,14 +48,17 @@
 };
 
 static	char		 *cond_id(const struct roff_node *);
-static	void		  print_mdoc_head(MDOC_ARGS);
+static	void		  print_mdoc_head(const struct roff_meta *,
+				struct html *);
 static	void		  print_mdoc_node(MDOC_ARGS);
 static	void		  print_mdoc_nodelist(MDOC_ARGS);
 static	void		  synopsis_pre(struct html *,
 				const struct roff_node *);
 
-static	void		  mdoc_root_post(MDOC_ARGS);
-static	int		  mdoc_root_pre(MDOC_ARGS);
+static	void		  mdoc_root_post(const struct roff_meta *,
+				struct html *);
+static	int		  mdoc_root_pre(const struct roff_meta *,
+				struct html *);
 
 static	void		  mdoc__x_post(MDOC_ARGS);
 static	int		  mdoc__x_pre(MDOC_ARGS);
@@ -284,30 +285,34 @@
 void
 html_mdoc(void *arg, const struct roff_man *mdoc)
 {
-	struct html	*h;
-	struct tag	*t;
+	struct html		*h;
+	struct roff_node	*n;
+	struct tag		*t;
 
 	h = (struct html *)arg;
+	n = mdoc->first->child;
 
 	if ((h->oflags & HTML_FRAGMENT) == 0) {
 		print_gen_decls(h);
 		print_otag(h, TAG_HTML, "");
+		if (n->type == ROFFT_COMMENT)
+			print_gen_comment(h, n);
 		t = print_otag(h, TAG_HEAD, "");
-		print_mdoc_head(&mdoc->meta, mdoc->first->child, h);
+		print_mdoc_head(&mdoc->meta, h);
 		print_tagq(h, t);
 		print_otag(h, TAG_BODY, "");
 	}
 
-	mdoc_root_pre(&mdoc->meta, mdoc->first->child, h);
+	mdoc_root_pre(&mdoc->meta, h);
 	t = print_otag(h, TAG_DIV, "c", "manual-text");
-	print_mdoc_nodelist(&mdoc->meta, mdoc->first->child, h);
+	print_mdoc_nodelist(&mdoc->meta, n, h);
 	print_tagq(h, t);
-	mdoc_root_post(&mdoc->meta, mdoc->first->child, h);
+	mdoc_root_post(&mdoc->meta, h);
 	print_tagq(h, NULL);
 }
 
 static void
-print_mdoc_head(MDOC_ARGS)
+print_mdoc_head(const struct roff_meta *meta, struct html *h)
 {
 	char	*cp;
 
@@ -344,7 +349,7 @@
 	int		 child;
 	struct tag	*t;
 
-	if (n->flags & NODE_NOPRT)
+	if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT)
 		return;
 
 	child = 1;
@@ -429,7 +434,7 @@
 }
 
 static void
-mdoc_root_post(MDOC_ARGS)
+mdoc_root_post(const struct roff_meta *meta, struct html *h)
 {
 	struct tag	*t, *tt;
 
@@ -446,7 +451,7 @@
 }
 
 static int
-mdoc_root_pre(MDOC_ARGS)
+mdoc_root_pre(const struct roff_meta *meta, struct html *h)
 {
 	struct tag	*t, *tt;
 	char		*volume, *title;
@@ -495,7 +500,7 @@
 	     (n->parent->tok == MDOC_Xo &&
 	      n->parent->parent->prev == NULL &&
 	      n->parent->parent->parent->tok == MDOC_It)))
-		return html_make_id(n);
+		return html_make_id(n, 1);
 	return NULL;
 }
 
@@ -506,11 +511,10 @@
 
 	switch (n->type) {
 	case ROFFT_HEAD:
-		id = html_make_id(n);
+		id = html_make_id(n, 1);
 		print_otag(h, TAG_H1, "cTi", "Sh", id);
 		if (id != NULL)
-			print_otag(h, TAG_A, "chR", "selflink", id);
-		free(id);
+			print_otag(h, TAG_A, "chR", "permalink", id);
 		break;
 	case ROFFT_BODY:
 		if (n->sec == SEC_AUTHORS)
@@ -530,11 +534,10 @@
 	if (n->type != ROFFT_HEAD)
 		return 1;
 
-	id = html_make_id(n);
+	id = html_make_id(n, 1);
 	print_otag(h, TAG_H2, "cTi", "Ss", id);
 	if (id != NULL)
-		print_otag(h, TAG_A, "chR", "selflink", id);
-	free(id);
+		print_otag(h, TAG_A, "chR", "permalink", id);
 	return 1;
 }
 
@@ -544,9 +547,8 @@
 	char	*id;
 
 	if ((id = cond_id(n)) != NULL)
-		print_otag(h, TAG_A, "chR", "selflink", id);
-	print_otag(h, TAG_B, "cTi", "Fl", id);
-	free(id);
+		print_otag(h, TAG_A, "chR", "permalink", id);
+	print_otag(h, TAG_CODE, "cTi", "Fl", id);
 
 	print_text(h, "\\-");
 	if (!(n->child == NULL &&
@@ -564,9 +566,8 @@
 	char	*id;
 
 	if ((id = cond_id(n)) != NULL)
-		print_otag(h, TAG_A, "chR", "selflink", id);
-	print_otag(h, TAG_B, "cTi", "Cm", id);
-	free(id);
+		print_otag(h, TAG_A, "chR", "permalink", id);
+	print_otag(h, TAG_CODE, "cTi", "Cm", id);
 	return 1;
 }
 
@@ -576,10 +577,9 @@
 	if (n->type != ROFFT_BODY)
 		return 1;
 
-	/* XXX: this tag in theory can contain block elements. */
-
 	print_text(h, "\\(em");
-	print_otag(h, TAG_SPAN, "cT", "Nd");
+	/* Cannot use TAG_SPAN because it may contain blocks. */
+	print_otag(h, TAG_DIV, "cT", "Nd");
 	return 1;
 }
 
@@ -591,7 +591,7 @@
 		print_otag(h, TAG_TD, "");
 		/* FALLTHROUGH */
 	case ROFFT_ELEM:
-		print_otag(h, TAG_B, "cT", "Nm");
+		print_otag(h, TAG_CODE, "cT", "Nm");
 		return 1;
 	case ROFFT_BODY:
 		print_otag(h, TAG_TD, "");
@@ -661,7 +661,6 @@
 {
 	const struct roff_node	*bl;
 	struct tag		*t;
-	const char		*cattr;
 	enum mdoc_list		 type;
 
 	bl = n->parent;
@@ -671,51 +670,15 @@
 
 	switch (type) {
 	case LIST_bullet:
-		cattr = "It-bullet";
-		break;
 	case LIST_dash:
 	case LIST_hyphen:
-		cattr = "It-dash";
-		break;
 	case LIST_item:
-		cattr = "It-item";
-		break;
 	case LIST_enum:
-		cattr = "It-enum";
-		break;
-	case LIST_diag:
-		cattr = "It-diag";
-		break;
-	case LIST_hang:
-		cattr = "It-hang";
-		break;
-	case LIST_inset:
-		cattr = "It-inset";
-		break;
-	case LIST_ohang:
-		cattr = "It-ohang";
-		break;
-	case LIST_tag:
-		cattr = "It-tag";
-		break;
-	case LIST_column:
-		cattr = "It-column";
-		break;
-	default:
-		break;
-	}
-
-	switch (type) {
-	case LIST_bullet:
-	case LIST_dash:
-	case LIST_hyphen:
-	case LIST_item:
-	case LIST_enum:
 		switch (n->type) {
 		case ROFFT_HEAD:
 			return 0;
 		case ROFFT_BODY:
-			print_otag(h, TAG_LI, "c", cattr);
+			print_otag(h, TAG_LI, "");
 			break;
 		default:
 			break;
@@ -727,13 +690,10 @@
 	case LIST_ohang:
 		switch (n->type) {
 		case ROFFT_HEAD:
-			print_otag(h, TAG_DT, "c", cattr);
-			if (type == LIST_diag)
-				print_otag(h, TAG_B, "c", cattr);
+			print_otag(h, TAG_DT, "");
 			break;
 		case ROFFT_BODY:
-			print_otag(h, TAG_DD, "csw*+l", cattr,
-			    bl->norm->Bl.width);
+			print_otag(h, TAG_DD, "");
 			break;
 		default:
 			break;
@@ -746,24 +706,21 @@
 			    (n->parent->prev == NULL ||
 			     n->parent->prev->body == NULL ||
 			     n->parent->prev->body->child != NULL)) {
-				t = print_otag(h, TAG_DT, "csw*+-l",
-				    cattr, bl->norm->Bl.width);
+				t = print_otag(h, TAG_DT, "");
 				print_text(h, "\\ ");
 				print_tagq(h, t);
-				t = print_otag(h, TAG_DD, "c", cattr);
+				t = print_otag(h, TAG_DD, "");
 				print_text(h, "\\ ");
 				print_tagq(h, t);
 			}
-			print_otag(h, TAG_DT, "csw*+-l", cattr,
-			    bl->norm->Bl.width);
+			print_otag(h, TAG_DT, "");
 			break;
 		case ROFFT_BODY:
 			if (n->child == NULL) {
-				print_otag(h, TAG_DD, "css?", cattr,
-				    "width", "auto");
+				print_otag(h, TAG_DD, "s", "width", "auto");
 				print_text(h, "\\ ");
 			} else
-				print_otag(h, TAG_DD, "c", cattr);
+				print_otag(h, TAG_DD, "");
 			break;
 		default:
 			break;
@@ -774,10 +731,10 @@
 		case ROFFT_HEAD:
 			break;
 		case ROFFT_BODY:
-			print_otag(h, TAG_TD, "c", cattr);
+			print_otag(h, TAG_TD, "");
 			break;
 		default:
-			print_otag(h, TAG_TR, "c", cattr);
+			print_otag(h, TAG_TR, "");
 		}
 	default:
 		break;
@@ -789,40 +746,20 @@
 static int
 mdoc_bl_pre(MDOC_ARGS)
 {
-	char		 cattr[21];
-	struct tag	*t;
+	char		 cattr[28];
 	struct mdoc_bl	*bl;
-	size_t		 i;
 	enum htmltag	 elemtype;
 
-	bl = &n->norm->Bl;
-
 	switch (n->type) {
 	case ROFFT_BODY:
 		return 1;
-
 	case ROFFT_HEAD:
-		if (bl->type != LIST_column || bl->ncols == 0)
-			return 0;
-
-		/*
-		 * For each column, print out the <COL> tag with our
-		 * suggested width.  The last column gets min-width, as
-		 * in terminal mode it auto-sizes to the width of the
-		 * screen and we want to preserve that behaviour.
-		 */
-
-		t = print_otag(h, TAG_COLGROUP, "");
-		for (i = 0; i < bl->ncols - 1; i++)
-			print_otag(h, TAG_COL, "sw+w", bl->cols[i]);
-		print_otag(h, TAG_COL, "swW", bl->cols[i]);
-		print_tagq(h, t);
 		return 0;
-
 	default:
 		break;
 	}
 
+	bl = &n->norm->Bl;
 	switch (bl->type) {
 	case LIST_bullet:
 		elemtype = TAG_UL;
@@ -859,9 +796,9 @@
 		break;
 	case LIST_tag:
 		if (bl->offs)
-			print_otag(h, TAG_DIV, "cswl", "Bl-tag", bl->offs);
-		print_otag(h, TAG_DL, "csw*+l", bl->comp ?
-		    "Bl-tag Bl-compact" : "Bl-tag", bl->width);
+			print_otag(h, TAG_DIV, "c", "Bd-indent");
+		print_otag(h, TAG_DL, "c", bl->comp ?
+		    "Bl-tag Bl-compact" : "Bl-tag");
 		return 1;
 	case LIST_column:
 		elemtype = TAG_TABLE;
@@ -870,9 +807,11 @@
 	default:
 		abort();
 	}
+	if (bl->offs != NULL)
+		(void)strlcat(cattr, " Bd-indent", sizeof(cattr));
 	if (bl->comp)
 		(void)strlcat(cattr, " Bl-compact", sizeof(cattr));
-	print_otag(h, elemtype, "cswl", cattr, bl->offs);
+	print_otag(h, elemtype, "c", cattr);
 	return 1;
 }
 
@@ -904,7 +843,7 @@
 	if (n->type != ROFFT_BLOCK)
 		return 1;
 
-	print_otag(h, TAG_DIV, "c", "D1");
+	print_otag(h, TAG_DIV, "c", "Bd Bd-indent");
 
 	if (n->tok == MDOC_Dl)
 		print_otag(h, TAG_CODE, "c", "Li");
@@ -917,7 +856,7 @@
 {
 	char	*id;
 
-	id = html_make_id(n);
+	id = html_make_id(n, 0);
 	print_otag(h, TAG_A, "cThR", "Sx", id);
 	free(id);
 	return 1;
@@ -926,7 +865,7 @@
 static int
 mdoc_bd_pre(MDOC_ARGS)
 {
-	int			 comp, offs, sv;
+	int			 comp, sv;
 	struct roff_node	*nn;
 
 	if (n->type == ROFFT_HEAD)
@@ -951,19 +890,10 @@
 
 	if (n->norm->Bd.offs == NULL ||
 	    ! strcmp(n->norm->Bd.offs, "left"))
-		offs = 0;
-	else if ( ! strcmp(n->norm->Bd.offs, "indent"))
-		offs = INDENT;
-	else if ( ! strcmp(n->norm->Bd.offs, "indent-two"))
-		offs = INDENT * 2;
+		print_otag(h, TAG_DIV, "c", "Bd");
 	else
-		offs = -1;
+		print_otag(h, TAG_DIV, "c", "Bd Bd-indent");
 
-	if (offs == -1)
-		print_otag(h, TAG_DIV, "cswl", "Bd", n->norm->Bd.offs);
-	else
-		print_otag(h, TAG_DIV, "cshl", "Bd", offs);
-
 	if (n->norm->Bd.type != DISP_unfilled &&
 	    n->norm->Bd.type != DISP_literal)
 		return 1;
@@ -1014,7 +944,7 @@
 static int
 mdoc_pa_pre(MDOC_ARGS)
 {
-	print_otag(h, TAG_I, "cT", "Pa");
+	print_otag(h, TAG_SPAN, "cT", "Pa");
 	return 1;
 }
 
@@ -1021,7 +951,7 @@
 static int
 mdoc_ad_pre(MDOC_ARGS)
 {
-	print_otag(h, TAG_I, "c", "Ad");
+	print_otag(h, TAG_SPAN, "c", "Ad");
 	return 1;
 }
 
@@ -1053,7 +983,7 @@
 mdoc_cd_pre(MDOC_ARGS)
 {
 	synopsis_pre(h, n);
-	print_otag(h, TAG_B, "cT", "Cd");
+	print_otag(h, TAG_CODE, "cT", "Cd");
 	return 1;
 }
 
@@ -1063,9 +993,8 @@
 	char	*id;
 
 	if ((id = cond_id(n)) != NULL)
-		print_otag(h, TAG_A, "chR", "selflink", id);
+		print_otag(h, TAG_A, "chR", "permalink", id);
 	print_otag(h, TAG_CODE, "cTi", "Dv", id);
-	free(id);
 	return 1;
 }
 
@@ -1075,9 +1004,8 @@
 	char	*id;
 
 	if ((id = cond_id(n)) != NULL)
-		print_otag(h, TAG_A, "chR", "selflink", id);
+		print_otag(h, TAG_A, "chR", "permalink", id);
 	print_otag(h, TAG_CODE, "cTi", "Ev", id);
-	free(id);
 	return 1;
 }
 
@@ -1090,12 +1018,11 @@
 	    (n->parent->tok == MDOC_It ||
 	     (n->parent->tok == MDOC_Bq &&
 	      n->parent->parent->parent->tok == MDOC_It)) ?
-	    html_make_id(n) : NULL;
+	    html_make_id(n, 1) : NULL;
 
 	if (id != NULL)
-		print_otag(h, TAG_A, "chR", "selflink", id);
+		print_otag(h, TAG_A, "chR", "permalink", id);
 	print_otag(h, TAG_CODE, "cTi", "Er", id);
-	free(id);
 	return 1;
 }
 
@@ -1142,11 +1069,11 @@
 	assert(n->type == ROFFT_TEXT);
 
 	if (strcmp(n->string, "#include")) {
-		print_otag(h, TAG_B, "cT", "Fd");
+		print_otag(h, TAG_CODE, "cT", "Fd");
 		return 1;
 	}
 
-	print_otag(h, TAG_B, "cT", "In");
+	print_otag(h, TAG_CODE, "cT", "In");
 	print_text(h, n->string);
 
 	if (NULL != (n = n->next)) {
@@ -1232,7 +1159,7 @@
 		print_tagq(h, t);
 	}
 
-	t = print_otag(h, TAG_B, "cT", "Fn");
+	t = print_otag(h, TAG_CODE, "cT", "Fn");
 
 	if (sp)
 		print_text(h, sp);
@@ -1245,7 +1172,7 @@
 
 	for (n = n->child->next; n; n = n->next) {
 		if (NODE_SYNPRETTY & n->flags)
-			t = print_otag(h, TAG_VAR, "cTss?", "Fa",
+			t = print_otag(h, TAG_VAR, "cTs", "Fa",
 			    "white-space", "nowrap");
 		else
 			t = print_otag(h, TAG_VAR, "cT", "Fa");
@@ -1375,7 +1302,7 @@
 		return 0;
 
 	assert(n->child->string);
-	t = print_otag(h, TAG_B, "cT", "Fn");
+	t = print_otag(h, TAG_CODE, "cT", "Fn");
 	print_text(h, n->child->string);
 	print_tagq(h, t);
 	return 0;
@@ -1399,7 +1326,7 @@
 	struct tag	*t;
 
 	synopsis_pre(h, n);
-	print_otag(h, TAG_B, "cT", "In");
+	print_otag(h, TAG_CODE, "cT", "In");
 
 	/*
 	 * The first argument of the `In' gets special treatment as
@@ -1444,9 +1371,8 @@
 	char	*id;
 
 	if ((id = cond_id(n)) != NULL)
-		print_otag(h, TAG_A, "chR", "selflink", id);
-	print_otag(h, TAG_B, "cTi", "Ic", id);
-	free(id);
+		print_otag(h, TAG_A, "chR", "permalink", id);
+	print_otag(h, TAG_CODE, "cTi", "Ic", id);
 	return 1;
 }
 
@@ -1478,20 +1404,16 @@
 		return 1;
 
 	if (FONT_Em == n->norm->Bf.font)
-		cattr = "Em";
+		cattr = "Bf Em";
 	else if (FONT_Sy == n->norm->Bf.font)
-		cattr = "Sy";
+		cattr = "Bf Sy";
 	else if (FONT_Li == n->norm->Bf.font)
-		cattr = "Li";
+		cattr = "Bf Li";
 	else
-		cattr = "No";
+		cattr = "Bf No";
 
-	/*
-	 * We want this to be inline-formatted, but needs to be div to
-	 * accept block children.
-	 */
-
-	print_otag(h, TAG_DIV, "css?hl", cattr, "display", "inline", 1);
+	/* Cannot use TAG_SPAN because it may contain blocks. */
+	print_otag(h, TAG_DIV, "c", cattr);
 	return 1;
 }
 
@@ -1501,9 +1423,8 @@
 	char *id;
 
 	if ((id = cond_id(n)) != NULL)
-		print_otag(h, TAG_A, "chR", "selflink", id);
-	print_otag(h, TAG_B, "cTi", "Ms", id);
-	free(id);
+		print_otag(h, TAG_A, "chR", "permalink", id);
+	print_otag(h, TAG_SPAN, "cTi", "Ms", id);
 	return 1;
 }
 
@@ -1542,9 +1463,8 @@
 	char *id;
 
 	if ((id = cond_id(n)) != NULL)
-		print_otag(h, TAG_A, "chR", "selflink", id);
+		print_otag(h, TAG_A, "chR", "permalink", id);
 	print_otag(h, TAG_SPAN, "ci", "No", id);
-	free(id);
 	return 1;
 }
 
@@ -1554,9 +1474,8 @@
 	char	*id;
 
 	if ((id = cond_id(n)) != NULL)
-		print_otag(h, TAG_A, "chR", "selflink", id);
+		print_otag(h, TAG_A, "chR", "permalink", id);
 	print_otag(h, TAG_CODE, "ci", "Li", id);
-	free(id);
 	return 1;
 }
 
@@ -1712,7 +1631,8 @@
 	case MDOC_Op:
 		print_text(h, "\\(lB");
 		h->flags |= HTML_NOSPACE;
-		print_otag(h, TAG_SPAN, "c", "Op");
+		/* Cannot use TAG_SPAN because it may contain blocks. */
+		print_otag(h, TAG_IDIV, "c", "Op");
 		break;
 	case MDOC_En:
 		if (NULL == n->norm->Es ||
--- old/usr/src/cmd/mandoc/mdoc_man.c	Thu Aug  9 15:28:38 2018
+++ new/usr/src/cmd/mandoc/mdoc_man.c	Thu Aug  9 15:28:38 2018
@@ -1,6 +1,6 @@
-/*	$Id: mdoc_man.c,v 1.122 2017/06/14 22:51:25 schwarze Exp $ */
+/*	$Id: mdoc_man.c,v 1.126 2018/04/11 17:11:13 schwarze Exp $ */
 /*
- * Copyright (c) 2011-2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011-2018 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
@@ -202,8 +202,8 @@
 	{ NULL, pre_bk, post_bk, NULL, NULL }, /* Bx */
 	{ NULL, pre_skip, NULL, NULL, NULL }, /* Db */
 	{ NULL, NULL, NULL, NULL, NULL }, /* Dc */
-	{ cond_body, pre_enc, post_enc, "\\(Lq", "\\(Rq" }, /* Do */
-	{ cond_body, pre_enc, post_enc, "\\(Lq", "\\(Rq" }, /* Dq */
+	{ cond_body, pre_enc, post_enc, "\\(lq", "\\(rq" }, /* Do */
+	{ cond_body, pre_enc, post_enc, "\\(lq", "\\(rq" }, /* Dq */
 	{ NULL, NULL, NULL, NULL, NULL }, /* Ec */
 	{ NULL, NULL, NULL, NULL, NULL }, /* Ef */
 	{ NULL, pre_em, post_font, NULL, NULL }, /* Em */
@@ -610,6 +610,14 @@
 {
 	struct roff_node *n;
 
+	printf(".\\\" Automatically generated from an mdoc input file."
+	    "  Do not edit.\n");
+	for (n = mdoc->first->child; n != NULL; n = n->next) {
+		if (n->type != ROFFT_COMMENT)
+			break;
+		printf(".\\\"%s\n", n->string);
+	}
+
 	printf(".TH \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"\n",
 	    mdoc->meta.title,
 	    (mdoc->meta.msec == NULL ? "" : mdoc->meta.msec),
@@ -624,7 +632,7 @@
 		fontqueue.head = fontqueue.tail = mandoc_malloc(8);
 		*fontqueue.tail = 'R';
 	}
-	for (n = mdoc->first->child; n != NULL; n = n->next)
+	for (; n != NULL; n = n->next)
 		print_node(&mdoc->meta, n);
 	putchar('\n');
 }
@@ -1408,7 +1416,7 @@
 			if (bln->norm->Bl.type == LIST_diag)
 				print_line(".B \"", 0);
 			else
-				print_line(".R \"", 0);
+				print_line(".BR \\& \"", 0);
 			outflags &= ~MMAN_spc;
 			return 1;
 		case LIST_bullet:
@@ -1547,7 +1555,6 @@
 pre_lk(DECL_ARGS)
 {
 	const struct roff_node *link, *descr, *punct;
-	int display;
 
 	if ((link = n->child) == NULL)
 		return 0;
@@ -1570,12 +1577,6 @@
 	}
 
 	/* Link target. */
-	display = man_strlen(link->string) >= 26;
-	if (display) {
-		print_line(".RS", MMAN_Bk_susp);
-		print_word("6n");
-		outflags |= MMAN_nl;
-	}
 	font_push('B');
 	print_word(link->string);
 	font_pop();
@@ -1585,8 +1586,6 @@
 		print_word(punct->string);
 		punct = punct->next;
 	}
-	if (display)
-		print_line(".RE", MMAN_nl);
 	return 0;
 }
 
--- old/usr/src/cmd/mandoc/mdoc_markdown.c	Thu Aug  9 15:28:38 2018
+++ new/usr/src/cmd/mandoc/mdoc_markdown.c	Thu Aug  9 15:28:38 2018
@@ -1,4 +1,4 @@
-/*	$Id: mdoc_markdown.c,v 1.23 2017/06/14 01:31:26 schwarze Exp $ */
+/*	$Id: mdoc_markdown.c,v 1.24 2018/04/11 17:11:13 schwarze Exp $ */
 /*
  * Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
  *
@@ -294,7 +294,7 @@
 	const struct md_act	*act;
 	int			 cond, process_children;
 
-	if (n->flags & NODE_NOPRT)
+	if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT)
 		return;
 
 	if (outflags & MD_nonl)
--- old/usr/src/cmd/mandoc/mdoc_state.c	Thu Aug  9 15:28:38 2018
+++ new/usr/src/cmd/mandoc/mdoc_state.c	Thu Aug  9 15:28:38 2018
@@ -1,4 +1,4 @@
-/*	$Id: mdoc_state.c,v 1.8 2017/05/05 15:17:32 schwarze Exp $ */
+/*	$Id: mdoc_state.c,v 1.9 2017/11/29 20:05:33 schwarze Exp $ */
 /*
  * Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
  *
@@ -208,19 +208,24 @@
 static void
 state_bl(STATE_ARGS)
 {
+	struct mdoc_arg	*args;
+	size_t		 i;
 
 	if (n->type != ROFFT_HEAD || n->parent->args == NULL)
 		return;
 
-	switch(n->parent->args->argv[0].arg) {
-	case MDOC_Diag:
-		n->norm->Bl.type = LIST_diag;
-		break;
-	case MDOC_Column:
-		n->norm->Bl.type = LIST_column;
-		break;
-	default:
-		break;
+	args = n->parent->args;
+	for (i = 0; i < args->argc; i++) {
+		switch(args->argv[i].arg) {
+		case MDOC_Diag:
+			n->norm->Bl.type = LIST_diag;
+			return;
+		case MDOC_Column:
+			n->norm->Bl.type = LIST_column;
+			return;
+		default:
+			break;
+		}
 	}
 }
 
--- old/usr/src/cmd/mandoc/mdoc_term.c	Thu Aug  9 15:28:38 2018
+++ new/usr/src/cmd/mandoc/mdoc_term.c	Thu Aug  9 15:28:38 2018
@@ -1,7 +1,7 @@
-/*	$Id: mdoc_term.c,v 1.364 2017/06/14 17:51:15 schwarze Exp $ */
+/*	$Id: mdoc_term.c,v 1.367 2018/04/11 17:11:13 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2012-2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2012-2018 Ingo Schwarze <schwarze@openbsd.org>
  * Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de>
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -283,7 +283,9 @@
 			p->defindent = 5;
 		term_begin(p, print_mdoc_head, print_mdoc_foot,
 		    &mdoc->meta);
-		while (n != NULL && n->flags & NODE_NOPRT)
+		while (n != NULL &&
+		    (n->type == ROFFT_COMMENT ||
+		     n->flags & NODE_NOPRT))
 			n = n->next;
 		if (n != NULL) {
 			if (n->tok != MDOC_Sh)
@@ -312,7 +314,7 @@
 	struct termpair	 npair;
 	size_t		 offset, rmargin;
 
-	if (n->flags & NODE_NOPRT)
+	if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT)
 		return;
 
 	chld = 1;
@@ -567,7 +569,9 @@
 	/* Do not vspace directly after Ss/Sh. */
 
 	nn = n;
-	while (nn->prev != NULL && nn->prev->flags & NODE_NOPRT)
+	while (nn->prev != NULL &&
+	    (nn->prev->type == ROFFT_COMMENT ||
+	     nn->prev->flags & NODE_NOPRT))
 		nn = nn->prev;
 	while (nn->prev == NULL) {
 		do {
@@ -1550,7 +1554,8 @@
 	case ROFFT_BLOCK:
 		term_newln(p);
 		for (nn = n->prev; nn != NULL; nn = nn->prev)
-			if ((nn->flags & NODE_NOPRT) == 0)
+			if (nn->type != ROFFT_COMMENT &&
+			    (nn->flags & NODE_NOPRT) == 0)
 				break;
 		if (nn != NULL)
 			term_vspace(p);
@@ -1664,7 +1669,7 @@
 		/* FALLTHROUGH */
 	case MDOC_Do:
 	case MDOC_Dq:
-		term_word(p, "\\(Lq");
+		term_word(p, "\\(lq");
 		break;
 	case MDOC_En:
 		if (NULL == n->norm->Es ||
@@ -1722,7 +1727,7 @@
 		/* FALLTHROUGH */
 	case MDOC_Do:
 	case MDOC_Dq:
-		term_word(p, "\\(Rq");
+		term_word(p, "\\(rq");
 		break;
 	case MDOC_En:
 		if (n->norm->Es == NULL ||
@@ -1940,7 +1945,6 @@
 termp_lk_pre(DECL_ARGS)
 {
 	const struct roff_node *link, *descr, *punct;
-	int display;
 
 	if ((link = n->child) == NULL)
 		return 0;
@@ -1966,11 +1970,6 @@
 	}
 
 	/* Link target. */
-	display = term_strlen(p, link->string) >= 26;
-	if (display) {
-		term_newln(p);
-		p->tcol->offset += term_len(p, p->defindent + 1);
-	}
 	term_fontpush(p, TERMFONT_BOLD);
 	term_word(p, link->string);
 	term_fontpop(p);
@@ -1981,8 +1980,6 @@
 		term_word(p, punct->string);
 		punct = punct->next;
 	}
-	if (display)
-		term_newln(p);
 	return 0;
 }
 
--- old/usr/src/cmd/mandoc/mdoc_validate.c	Thu Aug  9 15:28:39 2018
+++ new/usr/src/cmd/mandoc/mdoc_validate.c	Thu Aug  9 15:28:39 2018
@@ -1,7 +1,7 @@
-/*	$Id: mdoc_validate.c,v 1.352 2017/08/02 13:29:04 schwarze Exp $ */
+/*	$Id: mdoc_validate.c,v 1.360 2018/08/01 16:00:58 schwarze Exp $ */
 /*
  * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010-2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2018 Ingo Schwarze <schwarze@openbsd.org>
  * Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -53,10 +53,11 @@
 typedef	void	(*v_post)(POST_ARGS);
 
 static	int	 build_list(struct roff_man *, int);
-static	void	 check_text(struct roff_man *, int, int, char *);
 static	void	 check_argv(struct roff_man *,
 			struct roff_node *, struct mdoc_argv *);
 static	void	 check_args(struct roff_man *, struct roff_node *);
+static	void	 check_text(struct roff_man *, int, int, char *);
+static	void	 check_text_em(struct roff_man *, int, int, char *);
 static	void	 check_toptext(struct roff_man *, int, int, const char *);
 static	int	 child_an(const struct roff_node *);
 static	size_t		macro2len(enum roff_tok);
@@ -169,12 +170,12 @@
 	post_hyph,	/* %T */ /* FIXME: can be used outside Rs/Re. */
 	NULL,		/* %V */
 	NULL,		/* Ac */
-	post_delim_nb,	/* Ao */
+	NULL,		/* Ao */
 	post_delim_nb,	/* Aq */
 	post_at,	/* At */
 	NULL,		/* Bc */
 	post_bf,	/* Bf */
-	post_delim_nb,	/* Bo */
+	NULL,		/* Bo */
 	NULL,		/* Bq */
 	post_xx,	/* Bsx */
 	post_bx,	/* Bx */
@@ -194,16 +195,16 @@
 	post_xx,	/* Ox */
 	NULL,		/* Pc */
 	NULL,		/* Pf */
-	post_delim_nb,	/* Po */
+	NULL,		/* Po */
 	post_delim_nb,	/* Pq */
 	NULL,		/* Qc */
 	post_delim_nb,	/* Ql */
-	post_delim_nb,	/* Qo */
+	NULL,		/* Qo */
 	post_delim_nb,	/* Qq */
 	NULL,		/* Re */
 	post_rs,	/* Rs */
 	NULL,		/* Sc */
-	post_delim_nb,	/* So */
+	NULL,		/* So */
 	post_delim_nb,	/* Sq */
 	post_sm,	/* Sm */
 	post_sx,	/* Sx */
@@ -214,7 +215,7 @@
 	NULL,		/* Xo */
 	post_fo,	/* Fo */
 	NULL,		/* Fc */
-	post_delim_nb,	/* Oo */
+	NULL,		/* Oo */
 	NULL,		/* Oc */
 	post_bk,	/* Bk */
 	NULL,		/* Ek */
@@ -227,7 +228,7 @@
 	post_delim_nb,	/* Lk */
 	post_defaults,	/* Mt */
 	post_delim_nb,	/* Brq */
-	post_delim_nb,	/* Bro */
+	NULL,		/* Bro */
 	NULL,		/* Brc */
 	NULL,		/* %C */
 	post_es,	/* Es */
@@ -288,7 +289,7 @@
 void
 mdoc_node_validate(struct roff_man *mdoc)
 {
-	struct roff_node *n;
+	struct roff_node *n, *np;
 	const v_post *p;
 
 	n = mdoc->last;
@@ -305,15 +306,21 @@
 	mdoc->next = ROFF_NEXT_SIBLING;
 	switch (n->type) {
 	case ROFFT_TEXT:
+		np = n->parent;
 		if (n->sec != SEC_SYNOPSIS ||
-		    (n->parent->tok != MDOC_Cd && n->parent->tok != MDOC_Fd))
+		    (np->tok != MDOC_Cd && np->tok != MDOC_Fd))
 			check_text(mdoc, n->line, n->pos, n->string);
-		if (n->parent->tok == MDOC_It ||
-		    (n->parent->type == ROFFT_BODY &&
-		     (n->parent->tok == MDOC_Sh ||
-		      n->parent->tok == MDOC_Ss)))
+		if (np->tok != MDOC_Ql && np->tok != MDOC_Dl &&
+		    (np->tok != MDOC_Bd ||
+		     (mdoc->flags & MDOC_LITERAL) == 0) &&
+		    (np->tok != MDOC_It || np->type != ROFFT_HEAD ||
+		     np->parent->parent->norm->Bl.type != LIST_diag))
+			check_text_em(mdoc, n->line, n->pos, n->string);
+		if (np->tok == MDOC_It || (np->type == ROFFT_BODY &&
+		    (np->tok == MDOC_Sh || np->tok == MDOC_Ss)))
 			check_toptext(mdoc, n->line, n->pos, n->string);
 		break;
+	case ROFFT_COMMENT:
 	case ROFFT_EQN:
 	case ROFFT_TBL:
 		break;
@@ -395,6 +402,57 @@
 }
 
 static void
+check_text_em(struct roff_man *mdoc, int ln, int pos, char *p)
+{
+	const struct roff_node	*np, *nn;
+	char			*cp;
+
+	np = mdoc->last->prev;
+	nn = mdoc->last->next;
+
+	/* Look for em-dashes wrongly encoded as "--". */
+
+	for (cp = p; *cp != '\0'; cp++) {
+		if (cp[0] != '-' || cp[1] != '-')
+			continue;
+		cp++;
+
+		/* Skip input sequences of more than two '-'. */
+
+		if (cp[1] == '-') {
+			while (cp[1] == '-')
+				cp++;
+			continue;
+		}
+
+		/* Skip "--" directly attached to something else. */
+
+		if ((cp - p > 1 && cp[-2] != ' ') ||
+		    (cp[1] != '\0' && cp[1] != ' '))
+			continue;
+
+		/* Require a letter right before or right afterwards. */
+
+		if ((cp - p > 2 ?
+		     isalpha((unsigned char)cp[-3]) :
+		     np != NULL &&
+		     np->type == ROFFT_TEXT &&
+		     *np->string != '\0' &&
+		     isalpha((unsigned char)np->string[
+		       strlen(np->string) - 1])) ||
+		    (cp[1] != '\0' && cp[2] != '\0' ?
+		     isalpha((unsigned char)cp[2]) :
+		     nn != NULL &&
+		     nn->type == ROFFT_TEXT &&
+		     isalpha((unsigned char)*nn->string))) {
+			mandoc_msg(MANDOCERR_DASHDASH, mdoc->parse,
+			    ln, pos + (int)(cp - p) - 1, NULL);
+			break;
+		}
+	}
+}
+
+static void
 check_toptext(struct roff_man *mdoc, int ln, int pos, const char *p)
 {
 	const char	*cp, *cpr;
@@ -530,8 +588,7 @@
 
 	/* At least three alphabetic words with a sentence ending. */
 	if (strchr("!.:?", *lc) != NULL && (tok == MDOC_Em ||
-	    tok == MDOC_Li || tok == MDOC_Po || tok == MDOC_Pq ||
-	    tok == MDOC_Sy)) {
+	    tok == MDOC_Li || tok == MDOC_Pq || tok == MDOC_Sy)) {
 		nw = 0;
 		for (cp = lc - 1; cp >= nch->string; cp--) {
 			if (*cp == ' ') {
@@ -947,10 +1004,10 @@
 
 	roff_word_alloc(mdoc, n->line, n->pos, "library");
 	mdoc->last->flags = NODE_NOSRC;
-	roff_word_alloc(mdoc, n->line, n->pos, "\\(Lq");
+	roff_word_alloc(mdoc, n->line, n->pos, "\\(lq");
 	mdoc->last->flags = NODE_DELIMO | NODE_NOSRC;
 	mdoc->last = mdoc->last->next;
-	roff_word_alloc(mdoc, n->line, n->pos, "\\(Rq");
+	roff_word_alloc(mdoc, n->line, n->pos, "\\(rq");
 	mdoc->last->flags = NODE_DELIMC | NODE_NOSRC;
 	mdoc->last = n;
 }
@@ -1914,7 +1971,10 @@
 			arch++;
 		if (*arch == NULL) {
 			n = mdoc->first->child;
-			while (n->tok != MDOC_Dt)
+			while (n->tok != MDOC_Dt ||
+			    n->child == NULL ||
+			    n->child->next == NULL ||
+			    n->child->next->next == NULL)
 				n = n->next;
 			n = n->child->next->next;
 			mandoc_vmsg(MANDOCERR_ARCH_BAD,
@@ -1928,8 +1988,10 @@
 	/* Check that we begin with a proper `Sh'. */
 
 	n = mdoc->first->child;
-	while (n != NULL && n->tok >= MDOC_Dd &&
-	    mdoc_macros[n->tok].flags & MDOC_PROLOGUE)
+	while (n != NULL &&
+	    (n->type == ROFFT_COMMENT ||
+	     (n->tok >= MDOC_Dd &&
+	      mdoc_macros[n->tok].flags & MDOC_PROLOGUE)))
 		n = n->next;
 
 	if (n == NULL)
--- old/usr/src/cmd/mandoc/out.h	Thu Aug  9 15:28:39 2018
+++ new/usr/src/cmd/mandoc/out.h	Thu Aug  9 15:28:39 2018
@@ -1,4 +1,4 @@
-/*	$Id: out.h,v 1.31 2017/06/27 18:25:02 schwarze Exp $ */
+/*	$Id: out.h,v 1.32 2018/06/25 16:54:59 schwarze Exp $ */
 /*
  * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2014, 2017 Ingo Schwarze <schwarze@openbsd.org>
@@ -54,11 +54,6 @@
 	void		*arg; /* passed to sulen, slen, and len */
 };
 
-#define	SCALE_VS_INIT(p, v) \
-	do { (p)->unit = SCALE_VS; \
-	     (p)->scale = (v); } \
-	while (/* CONSTCOND */ 0)
-
 #define	SCALE_HS_INIT(p, v) \
 	do { (p)->unit = SCALE_EN; \
 	     (p)->scale = (v); } \
--- old/usr/src/cmd/mandoc/read.c	Thu Aug  9 15:28:39 2018
+++ new/usr/src/cmd/mandoc/read.c	Thu Aug  9 15:28:39 2018
@@ -1,7 +1,7 @@
-/*	$Id: read.c,v 1.192 2017/07/20 14:36:36 schwarze Exp $ */
+/*	$Id: read.c,v 1.196 2018/07/28 18:34:15 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010-2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2018 Ingo Schwarze <schwarze@openbsd.org>
  * Copyright (c) 2010, 2012 Joerg Sonnenberger <joerg@netbsd.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -94,9 +94,10 @@
 	"generic style suggestion",
 
 	"legacy man(7) date format",
+	"normalizing date format to",
 	"lower case character in document title",
 	"duplicate RCS id",
-	"typo in section name",
+	"possible typo in section name",
 	"unterminated quoted argument",
 	"useless macro",
 	"consider using OS macro",
@@ -106,6 +107,7 @@
 	"no blank before trailing delimiter",
 	"fill mode already enabled, skipping",
 	"fill mode already disabled, skipping",
+	"verbatim \"--\", maybe consider using \\(em",
 	"function name without markup",
 	"whitespace at end of input line",
 	"bad comment style",
@@ -556,6 +558,7 @@
 	gzFile		 gz;
 	size_t		 off;
 	ssize_t		 ssz;
+	int		 gzerrnum, retval;
 
 	if (fstat(fd, &st) == -1) {
 		mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0,
@@ -583,9 +586,22 @@
 	}
 
 	if (curp->gzip) {
+		/*
+		 * Duplicating the file descriptor is required
+		 * because we will have to call gzclose(3)
+		 * to free memory used internally by zlib,
+		 * but that will also close the file descriptor,
+		 * which this function must not do.
+		 */
+		if ((fd = dup(fd)) == -1) {
+			mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0,
+			    "dup: %s", strerror(errno));
+			return 0;
+		}
 		if ((gz = gzdopen(fd, "rb")) == NULL) {
 			mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0,
 			    "gzdopen: %s", strerror(errno));
+			close(fd);
 			return 0;
 		}
 	} else
@@ -598,6 +614,7 @@
 
 	*with_mmap = 0;
 	off = 0;
+	retval = 0;
 	fb->sz = 0;
 	fb->buf = NULL;
 	for (;;) {
@@ -614,19 +631,29 @@
 		    read(fd, fb->buf + (int)off, fb->sz - off);
 		if (ssz == 0) {
 			fb->sz = off;
-			return 1;
+			retval = 1;
+			break;
 		}
 		if (ssz == -1) {
-			mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0,
-			    "read: %s", strerror(errno));
+			if (curp->gzip)
+				(void)gzerror(gz, &gzerrnum);
+			mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0, "read: %s",
+			    curp->gzip && gzerrnum != Z_ERRNO ?
+			    zError(gzerrnum) : strerror(errno));
 			break;
 		}
 		off += (size_t)ssz;
 	}
 
-	free(fb->buf);
-	fb->buf = NULL;
-	return 0;
+	if (curp->gzip && (gzerrnum = gzclose(gz)) != Z_OK)
+		mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0, "gzclose: %s",
+		    gzerrnum == Z_ERRNO ? strerror(errno) :
+		    zError(gzerrnum));
+	if (retval == 0) {
+		free(fb->buf);
+		fb->buf = NULL;
+	}
+	return retval;
 }
 
 static void
--- old/usr/src/cmd/mandoc/roff.c	Thu Aug  9 15:28:40 2018
+++ new/usr/src/cmd/mandoc/roff.c	Thu Aug  9 15:28:40 2018
@@ -1,7 +1,7 @@
-/*	$Id: roff.c,v 1.324 2017/07/14 17:16:16 schwarze Exp $ */
+/*	$Id: roff.c,v 1.329 2018/08/01 15:40:17 schwarze Exp $ */
 /*
  * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2015, 2017, 2018 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
@@ -46,6 +46,7 @@
 #define	ROFFDEF_STD	(1 << 4)  /* mdoc(7) or man(7) macro. */
 #define	ROFFDEF_ANY	(ROFFDEF_USER | ROFFDEF_PRE | \
 			 ROFFDEF_REN | ROFFDEF_STD)
+#define	ROFFDEF_UNDEF	(1 << 5)  /* Completely undefined. */
 
 /* --- data types --------------------------------------------------------- */
 
@@ -72,6 +73,7 @@
 struct	roffreg {
 	struct roffstr	 key;
 	int		 val;
+	int		 step;
 	struct roffreg	*next;
 };
 
@@ -181,11 +183,11 @@
 static	size_t		 roff_getname(struct roff *, char **, int, int);
 static	int		 roff_getnum(const char *, int *, int *, int);
 static	int		 roff_getop(const char *, int *, char *);
-static	int		 roff_getregn(const struct roff *,
-				const char *, size_t);
+static	int		 roff_getregn(struct roff *,
+				const char *, size_t, char);
 static	int		 roff_getregro(const struct roff *,
 				const char *name);
-static	const char	*roff_getstrn(const struct roff *,
+static	const char	*roff_getstrn(struct roff *,
 				const char *, size_t, int *);
 static	int		 roff_hasregn(const struct roff *,
 				const char *, size_t);
@@ -206,6 +208,8 @@
 static	enum rofferr	 roff_rm(ROFF_ARGS);
 static	enum rofferr	 roff_rn(ROFF_ARGS);
 static	enum rofferr	 roff_rr(ROFF_ARGS);
+static	void		 roff_setregn(struct roff *, const char *,
+				size_t, int, char, int);
 static	void		 roff_setstr(struct roff *,
 				const char *, const char *, int);
 static	void		 roff_setstrn(struct roffkv **, const char *,
@@ -758,7 +762,7 @@
 
 	r = mandoc_calloc(1, sizeof(struct roff));
 	r->parse = parse;
-	r->reqtab = roffhash_alloc(0, ROFF_USERDEF);
+	r->reqtab = roffhash_alloc(0, ROFF_RENAMED);
 	r->options = options;
 	r->format = options & (MPARSE_MDOC | MPARSE_MAN);
 	r->rstackpos = -1;
@@ -1118,8 +1122,10 @@
 roff_res(struct roff *r, struct buf *buf, int ln, int pos)
 {
 	char		 ubuf[24]; /* buffer to print the number */
+	struct roff_node *n;	/* used for header comments */
 	const char	*start;	/* start of the string to process */
 	char		*stesc;	/* start of an escape sequence ('\\') */
+	char		*ep;	/* end of comment string */
 	const char	*stnam;	/* start of the name, after "[(*" */
 	const char	*cp;	/* end of the name, e.g. before ']' */
 	const char	*res;	/* the string to be substituted */
@@ -1134,6 +1140,7 @@
 	int		 done;	/* no more input available */
 	int		 deftype; /* type of definition to paste */
 	int		 rcsid;	/* kind of RCS id seen */
+	char		 sign;	/* increment number register */
 	char		 term;	/* character terminating the escape */
 
 	/* Search forward for comments. */
@@ -1168,14 +1175,35 @@
 
 		/* Handle trailing whitespace. */
 
-		cp = strchr(stesc--, '\0') - 1;
-		if (*cp == '\n') {
+		ep = strchr(stesc--, '\0') - 1;
+		if (*ep == '\n') {
 			done = 1;
-			cp--;
+			ep--;
 		}
-		if (*cp == ' ' || *cp == '\t')
+		if (*ep == ' ' || *ep == '\t')
 			mandoc_msg(MANDOCERR_SPACE_EOL, r->parse,
-			    ln, cp - buf->buf, NULL);
+			    ln, ep - buf->buf, NULL);
+
+		/*
+		 * Save comments preceding the title macro
+		 * in the syntax tree.
+		 */
+
+		if (r->format == 0) {
+			while (*ep == ' ' || *ep == '\t')
+				ep--;
+			ep[1] = '\0';
+			n = roff_node_alloc(r->man,
+			    ln, stesc + 1 - buf->buf,
+			    ROFFT_COMMENT, TOKEN_NONE);
+			n->string = mandoc_strdup(stesc + 2);
+			roff_node_append(r->man, n);
+			n->flags |= NODE_VALID | NODE_ENDED;
+			r->man->next = ROFF_NEXT_SIBLING;
+		}
+
+		/* Discard comments. */
+
 		while (stesc > start && stesc[-1] == ' ')
 			stesc--;
 		*stesc = '\0';
@@ -1244,6 +1272,9 @@
 			term = cp[1];
 			/* FALLTHROUGH */
 		case 'n':
+			sign = cp[1];
+			if (sign == '+' || sign == '-')
+				cp++;
 			res = ubuf;
 			break;
 		default:
@@ -1348,7 +1379,7 @@
 		case 'n':
 			if (arg_complete)
 				(void)snprintf(ubuf, sizeof(ubuf), "%d",
-				    roff_getregn(r, stnam, naml));
+				    roff_getregn(r, stnam, naml, sign));
 			else
 				ubuf[0] = '\0';
 			break;
@@ -1639,6 +1670,11 @@
 	}
 	if (t != TOKEN_NONE)
 		*pos = cp - buf;
+	else if (deftype == ROFFDEF_UNDEF) {
+		/* Using an undefined macro defines it to be empty. */
+		roff_setstrn(&r->strtab, mac, maclen, "", 0, 0);
+		roff_setstrn(&r->rentab, mac, maclen, NULL, 0, 0);
+	}
 	return t;
 }
 
@@ -2515,20 +2551,29 @@
 void
 roff_setreg(struct roff *r, const char *name, int val, char sign)
 {
+	roff_setregn(r, name, strlen(name), val, sign, INT_MIN);
+}
+
+static void
+roff_setregn(struct roff *r, const char *name, size_t len,
+    int val, char sign, int step)
+{
 	struct roffreg	*reg;
 
 	/* Search for an existing register with the same name. */
 	reg = r->regtab;
 
-	while (reg && strcmp(name, reg->key.p))
+	while (reg != NULL && (reg->key.sz != len ||
+	    strncmp(reg->key.p, name, len) != 0))
 		reg = reg->next;
 
 	if (NULL == reg) {
 		/* Create a new register. */
 		reg = mandoc_malloc(sizeof(struct roffreg));
-		reg->key.p = mandoc_strdup(name);
-		reg->key.sz = strlen(name);
+		reg->key.p = mandoc_strndup(name, len);
+		reg->key.sz = len;
 		reg->val = 0;
+		reg->step = 0;
 		reg->next = r->regtab;
 		r->regtab = reg;
 	}
@@ -2539,6 +2584,8 @@
 		reg->val -= val;
 	else
 		reg->val = val;
+	if (step != INT_MIN)
+		reg->step = step;
 }
 
 /*
@@ -2572,26 +2619,13 @@
 }
 
 int
-roff_getreg(const struct roff *r, const char *name)
+roff_getreg(struct roff *r, const char *name)
 {
-	struct roffreg	*reg;
-	int		 val;
-
-	if ('.' == name[0] && '\0' != name[1] && '\0' == name[2]) {
-		val = roff_getregro(r, name + 1);
-		if (-1 != val)
-			return val;
-	}
-
-	for (reg = r->regtab; reg; reg = reg->next)
-		if (0 == strcmp(name, reg->key.p))
-			return reg->val;
-
-	return 0;
+	return roff_getregn(r, name, strlen(name), '\0');
 }
 
 static int
-roff_getregn(const struct roff *r, const char *name, size_t len)
+roff_getregn(struct roff *r, const char *name, size_t len, char sign)
 {
 	struct roffreg	*reg;
 	int		 val;
@@ -2602,11 +2636,24 @@
 			return val;
 	}
 
-	for (reg = r->regtab; reg; reg = reg->next)
+	for (reg = r->regtab; reg; reg = reg->next) {
 		if (len == reg->key.sz &&
-		    0 == strncmp(name, reg->key.p, len))
+		    0 == strncmp(name, reg->key.p, len)) {
+			switch (sign) {
+			case '+':
+				reg->val += reg->step;
+				break;
+			case '-':
+				reg->val -= reg->step;
+				break;
+			default:
+				break;
+			}
 			return reg->val;
+		}
+	}
 
+	roff_setregn(r, name, len, 0, '\0', INT_MIN);
 	return 0;
 }
 
@@ -2646,9 +2693,9 @@
 static enum rofferr
 roff_nr(ROFF_ARGS)
 {
-	char		*key, *val;
+	char		*key, *val, *step;
 	size_t		 keysz;
-	int		 iv;
+	int		 iv, is, len;
 	char		 sign;
 
 	key = val = buf->buf + pos;
@@ -2658,15 +2705,22 @@
 	keysz = roff_getname(r, &val, ln, pos);
 	if (key[keysz] == '\\')
 		return ROFF_IGN;
-	key[keysz] = '\0';
 
 	sign = *val;
 	if (sign == '+' || sign == '-')
 		val++;
 
-	if (roff_evalnum(r, ln, val, NULL, &iv, ROFFNUM_SCALE))
-		roff_setreg(r, key, iv, sign);
+	len = 0;
+	if (roff_evalnum(r, ln, val, &len, &iv, ROFFNUM_SCALE) == 0)
+		return ROFF_IGN;
 
+	step = val + len;
+	while (isspace((unsigned char)*step))
+		step++;
+	if (roff_evalnum(r, ln, step, NULL, &is, 0) == 0)
+		is = INT_MIN;
+
+	roff_setregn(r, key, keysz, iv, sign, is);
 	return ROFF_IGN;
 }
 
@@ -2791,6 +2845,7 @@
 		free(buf->buf);
 		buf->buf = mandoc_strdup(".sp");
 		buf->sz = 4;
+		*offs = 0;
 		return ROFF_REPARSE;
 	}
 	r->tbl = NULL;
@@ -3310,6 +3365,7 @@
 			    ln, (int)(cp - n1), NULL);
 			free(buf->buf);
 			buf->buf = n1;
+			*offs = 0;
 			return ROFF_IGN;
 		}
 
@@ -3404,6 +3460,7 @@
 	    buf->buf[pos] == '\0' ? "" : " ", buf->buf + pos) + 1;
 	free(buf->buf);
 	buf->buf = nbuf;
+	*offs = 0;
 	return ROFF_CONT;
 }
 
@@ -3537,62 +3594,95 @@
 }
 
 static const char *
-roff_getstrn(const struct roff *r, const char *name, size_t len,
+roff_getstrn(struct roff *r, const char *name, size_t len,
     int *deftype)
 {
 	const struct roffkv	*n;
-	int			 i;
+	int			 found, i;
 	enum roff_tok		 tok;
 
-	if (*deftype & ROFFDEF_USER) {
-		for (n = r->strtab; n != NULL; n = n->next) {
-			if (strncmp(name, n->key.p, len) == 0 &&
-			    n->key.p[len] == '\0' &&
-			    n->val.p != NULL) {
-				*deftype = ROFFDEF_USER;
-				return n->val.p;
-			}
+	found = 0;
+	for (n = r->strtab; n != NULL; n = n->next) {
+		if (strncmp(name, n->key.p, len) != 0 ||
+		    n->key.p[len] != '\0' || n->val.p == NULL)
+			continue;
+		if (*deftype & ROFFDEF_USER) {
+			*deftype = ROFFDEF_USER;
+			return n->val.p;
+		} else {
+			found = 1;
+			break;
 		}
 	}
-	if (*deftype & ROFFDEF_PRE) {
-		for (i = 0; i < PREDEFS_MAX; i++) {
-			if (strncmp(name, predefs[i].name, len) == 0 &&
-			    predefs[i].name[len] == '\0') {
-				*deftype = ROFFDEF_PRE;
-				return predefs[i].str;
-			}
+	for (n = r->rentab; n != NULL; n = n->next) {
+		if (strncmp(name, n->key.p, len) != 0 ||
+		    n->key.p[len] != '\0' || n->val.p == NULL)
+			continue;
+		if (*deftype & ROFFDEF_REN) {
+			*deftype = ROFFDEF_REN;
+			return n->val.p;
+		} else {
+			found = 1;
+			break;
 		}
 	}
-	if (*deftype & ROFFDEF_REN) {
-		for (n = r->rentab; n != NULL; n = n->next) {
-			if (strncmp(name, n->key.p, len) == 0 &&
-			    n->key.p[len] == '\0' &&
-			    n->val.p != NULL) {
-				*deftype = ROFFDEF_REN;
-				return n->val.p;
-			}
+	for (i = 0; i < PREDEFS_MAX; i++) {
+		if (strncmp(name, predefs[i].name, len) != 0 ||
+		    predefs[i].name[len] != '\0')
+			continue;
+		if (*deftype & ROFFDEF_PRE) {
+			*deftype = ROFFDEF_PRE;
+			return predefs[i].str;
+		} else {
+			found = 1;
+			break;
 		}
 	}
-	if (*deftype & ROFFDEF_STD) {
-		if (r->man->macroset != MACROSET_MAN) {
-			for (tok = MDOC_Dd; tok < MDOC_MAX; tok++) {
-				if (strncmp(name, roff_name[tok], len) == 0 &&
-				    roff_name[tok][len] == '\0') {
-					*deftype = ROFFDEF_STD;
-					return NULL;
-				}
+	if (r->man->macroset != MACROSET_MAN) {
+		for (tok = MDOC_Dd; tok < MDOC_MAX; tok++) {
+			if (strncmp(name, roff_name[tok], len) != 0 ||
+			    roff_name[tok][len] != '\0')
+				continue;
+			if (*deftype & ROFFDEF_STD) {
+				*deftype = ROFFDEF_STD;
+				return NULL;
+			} else {
+				found = 1;
+				break;
 			}
 		}
-		if (r->man->macroset != MACROSET_MDOC) {
-			for (tok = MAN_TH; tok < MAN_MAX; tok++) {
-				if (strncmp(name, roff_name[tok], len) == 0 &&
-				    roff_name[tok][len] == '\0') {
-					*deftype = ROFFDEF_STD;
-					return NULL;
-				}
+	}
+	if (r->man->macroset != MACROSET_MDOC) {
+		for (tok = MAN_TH; tok < MAN_MAX; tok++) {
+			if (strncmp(name, roff_name[tok], len) != 0 ||
+			    roff_name[tok][len] != '\0')
+				continue;
+			if (*deftype & ROFFDEF_STD) {
+				*deftype = ROFFDEF_STD;
+				return NULL;
+			} else {
+				found = 1;
+				break;
 			}
 		}
 	}
+
+	if (found == 0 && *deftype != ROFFDEF_ANY) {
+		if (*deftype & ROFFDEF_REN) {
+			/*
+			 * This might still be a request,
+			 * so do not treat it as undefined yet.
+			 */
+			*deftype = ROFFDEF_UNDEF;
+			return NULL;
+		}
+
+		/* Using an undefined string defines it to be empty. */
+
+		roff_setstrn(&r->strtab, name, len, "", 0, 0);
+		roff_setstrn(&r->rentab, name, len, NULL, 0, 0);
+	}
+
 	*deftype = 0;
 	return NULL;
 }
--- old/usr/src/cmd/mandoc/roff.h	Thu Aug  9 15:28:40 2018
+++ new/usr/src/cmd/mandoc/roff.h	Thu Aug  9 15:28:40 2018
@@ -1,4 +1,4 @@
-/*	$Id: roff.h,v 1.58 2017/07/08 14:51:05 schwarze Exp $	*/
+/*	$Id: roff.h,v 1.59 2018/04/11 17:11:13 schwarze Exp $	*/
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@@ -61,6 +61,7 @@
 	ROFFT_TAIL,
 	ROFFT_ELEM,
 	ROFFT_TEXT,
+	ROFFT_COMMENT,
 	ROFFT_TBL,
 	ROFFT_EQN
 };
--- old/usr/src/cmd/mandoc/roff_html.c	Thu Aug  9 15:28:40 2018
+++ new/usr/src/cmd/mandoc/roff_html.c	Thu Aug  9 15:28:40 2018
@@ -1,7 +1,7 @@
-/*	$Id: roff_html.c,v 1.11 2017/06/24 14:38:33 schwarze Exp $ */
+/*	$Id: roff_html.c,v 1.12 2018/06/25 14:53:58 schwarze Exp $ */
 /*
  * Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2014, 2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2014, 2017, 2018 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
@@ -82,15 +82,5 @@
 static void
 roff_html_pre_sp(ROFF_HTML_ARGS)
 {
-	struct roffsu	 su;
-
-	SCALE_VS_INIT(&su, 1);
-	if ((n = n->child) != NULL) {
-		if (a2roffsu(n->string, &su, SCALE_VS) == NULL)
-			su.scale = 1.0;
-		else if (su.scale < 0.0)
-			su.scale = 0.0;
-	}
-	print_otag(h, TAG_DIV, "suh", &su);
-	print_text(h, "\\~");  /* So the div isn't empty. */
+	print_paragraph(h);
 }
--- old/usr/src/cmd/mandoc/st.in	Thu Aug  9 15:28:41 2018
+++ new/usr/src/cmd/mandoc/st.in	Thu Aug  9 15:28:41 2018
@@ -1,4 +1,4 @@
-/*	$Id: st.in,v 1.29 2017/06/24 13:49:29 schwarze Exp $ */
+/*	$Id: st.in,v 1.30 2018/04/05 09:17:26 schwarze Exp $ */
 /*
  * Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
  *
@@ -28,49 +28,49 @@
  * REMEMBER TO ADD NEW STANDARDS TO MDOC.7!
  */
 
-LINE("-p1003.1-88",	"IEEE Std 1003.1-1988 (\\(LqPOSIX.1\\(Rq)")
-LINE("-p1003.1-90",	"IEEE Std 1003.1-1990 (\\(LqPOSIX.1\\(Rq)")
-LINE("-p1003.1-96",	"ISO/IEC 9945-1:1996 (\\(LqPOSIX.1\\(Rq)")
-LINE("-p1003.1-2001",	"IEEE Std 1003.1-2001 (\\(LqPOSIX.1\\(Rq)")
-LINE("-p1003.1-2004",	"IEEE Std 1003.1-2004 (\\(LqPOSIX.1\\(Rq)")
-LINE("-p1003.1-2008",	"IEEE Std 1003.1-2008 (\\(LqPOSIX.1\\(Rq)")
-LINE("-p1003.1",	"IEEE Std 1003.1 (\\(LqPOSIX.1\\(Rq)")
-LINE("-p1003.1b",	"IEEE Std 1003.1b (\\(LqPOSIX.1b\\(Rq)")
-LINE("-p1003.1b-93",	"IEEE Std 1003.1b-1993 (\\(LqPOSIX.1b\\(Rq)")
-LINE("-p1003.1c-95",	"IEEE Std 1003.1c-1995 (\\(LqPOSIX.1c\\(Rq)")
-LINE("-p1003.1g-2000",	"IEEE Std 1003.1g-2000 (\\(LqPOSIX.1g\\(Rq)")
-LINE("-p1003.1i-95",	"IEEE Std 1003.1i-1995 (\\(LqPOSIX.1i\\(Rq)")
-LINE("-p1003.2",	"IEEE Std 1003.2 (\\(LqPOSIX.2\\(Rq)")
-LINE("-p1003.2-92",	"IEEE Std 1003.2-1992 (\\(LqPOSIX.2\\(Rq)")
-LINE("-p1003.2a-92",	"IEEE Std 1003.2a-1992 (\\(LqPOSIX.2\\(Rq)")
-LINE("-isoC",		"ISO/IEC 9899:1990 (\\(LqISO\\~C90\\(Rq)")
-LINE("-isoC-90",	"ISO/IEC 9899:1990 (\\(LqISO\\~C90\\(Rq)")
-LINE("-isoC-amd1",	"ISO/IEC 9899/AMD1:1995 (\\(LqISO\\~C90, Amendment 1\\(Rq)")
-LINE("-isoC-tcor1",	"ISO/IEC 9899/TCOR1:1994 (\\(LqISO\\~C90, Technical Corrigendum 1\\(Rq)")
-LINE("-isoC-tcor2",	"ISO/IEC 9899/TCOR2:1995 (\\(LqISO\\~C90, Technical Corrigendum 2\\(Rq)")
-LINE("-isoC-99",	"ISO/IEC 9899:1999 (\\(LqISO\\~C99\\(Rq)")
-LINE("-isoC-2011",	"ISO/IEC 9899:2011 (\\(LqISO\\~C11\\(Rq)")
-LINE("-iso9945-1-90",	"ISO/IEC 9945-1:1990 (\\(LqPOSIX.1\\(Rq)")
-LINE("-iso9945-1-96",	"ISO/IEC 9945-1:1996 (\\(LqPOSIX.1\\(Rq)")
-LINE("-iso9945-2-93",	"ISO/IEC 9945-2:1993 (\\(LqPOSIX.2\\(Rq)")
-LINE("-ansiC",		"ANSI X3.159-1989 (\\(LqANSI\\~C89\\(Rq)")
-LINE("-ansiC-89",	"ANSI X3.159-1989 (\\(LqANSI\\~C89\\(Rq)")
+LINE("-p1003.1-88",	"IEEE Std 1003.1-1988 (\\(lqPOSIX.1\\(rq)")
+LINE("-p1003.1-90",	"IEEE Std 1003.1-1990 (\\(lqPOSIX.1\\(rq)")
+LINE("-p1003.1-96",	"ISO/IEC 9945-1:1996 (\\(lqPOSIX.1\\(rq)")
+LINE("-p1003.1-2001",	"IEEE Std 1003.1-2001 (\\(lqPOSIX.1\\(rq)")
+LINE("-p1003.1-2004",	"IEEE Std 1003.1-2004 (\\(lqPOSIX.1\\(rq)")
+LINE("-p1003.1-2008",	"IEEE Std 1003.1-2008 (\\(lqPOSIX.1\\(rq)")
+LINE("-p1003.1",	"IEEE Std 1003.1 (\\(lqPOSIX.1\\(rq)")
+LINE("-p1003.1b",	"IEEE Std 1003.1b (\\(lqPOSIX.1b\\(rq)")
+LINE("-p1003.1b-93",	"IEEE Std 1003.1b-1993 (\\(lqPOSIX.1b\\(rq)")
+LINE("-p1003.1c-95",	"IEEE Std 1003.1c-1995 (\\(lqPOSIX.1c\\(rq)")
+LINE("-p1003.1g-2000",	"IEEE Std 1003.1g-2000 (\\(lqPOSIX.1g\\(rq)")
+LINE("-p1003.1i-95",	"IEEE Std 1003.1i-1995 (\\(lqPOSIX.1i\\(rq)")
+LINE("-p1003.2",	"IEEE Std 1003.2 (\\(lqPOSIX.2\\(rq)")
+LINE("-p1003.2-92",	"IEEE Std 1003.2-1992 (\\(lqPOSIX.2\\(rq)")
+LINE("-p1003.2a-92",	"IEEE Std 1003.2a-1992 (\\(lqPOSIX.2\\(rq)")
+LINE("-isoC",		"ISO/IEC 9899:1990 (\\(lqISO\\~C90\\(rq)")
+LINE("-isoC-90",	"ISO/IEC 9899:1990 (\\(lqISO\\~C90\\(rq)")
+LINE("-isoC-amd1",	"ISO/IEC 9899/AMD1:1995 (\\(lqISO\\~C90, Amendment 1\\(rq)")
+LINE("-isoC-tcor1",	"ISO/IEC 9899/TCOR1:1994 (\\(lqISO\\~C90, Technical Corrigendum 1\\(rq)")
+LINE("-isoC-tcor2",	"ISO/IEC 9899/TCOR2:1995 (\\(lqISO\\~C90, Technical Corrigendum 2\\(rq)")
+LINE("-isoC-99",	"ISO/IEC 9899:1999 (\\(lqISO\\~C99\\(rq)")
+LINE("-isoC-2011",	"ISO/IEC 9899:2011 (\\(lqISO\\~C11\\(rq)")
+LINE("-iso9945-1-90",	"ISO/IEC 9945-1:1990 (\\(lqPOSIX.1\\(rq)")
+LINE("-iso9945-1-96",	"ISO/IEC 9945-1:1996 (\\(lqPOSIX.1\\(rq)")
+LINE("-iso9945-2-93",	"ISO/IEC 9945-2:1993 (\\(lqPOSIX.2\\(rq)")
+LINE("-ansiC",		"ANSI X3.159-1989 (\\(lqANSI\\~C89\\(rq)")
+LINE("-ansiC-89",	"ANSI X3.159-1989 (\\(lqANSI\\~C89\\(rq)")
 LINE("-ieee754",	"IEEE Std 754-1985")
 LINE("-iso8802-3",	"ISO 8802-3: 1989")
 LINE("-iso8601",	"ISO 8601")
-LINE("-ieee1275-94",	"IEEE Std 1275-1994 (\\(LqOpen Firmware\\(Rq)")
-LINE("-xpg3",		"X/Open Portability Guide Issue\\~3 (\\(LqXPG3\\(Rq)")
-LINE("-xpg4",		"X/Open Portability Guide Issue\\~4 (\\(LqXPG4\\(Rq)")
-LINE("-xpg4.2",		"X/Open Portability Guide Issue\\~4, Version\\~2 (\\(LqXPG4.2\\(Rq)")
-LINE("-xbd5",		"X/Open Base Definitions Issue\\~5 (\\(LqXBD5\\(Rq)")
-LINE("-xcu5",		"X/Open Commands and Utilities Issue\\~5 (\\(LqXCU5\\(Rq)")
-LINE("-xsh4.2",		"X/Open System Interfaces and Headers Issue\\~4, Version\\~2 (\\(LqXSH4.2\\(Rq)")
-LINE("-xsh5",		"X/Open System Interfaces and Headers Issue\\~5 (\\(LqXSH5\\(Rq)")
-LINE("-xns5",		"X/Open Networking Services Issue\\~5 (\\(LqXNS5\\(Rq)")
-LINE("-xns5.2",		"X/Open Networking Services Issue\\~5.2 (\\(LqXNS5.2\\(Rq)")
-LINE("-xcurses4.2",	"X/Open Curses Issue\\~4, Version\\~2 (\\(LqXCURSES4.2\\(Rq)")
-LINE("-susv1",		"Version\\~1 of the Single UNIX Specification (\\(LqSUSv1\\(Rq)")
-LINE("-susv2",		"Version\\~2 of the Single UNIX Specification (\\(LqSUSv2\\(Rq)")
-LINE("-susv3",		"Version\\~3 of the Single UNIX Specification (\\(LqSUSv3\\(Rq)")
-LINE("-susv4",		"Version\\~4 of the Single UNIX Specification (\\(LqSUSv4\\(Rq)")
-LINE("-svid4",		"System\\~V Interface Definition, Fourth Edition (\\(LqSVID4\\(Rq)")
+LINE("-ieee1275-94",	"IEEE Std 1275-1994 (\\(lqOpen Firmware\\(rq)")
+LINE("-xpg3",		"X/Open Portability Guide Issue\\~3 (\\(lqXPG3\\(rq)")
+LINE("-xpg4",		"X/Open Portability Guide Issue\\~4 (\\(lqXPG4\\(rq)")
+LINE("-xpg4.2",		"X/Open Portability Guide Issue\\~4, Version\\~2 (\\(lqXPG4.2\\(rq)")
+LINE("-xbd5",		"X/Open Base Definitions Issue\\~5 (\\(lqXBD5\\(rq)")
+LINE("-xcu5",		"X/Open Commands and Utilities Issue\\~5 (\\(lqXCU5\\(rq)")
+LINE("-xsh4.2",		"X/Open System Interfaces and Headers Issue\\~4, Version\\~2 (\\(lqXSH4.2\\(rq)")
+LINE("-xsh5",		"X/Open System Interfaces and Headers Issue\\~5 (\\(lqXSH5\\(rq)")
+LINE("-xns5",		"X/Open Networking Services Issue\\~5 (\\(lqXNS5\\(rq)")
+LINE("-xns5.2",		"X/Open Networking Services Issue\\~5.2 (\\(lqXNS5.2\\(rq)")
+LINE("-xcurses4.2",	"X/Open Curses Issue\\~4, Version\\~2 (\\(lqXCURSES4.2\\(rq)")
+LINE("-susv1",		"Version\\~1 of the Single UNIX Specification (\\(lqSUSv1\\(rq)")
+LINE("-susv2",		"Version\\~2 of the Single UNIX Specification (\\(lqSUSv2\\(rq)")
+LINE("-susv3",		"Version\\~3 of the Single UNIX Specification (\\(lqSUSv3\\(rq)")
+LINE("-susv4",		"Version\\~4 of the Single UNIX Specification (\\(lqSUSv4\\(rq)")
+LINE("-svid4",		"System\\~V Interface Definition, Fourth Edition (\\(lqSVID4\\(rq)")
--- old/usr/src/cmd/mandoc/tag.c	Thu Aug  9 15:28:41 2018
+++ new/usr/src/cmd/mandoc/tag.c	Thu Aug  9 15:28:41 2018
@@ -1,4 +1,4 @@
-/*	$Id: tag.c,v 1.18 2017/02/17 14:31:52 schwarze Exp $ */
+/*	$Id: tag.c,v 1.19 2018/02/23 16:47:10 schwarze Exp $ */
 /*
  * Copyright (c) 2015, 2016 Ingo Schwarze <schwarze@openbsd.org>
  *
@@ -213,6 +213,9 @@
 	ohash_delete(&tag_data);
 	if (stream != NULL)
 		fclose(stream);
+	else
+		close(tag_files.tfd);
+	tag_files.tfd = -1;
 }
 
 void
--- old/usr/src/cmd/mandoc/tbl_html.c	Thu Aug  9 15:28:41 2018
+++ new/usr/src/cmd/mandoc/tbl_html.c	Thu Aug  9 15:28:41 2018
@@ -1,4 +1,4 @@
-/*	$Id: tbl_html.c,v 1.23 2017/07/31 16:14:10 schwarze Exp $ */
+/*	$Id: tbl_html.c,v 1.24 2018/06/25 13:45:57 schwarze Exp $ */
 /*
  * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@@ -79,9 +79,6 @@
 static void
 html_tblopen(struct html *h, const struct tbl_span *sp)
 {
-	struct tag	*t;
-	int		 ic;
-
 	if (h->tbl.cols == NULL) {
 		h->tbl.len = html_tbl_len;
 		h->tbl.slen = html_tbl_strlen;
@@ -88,14 +85,8 @@
 		h->tbl.sulen = html_tbl_sulen;
 		tblcalc(&h->tbl, sp, 0, 0);
 	}
-
 	assert(NULL == h->tblt);
 	h->tblt = print_otag(h, TAG_TABLE, "c", "tbl");
-
-	t = print_otag(h, TAG_COLGROUP, "");
-	for (ic = 0; ic < sp->opts->cols; ic++)
-		print_otag(h, TAG_COL, "shw", h->tbl.cols[ic].width);
-	print_tagq(h, t);
 }
 
 void
--- old/usr/src/cmd/mandoc/term_ascii.c	Thu Aug  9 15:28:41 2018
+++ new/usr/src/cmd/mandoc/term_ascii.c	Thu Aug  9 15:28:41 2018
@@ -1,7 +1,7 @@
-/*	$Id: term_ascii.c,v 1.58 2017/06/14 14:24:20 schwarze Exp $ */
+/*	$Id: term_ascii.c,v 1.61 2018/05/20 21:37:34 schwarze Exp $ */
 /*
  * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2014, 2015, 2017, 2018 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
@@ -21,11 +21,13 @@
 
 #include <assert.h>
 #if HAVE_WCHAR
+#include <langinfo.h>
 #include <locale.h>
 #endif
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 #if HAVE_WCHAR
 #include <wchar.h>
@@ -100,7 +102,17 @@
 		v = TERMENC_LOCALE == enc ?
 		    setlocale(LC_CTYPE, "") :
 		    setlocale(LC_CTYPE, UTF8_LOCALE);
-		if (NULL != v && MB_CUR_MAX > 1) {
+
+		/*
+		 * We only support UTF-8,
+		 * so revert to ASCII for anything else.
+		 */
+
+		if (v != NULL &&
+		    strcmp(nl_langinfo(CODESET), "UTF-8") != 0)
+			v = setlocale(LC_CTYPE, "C");
+
+		if (v != NULL && MB_CUR_MAX > 1) {
 			p->enc = enc;
 			p->advance = locale_advance;
 			p->endline = locale_endline;
@@ -121,6 +133,8 @@
 	if (outopts->synopsisonly)
 		p->synopsisonly = 1;
 
+	assert(p->defindent < UINT16_MAX);
+	assert(p->defrmargin < UINT16_MAX);
 	return p;
 }
 
@@ -159,6 +173,8 @@
 		p->defrmargin -= width;
 	else
 		p->defrmargin = 0;
+	if (p->defrmargin > 1000)
+		p->defrmargin = 1000;
 	p->lastrmargin = p->tcol->rmargin;
 	p->tcol->rmargin = p->maxrmargin = p->defrmargin;
 }
@@ -227,6 +243,7 @@
 {
 	size_t		i;
 
+	assert(len < UINT16_MAX);
 	for (i = 0; i < len; i++)
 		putchar(' ');
 }
@@ -294,17 +311,17 @@
 	"<88>",	"<89>",	"<8A>",	"<8B>",	"<8C>",	"<8D>",	"<8E>",	"<8F>",
 	"<90>",	"<91>",	"<92>",	"<93>",	"<94>",	"<95>",	"<96>",	"<97>",
 	"<98>",	"<99>",	"<9A>",	"<9B>",	"<9C>",	"<9D>",	"<9E>",	"<9F>",
-	nbrsp,	"!",	"/\bc",	"GBP",	"o\bx",	"=\bY",	"|",	"<sec>",
+	nbrsp,	"!",	"/\bc",	"GBP",	"o\bx",	"=\bY",	"|",	"<section>",
 	"\"",	"(C)",	"_\ba",	"<<",	"~",	"",	"(R)",	"-",
-	"<deg>","+-",	"2",	"3",	"'",	",\bu",	"<par>",".",
-	",",	"1",	"_\bo",	">>",	"1/4",	"1/2",	"3/4",	"?",
+	"<degree>","+-","^2",	"^3",	"'","<micro>","<paragraph>",".",
+	",",	"^1",	"_\bo",	">>",	"1/4",	"1/2",	"3/4",	"?",
 	"`\bA",	"'\bA",	"^\bA",	"~\bA",	"\"\bA","o\bA",	"AE",	",\bC",
 	"`\bE",	"'\bE",	"^\bE",	"\"\bE","`\bI",	"'\bI",	"^\bI",	"\"\bI",
-	"-\bD",	"~\bN",	"`\bO",	"'\bO",	"^\bO",	"~\bO",	"\"\bO","x",
+	"Dh",	"~\bN",	"`\bO",	"'\bO",	"^\bO",	"~\bO",	"\"\bO","x",
 	"/\bO",	"`\bU",	"'\bU",	"^\bU",	"\"\bU","'\bY",	"Th",	"ss",
 	"`\ba",	"'\ba",	"^\ba",	"~\ba",	"\"\ba","o\ba",	"ae",	",\bc",
 	"`\be",	"'\be",	"^\be",	"\"\be","`\bi",	"'\bi",	"^\bi",	"\"\bi",
-	"d",	"~\bn",	"`\bo",	"'\bo",	"^\bo",	"~\bo",	"\"\bo","-:-",
+	"dh",	"~\bn",	"`\bo",	"'\bo",	"^\bo",	"~\bo",	"\"\bo","/",
 	"/\bo",	"`\bu",	"'\bu",	"^\bu",	"\"\bu","'\by",	"th",	"\"\by",
 	"A",	"a",	"A",	"a",	"A",	"a",	"'\bC",	"'\bc",
 	"^\bC",	"^\bc",	"C",	"c",	"C",	"c",	"D",	"d",
@@ -364,6 +381,7 @@
 {
 	size_t		i;
 
+	assert(len < UINT16_MAX);
 	for (i = 0; i < len; i++)
 		putwchar(L' ');
 }
--- old/usr/src/cmd/mandoc/term_ps.c	Thu Aug  9 15:28:42 2018
+++ new/usr/src/cmd/mandoc/term_ps.c	Thu Aug  9 15:28:42 2018
@@ -1,7 +1,8 @@
-/*	$Id: term_ps.c,v 1.85 2017/06/07 17:38:26 schwarze Exp $ */
+/*	$Id: term_ps.c,v 1.91 2017/11/10 23:42:52 schwarze Exp $ */
 /*
  * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2014, 2015, 2016, 2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2017 Marc Espie <espie@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
@@ -66,6 +67,7 @@
 	size_t		  pscol;	/* visible column (AFM units) */
 	size_t		  pscolnext;	/* used for overstrike */
 	size_t		  psrow;	/* visible row (AFM units) */
+	size_t		  lastrow;	/* psrow of the previous word */
 	char		 *psmarg;	/* margin buf */
 	size_t		  psmargsz;	/* margin buf size */
 	size_t		  psmargcur;	/* cur index in margin buf */
@@ -77,6 +79,7 @@
 	size_t		  lineheight;	/* line height (AFM units) */
 	size_t		  top;		/* body top (AFM units) */
 	size_t		  bottom;	/* body bottom (AFM units) */
+	const char	 *medianame;	/* for DocumentMedia and PageSize */
 	size_t		  height;	/* page height (AFM units */
 	size_t		  width;	/* page width (AFM units) */
 	size_t		  lastwidth;	/* page width before last ll */
@@ -108,7 +111,7 @@
 static	void		  ps_putchar(struct termp *, char);
 static	void		  ps_setfont(struct termp *, enum termfont);
 static	void		  ps_setwidth(struct termp *, int, int);
-static	struct termp	 *pspdf_alloc(const struct manoutput *);
+static	struct termp	 *pspdf_alloc(const struct manoutput *, enum termtype);
 static	void		  pdf_obj(struct termp *, size_t);
 
 /*
@@ -511,27 +514,17 @@
 void *
 pdf_alloc(const struct manoutput *outopts)
 {
-	struct termp	*p;
-
-	if (NULL != (p = pspdf_alloc(outopts)))
-		p->type = TERMTYPE_PDF;
-
-	return p;
+	return pspdf_alloc(outopts, TERMTYPE_PDF);
 }
 
 void *
 ps_alloc(const struct manoutput *outopts)
 {
-	struct termp	*p;
-
-	if (NULL != (p = pspdf_alloc(outopts)))
-		p->type = TERMTYPE_PS;
-
-	return p;
+	return pspdf_alloc(outopts, TERMTYPE_PS);
 }
 
 static struct termp *
-pspdf_alloc(const struct manoutput *outopts)
+pspdf_alloc(const struct manoutput *outopts, enum termtype type)
 {
 	struct termp	*p;
 	unsigned int	 pagex, pagey;
@@ -541,6 +534,7 @@
 	p = mandoc_calloc(1, sizeof(*p));
 	p->tcol = p->tcols = mandoc_calloc(1, sizeof(*p->tcol));
 	p->maxtcol = 1;
+	p->type = type;
 
 	p->enc = TERMENC_ASCII;
 	p->fontq = mandoc_reallocarray(NULL,
@@ -559,6 +553,7 @@
 
 	/* Default to US letter (millimetres). */
 
+	p->ps->medianame = "Letter";
 	pagex = 216;
 	pagey = 279;
 
@@ -570,20 +565,26 @@
 	 */
 
 	pp = outopts->paper;
-	if (pp && strcasecmp(pp, "letter")) {
-		if (0 == strcasecmp(pp, "a3")) {
+	if (pp != NULL && strcasecmp(pp, "letter") != 0) {
+		if (strcasecmp(pp, "a3") == 0) {
+			p->ps->medianame = "A3";
 			pagex = 297;
 			pagey = 420;
-		} else if (0 == strcasecmp(pp, "a4")) {
+		} else if (strcasecmp(pp, "a4") == 0) {
+			p->ps->medianame = "A4";
 			pagex = 210;
 			pagey = 297;
-		} else if (0 == strcasecmp(pp, "a5")) {
+		} else if (strcasecmp(pp, "a5") == 0) {
+			p->ps->medianame = "A5";
 			pagex = 148;
 			pagey = 210;
-		} else if (0 == strcasecmp(pp, "legal")) {
+		} else if (strcasecmp(pp, "legal") == 0) {
+			p->ps->medianame = "Legal";
 			pagex = 216;
 			pagey = 356;
-		} else if (2 != sscanf(pp, "%ux%u", &pagex, &pagey))
+		} else if (sscanf(pp, "%ux%u", &pagex, &pagey) == 2)
+			p->ps->medianame = "CustomSize";
+		else
 			warnx("%s: Unknown paper", pp);
 	}
 
@@ -596,8 +597,8 @@
 
 	/* Remember millimetres -> AFM units. */
 
-	pagex = PNT2AFM(p, ((double)pagex * 2.834));
-	pagey = PNT2AFM(p, ((double)pagey * 2.834));
+	pagex = PNT2AFM(p, ((double)pagex * 72.0 / 25.4));
+	pagey = PNT2AFM(p, ((double)pagey * 72.0 / 25.4));
 
 	/* Margins are 1/9 the page x and y. */
 
@@ -733,7 +734,7 @@
 
 	/*
 	 * Close out a page that we've already flushed to output.  In
-	 * PostScript, we simply note that the page must be showed.  In
+	 * PostScript, we simply note that the page must be shown.  In
 	 * PDF, we must now create the Length, Resource, and Page node
 	 * for the page contents.
 	 */
@@ -742,8 +743,6 @@
 	ps_printf(p, "%s", p->ps->psmarg);
 
 	if (TERMTYPE_PS != p->type) {
-		ps_printf(p, "ET\n");
-
 		len = p->ps->pdfbytes - p->ps->pdflastpg;
 		base = p->ps->pages * 4 + p->ps->pdfbody;
 
@@ -759,7 +758,7 @@
 		ps_printf(p, "/Font <<\n");
 		for (i = 0; i < (int)TERMFONT__MAX; i++)
 			ps_printf(p, "/F%d %d 0 R\n", i, 3 + i);
-		ps_printf(p, ">>\n>>\n");
+		ps_printf(p, ">>\n>>\nendobj\n");
 
 		/* Page node. */
 		pdf_obj(p, base + 3);
@@ -824,7 +823,7 @@
 	ps_printf(p, "<<\n");
 	ps_printf(p, "/Type /Catalog\n");
 	ps_printf(p, "/Pages 2 0 R\n");
-	ps_printf(p, ">>\n");
+	ps_printf(p, ">>\nendobj\n");
 	xref = p->ps->pdfbytes;
 	ps_printf(p, "xref\n");
 	ps_printf(p, "0 %zu\n", base + 1);
@@ -848,6 +847,7 @@
 static void
 ps_begin(struct termp *p)
 {
+	size_t		 width, height;
 	int		 i;
 
 	/*
@@ -865,6 +865,7 @@
 	p->ps->flags = PS_MARGINS;
 	p->ps->pscol = p->ps->left;
 	p->ps->psrow = p->ps->header;
+	p->ps->lastrow = 0; /* impossible row */
 
 	ps_setfont(p, TERMFONT_NONE);
 
@@ -889,21 +890,44 @@
 	 */
 
 	if (TERMTYPE_PS == p->type) {
+		width = AFM2PNT(p, p->ps->width);
+		height = AFM2PNT(p, p->ps->height);
+
 		ps_printf(p, "%%!PS-Adobe-3.0\n");
 		ps_printf(p, "%%%%DocumentData: Clean7Bit\n");
 		ps_printf(p, "%%%%Orientation: Portrait\n");
 		ps_printf(p, "%%%%Pages: (atend)\n");
 		ps_printf(p, "%%%%PageOrder: Ascend\n");
-		ps_printf(p, "%%%%DocumentMedia: "
-		    "Default %zu %zu 0 () ()\n",
-		    (size_t)AFM2PNT(p, p->ps->width),
-		    (size_t)AFM2PNT(p, p->ps->height));
+		ps_printf(p, "%%%%DocumentMedia: man-%s %zu %zu 0 () ()\n",
+		    p->ps->medianame, width, height);
 		ps_printf(p, "%%%%DocumentNeededResources: font");
 
 		for (i = 0; i < (int)TERMFONT__MAX; i++)
 			ps_printf(p, " %s", fonts[i].name);
 
-		ps_printf(p, "\n%%%%EndComments\n");
+		ps_printf(p, "\n%%%%DocumentSuppliedResources: "
+		    "procset MandocProcs 1.0 0\n");
+		ps_printf(p, "%%%%EndComments\n");
+		ps_printf(p, "%%%%BeginProlog\n");
+		ps_printf(p, "%%%%BeginResource: procset MandocProcs "
+		    "10170 10170\n");
+		/* The font size is effectively hard-coded for now. */
+		ps_printf(p, "/fs %zu def\n", p->ps->scale);
+		for (i = 0; i < (int)TERMFONT__MAX; i++)
+			ps_printf(p, "/f%d { /%s fs selectfont } def\n",
+			    i, fonts[i].name);
+		ps_printf(p, "/s { 3 1 roll moveto show } bind def\n");
+		ps_printf(p, "/c { exch currentpoint exch pop "
+		    "moveto show } bind def\n");
+		ps_printf(p, "%%%%EndResource\n");
+		ps_printf(p, "%%%%EndProlog\n");
+		ps_printf(p, "%%%%BeginSetup\n");
+		ps_printf(p, "%%%%BeginFeature: *PageSize %s\n",
+		    p->ps->medianame);
+		ps_printf(p, "<</PageSize [%zu %zu]>>setpagedevice\n",
+		    width, height);
+		ps_printf(p, "%%%%EndFeature\n");
+		ps_printf(p, "%%%%EndSetup\n");
 	} else {
 		ps_printf(p, "%%PDF-1.1\n");
 		pdf_obj(p, 1);
@@ -918,7 +942,7 @@
 			ps_printf(p, "/Subtype /Type1\n");
 			ps_printf(p, "/Name /F%d\n", i);
 			ps_printf(p, "/BaseFont /%s\n", fonts[i].name);
-			ps_printf(p, ">>\n");
+			ps_printf(p, ">>\nendobj\n");
 		}
 	}
 
@@ -943,9 +967,7 @@
 		if (TERMTYPE_PS == p->type) {
 			ps_printf(p, "%%%%Page: %zu %zu\n",
 			    p->ps->pages + 1, p->ps->pages + 1);
-			ps_printf(p, "/%s %zu selectfont\n",
-			    fonts[(int)p->ps->lastf].name,
-			    p->ps->scale);
+			ps_printf(p, "f%d\n", (int)p->ps->lastf);
 		} else {
 			pdf_obj(p, p->ps->pdfbody +
 			    p->ps->pages * 4);
@@ -970,10 +992,13 @@
 			ps_printf(p, "%.3f %.3f Td\n(",
 			    AFM2PNT(p, p->ps->pscol),
 			    AFM2PNT(p, p->ps->psrow));
-		} else
-			ps_printf(p, "%.3f %.3f moveto\n(",
-			    AFM2PNT(p, p->ps->pscol),
-			    AFM2PNT(p, p->ps->psrow));
+		} else {
+			ps_printf(p, "%.3f", AFM2PNT(p, p->ps->pscol));
+			if (p->ps->psrow != p->ps->lastrow)
+				ps_printf(p, " %.3f",
+				    AFM2PNT(p, p->ps->psrow));
+			ps_printf(p, "(");
+		}
 		p->ps->flags |= PS_INLINE;
 	}
 
@@ -1021,10 +1046,14 @@
 	if ( ! (PS_INLINE & p->ps->flags))
 		return;
 
-	if (TERMTYPE_PS != p->type) {
+	if (TERMTYPE_PS != p->type)
 		ps_printf(p, ") Tj\nET\n");
-	} else
-		ps_printf(p, ") show\n");
+	else if (p->ps->psrow == p->ps->lastrow)
+		ps_printf(p, ")c\n");
+	else {
+		ps_printf(p, ")s\n");
+		p->ps->lastrow = p->ps->psrow;
+	}
 
 	p->ps->flags &= ~PS_INLINE;
 }
@@ -1243,8 +1272,7 @@
 		return;
 
 	if (TERMTYPE_PS == p->type)
-		ps_printf(p, "/%s %zu selectfont\n",
-		    fonts[(int)f].name, p->ps->scale);
+		ps_printf(p, "f%d\n", (int)f);
 	else
 		ps_printf(p, "/F%d %zu Tf\n",
 		    (int)f, p->ps->scale);
--- old/usr/src/cmd/mandoc/tree.c	Thu Aug  9 15:28:42 2018
+++ new/usr/src/cmd/mandoc/tree.c	Thu Aug  9 15:28:42 2018
@@ -1,7 +1,7 @@
-/*	$Id: tree.c,v 1.77 2017/07/08 14:51:05 schwarze Exp $ */
+/*	$Id: tree.c,v 1.78 2018/04/11 17:11:13 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2013,2014,2015,2017,2018 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
@@ -115,6 +115,9 @@
 	case ROFFT_TEXT:
 		t = "text";
 		break;
+	case ROFFT_COMMENT:
+		t = "comment";
+		break;
 	case ROFFT_TBL:
 		break;
 	case ROFFT_EQN:
@@ -126,6 +129,7 @@
 
 	switch (n->type) {
 	case ROFFT_TEXT:
+	case ROFFT_COMMENT:
 		p = n->string;
 		break;
 	case ROFFT_BODY:
@@ -231,6 +235,9 @@
 	case ROFFT_TEXT:
 		t = "text";
 		break;
+	case ROFFT_COMMENT:
+		t = "comment";
+		break;
 	case ROFFT_BLOCK:
 		t = "block";
 		break;
@@ -251,6 +258,7 @@
 
 	switch (n->type) {
 	case ROFFT_TEXT:
+	case ROFFT_COMMENT:
 		p = n->string;
 		break;
 	case ROFFT_ELEM:
--- old/usr/src/man/man1/mandoc.1	Thu Aug  9 15:28:42 2018
+++ new/usr/src/man/man1/mandoc.1	Thu Aug  9 15:28:42 2018
@@ -1,7 +1,7 @@
-.\"	$Id: mandoc.1,v 1.217 2017/07/20 15:26:41 schwarze Exp $
+.\"	$Id: mandoc.1,v 1.226 2018/07/28 18:34:15 schwarze Exp $
 .\"
 .\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
-.\" Copyright (c) 2012, 2014-2017 Ingo Schwarze <schwarze@openbsd.org>
+.\" Copyright (c) 2012, 2014-2018 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
@@ -15,7 +15,7 @@
 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd $Mdocdate: July 20 2017 $
+.Dd $Mdocdate: July 28 2018 $
 .Dt MANDOC 1
 .Os
 .Sh NAME
@@ -34,9 +34,7 @@
 .Sh DESCRIPTION
 The
 .Nm
-utility formats
-.Ux
-manual pages for display.
+utility formats manual pages for display.
 .Pp
 By default,
 .Nm
@@ -118,7 +116,7 @@
 all input files are interpreted as
 .Xr man 5 .
 By default, the input language is automatically detected for each file:
-if the the first macro is
+if the first macro is
 .Ic \&Dd
 or
 .Ic \&Dt ,
@@ -132,13 +130,32 @@
 is silently ignored.
 .It Fl O Ar options
 Comma-separated output options.
+See the descriptions of the individual output formats for supported
+.Ar options .
 .It Fl T Ar output
-Output format.
-See
-.Sx Output Formats
-for available formats.
-Defaults to
-.Fl T Cm locale .
+Select the output format.
+Supported values for the
+.Ar output
+argument are
+.Cm ascii ,
+.Cm html ,
+the default of
+.Cm locale ,
+.Cm man ,
+.Cm markdown ,
+.Cm pdf ,
+.Cm ps ,
+.Cm tree ,
+and
+.Cm utf8 .
+.Pp
+The special
+.Fl T Cm lint
+mode only parses the input and produces no output.
+It implies
+.Fl W Cm all
+and redirects parser messages, which usually appear on standard
+error output, to standard output.
 .It Fl W Ar level
 Specify the minimum message
 .Ar level
@@ -196,73 +213,20 @@
 are requested, they can be joined with a comma, for example
 .Fl W Cm error , Ns Cm stop .
 .It Ar file
-Read input from zero or more files.
-If unspecified, reads from stdin.
-If multiple files are specified,
+Read from the given input file.
+If multiple files are specified, they are processed in the given order.
+If unspecified,
 .Nm
-will halt with the first failed parse.
+reads from standard input.
 .El
-.Ss Output Formats
-The
-.Nm
-utility accepts the following
-.Fl T
-arguments, which correspond to output modes:
-.Bl -tag -width "-T markdown"
-.It Fl T Cm ascii
-Produce 7-bit ASCII output.
-See
-.Sx ASCII Output .
-.It Fl T Cm html
-Produce HTML5, CSS1, and MathML output.
-See
-.Sx HTML Output .
-.It Fl T Ns Cm lint
-Parse only: produce no output.
-Implies
-.Fl W Cm all
-and redirects parser messages, which usually appear
-on standard error output, to standard output.
-.It Fl T Cm locale
-Encode output using the current locale.
-This is the default.
-See
-.Sx Locale Output .
-.It Fl T Cm man
-Produce
-.Xr man 5
-format output.
-See
-.Sx Man Output .
-.It Fl T Cm markdown
-Produce output in
-.Sy markdown
-format.
-See
-.Sx Markdown Output .
-.It Fl T Cm pdf
-Produce PDF output.
-See
-.Sx PDF Output .
-.It Fl T Cm ps
-Produce PostScript output.
-See
-.Sx PostScript Output .
-.It Fl T Cm tree
-Produce an indented parse tree.
-.It Fl T Cm utf8
-Encode output in the UTF\-8 multi-byte format.
-See
-.Sx UTF\-8 Output .
-.El
-.Pp
-If multiple input files are specified, these will be processed by the
-corresponding filter in-order.
 .Ss ASCII Output
-Output produced by
+Use
 .Fl T Cm ascii
-is rendered in standard 7-bit ASCII documented in
-.Xr ascii 5 .
+to force text output in 7-bit ASCII character encoding documented in the
+.Xr ascii 5
+manual page, ignoring the
+.Xr locale 1
+set in the environment.
 .Pp
 Font styles are applied by using back-spaced encoding such that an
 underlined character
@@ -279,9 +243,6 @@
 .Xr mandoc_char 5
 are rendered best-effort in an ASCII equivalent.
 .Pp
-Output width is limited to 78 visible columns unless literal input lines
-exceed this limit.
-.Pp
 The following
 .Fl O
 arguments are accepted:
@@ -295,9 +256,30 @@
 .Xr man 5 .
 Increasing this is not recommended; it may result in degraded formatting,
 for example overfull lines or ugly line breaks.
+When output is to a pager on a terminal that is less than 66 columns
+wide, the default is reduced to three columns.
+.It Cm mdoc
+Format
+.Xr man 5
+input files in
+.Xr mdoc 5
+output style.
+Specifically, this suppresses the two additional blank lines near the
+top and the bottom of each page, and it implies
+.Fl O Cm indent Ns =5 .
+One useful application is for checking that
+.Fl T Cm man
+output formats in the same way as the
+.Xr mdoc 5
+source it was generated from.
 .It Cm width Ns = Ns Ar width
 The output width is set to
-.Ar width .
+.Ar width
+instead of the default of 78.
+When output is to a pager on a terminal that is less than 79 columns
+wide, the default is reduced to one less than the terminal width.
+In any case, lines that are output in literal mode are never wrapped
+and may exceed the output width.
 .El
 .Ss HTML Output
 Output produced by
@@ -318,7 +300,8 @@
 readable in any graphical or text-based web
 browser.
 .Pp
-Special characters are rendered in decimal-encoded UTF\-8.
+Non-ASCII characters are rendered
+as hexadecimal Unicode character references.
 .Pp
 The following
 .Fl O
@@ -368,11 +351,28 @@
 relative URI.
 .El
 .Ss Locale Output
-Locale-depending output encoding is triggered with
+By default,
+.Nm
+automatically selects UTF-8 or ASCII output according to the current
+.Xr locale 1 .
+If any of the environment variables
+.Ev LC_ALL ,
+.Ev LC_CTYPE ,
+or
+.Ev LANG
+are set and the first one that is set
+selects the UTF-8 character encoding, it produces
+.Sx UTF-8 Output ;
+otherwise, it falls back to
+.Sx ASCII Output .
+This output mode can also be selected explicitly with
 .Fl T Cm locale .
-This is the default.
 .Ss Man Output
-Translate input format into
+Use
+.Fl T Cm man
+to translate
+.Xr mdoc 5
+input into
 .Xr man 5
 output format.
 This is useful for distributing manual sources to legacy systems
@@ -380,11 +380,7 @@
 .Xr mdoc 5
 formatters.
 .Pp
-If
-.Xr mdoc 5
-is passed as input, it is translated into
-.Xr man 5 .
-If the input format is
+If the input format of a file is
 .Xr man 5 ,
 the input is copied to the output, expanding any
 .Xr mandoc_roff 5
@@ -396,11 +392,11 @@
 .Sx DIAGNOSTICS
 are displayed before copying the input to the output.
 .Ss Markdown Output
-Translate
+Use
+.Fl T Cm markdown
+to translate
 .Xr mdoc 5
-input to the
-.Sy markdown
-format conforming to
+input to the markdown format conforming to
 .Lk http://daringfireball.net/projects/markdown/syntax.text\
  "John Gruber's 2004 specification" .
 The output also almost conforms to the
@@ -471,13 +467,24 @@
 .Ar letter
 is used.
 .El
-.Ss UTF\-8 Output
+.Ss UTF-8 Output
 Use
 .Fl T Cm utf8
-to force a UTF\-8 locale.
+to force text output in UTF-8 multi-byte character encoding,
+ignoring the
+.Xr locale 1
+settings in the environment.
 See
-.Sx Locale Output
-for details and options.
+.Sx ASCII Output
+regarding font styles and
+.Fl O
+arguments.
+.Pp
+On operating systems lacking locale or wide character support, and
+on those where the internal character representation is not UCS-4,
+.Nm
+always falls back to
+.Sx ASCII Output .
 .Ss Syntax tree output
 Use
 .Fl T Cm tree
@@ -544,6 +551,16 @@
 the parser or by the validator.
 Meta data is not available in this case.
 .El
+.Sh ENVIRONMENT
+.Bl -tag -width Ev
+.It Ev LC_CTYPE
+The character encoding
+.Xr locale 1 .
+When
+.Sx Locale Output
+is selected, it decides whether to use ASCII or UTF-8 output format.
+It never affects the interpretation of input files.
+.El
 .Sh EXIT STATUS
 The
 .Nm
@@ -684,7 +701,7 @@
 .Cm style
 suggestion really justifies a change to the input file.
 .It Cm base
-A convertion used in the base system of a specific operating system
+A convention used in the base system of a specific operating system
 is not adhered to.
 These are not markup mistakes, and neither the quality of formatting
 nor portability are in danger.
@@ -792,6 +809,16 @@
 date format
 .Dq "Month dd, yyyy"
 instead.
+.It Sy "normalizing date format to" : No ...
+.Pq mdoc , man
+The
+.Ic \&Dd
+or
+.Ic \&TH
+macro provides an abbreviated month name or a day number with a
+leading zero.
+In the formatted output, the month name is written out in full
+and the leading zero is omitted.
 .It Sy "lower case character in document title"
 .Pq mdoc , man
 The title is still used as given in the
@@ -804,7 +831,7 @@
 the same operating system.
 Consider deleting the later instance and moving the first one up
 to the top of the page.
-.It Sy "typo in section name"
+.It Sy "possible typo in section name"
 .Pq mdoc
 Fuzzy string matching revealed that the argument of an
 .Ic \&Sh
@@ -881,6 +908,12 @@
 request occurs even though the document already switched to no-fill mode
 and did not switch back to fill mode yet.
 It has no effect.
+.It Sy "verbatim \(dq--\(dq, maybe consider using \e(em"
+.Pq mdoc
+Even though the ASCII output device renders an em-dash as
+.Qq \-\- ,
+that is not a good way to write it in an input file
+because it renders poorly on all other output devices.
 .It Sy "function name without markup"
 .Pq mdoc
 A word followed by an empty pair of parentheses occurs on a text line.
--- old/usr/src/man/man5/eqn.5	Thu Aug  9 15:28:43 2018
+++ new/usr/src/man/man5/eqn.5	Thu Aug  9 15:28:43 2018
@@ -1,4 +1,4 @@
-.\"	$Id: eqn.7,v 1.36 2017/07/20 11:07:27 schwarze Exp $
+.\"	$Id: eqn.7,v 1.37 2017/09/04 10:35:27 schwarze Exp $
 .\"
 .\" Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
 .\" Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -15,7 +15,7 @@
 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd $Mdocdate: July 20 2017 $
+.Dd $Mdocdate: September 4 2017 $
 .Dt EQN 5
 .Os
 .Sh NAME
@@ -83,7 +83,7 @@
         | \(dqsqrt\(dq box
         | box pos box
         | box mark
-        | \(dqmatrix\(dq \(dq{\(dq [col \(dq{\(dq list \(dq}\(dq ]*
+        | \(dqmatrix\(dq \(dq{\(dq [col \(dq{\(dq list \(dq}\(dq]* \(dq}\(dq
         | pile \(dq{\(dq list \(dq}\(dq
         | font box
         | \(dqsize\(dq text box
--- old/usr/src/man/man5/mandoc_char.5	Thu Aug  9 15:28:43 2018
+++ new/usr/src/man/man5/mandoc_char.5	Thu Aug  9 15:28:43 2018
@@ -1,4 +1,4 @@
-.\"	$Id: mandoc_char.7,v 1.67 2017/06/14 20:57:07 schwarze Exp $
+.\"	$Id: mandoc_char.7,v 1.72 2018/08/08 14:30:48 schwarze Exp $
 .\"
 .\" Copyright (c) 2003 Jason McIntyre <jmc@openbsd.org>
 .\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -16,7 +16,7 @@
 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd $Mdocdate: June 14 2017 $
+.Dd $Mdocdate: August 8 2018 $
 .Dt MANDOC_CHAR 5
 .Os
 .Sh NAME
@@ -35,13 +35,27 @@
 .Pp
 The rendering depends on the
 .Xr mandoc 1
-output mode; in ASCII output, most characters are completely
-unintelligible.
-For that reason, using any of the special characters documented here,
-except those discussed in the
+output mode; it can be inspected by calling
+.Xr man 1
+on the
+.Nm
+manual page with different
+.Fl T
+arguments.
+In ASCII output, the rendering of some characters may be hard
+to interpret for the reader.
+Many are rendered as descriptive strings like
+.Qq <integral> ,
+.Qq <degree> ,
+or
+.Qq <Gamma> ,
+which may look ugly, and many are replaced by similar ASCII characters.
+In particular, accented characters are usually shown without the accent.
+For that reason, try to avoid using any of the special characters
+documented here except those discussed in the
 .Sx DESCRIPTION ,
-is strongly discouraged; they are supported merely for backwards
-compatibility with existing documents.
+unless they are essential for explaining the subject matter at hand,
+for example when documenting complicated mathematical functions.
 .Pp
 In particular, in English manual pages, do not use special-character
 escape sequences to represent national language characters in author
@@ -48,10 +62,10 @@
 names; instead, provide ASCII transcriptions of the names.
 .Ss Dashes and Hyphens
 In typography there are different types of dashes of various width:
-the hyphen (-),
-the minus sign (\(mi),
+the hyphen (\(hy),
 the en-dash (\(en),
-and the em-dash (\(em).
+the em-dash (\(em),
+and the mathematical minus sign (\(mi).
 .Pp
 Hyphens are used for adjectives;
 to separate the two parts of a compound word;
@@ -62,6 +76,42 @@
 lorry-driver
 .Ed
 .Pp
+The en-dash is used to separate the two elements of a range,
+or can be used the same way as an em-dash.
+It should be written as
+.Sq \e(en :
+.Bd -unfilled -offset indent
+pp. 95\e(en97.
+Go away \e(en or else!
+.Ed
+.Pp
+The em-dash can be used to show an interruption
+or can be used the same way as colons, semi-colons, or parentheses.
+It should be written as
+.Sq \e(em :
+.Bd -unfilled -offset indent
+Three things \e(em apples, oranges, and bananas.
+This is not that \e(em rather, this is that.
+.Ed
+.Pp
+In
+.Xr mandoc_roff 5
+documents, the minus sign is normally written as
+.Sq \e- .
+In manual pages, some style guides recommend to also use
+.Sq \e-
+if an ASCII 0x2d
+.Dq hyphen-minus
+output glyph that can be copied and pasted is desired in output modes
+supporting it, for example in
+.Fl T Cm utf8
+and
+.Fl T Cm html .
+But currently, no practically relevant manual page formatter actually
+requires that subtlety, so in manual pages just write plain
+.Sq -
+to represent hyphen, minus, and hyphen-minus.
+.Pp
 If a word on a text input line contains a hyphen, a formatter may decide
 to insert an output line break after the hyphen if that helps filling
 the current output line, but the whole word would overflow the line.
@@ -85,37 +135,6 @@
 .Xr mandoc 1 ,
 which only breaks the line at whitespace, and inside words only
 after existing hyphens.
-.Pp
-The mathematical minus sign is used for negative numbers or subtraction.
-It should be written as
-.Sq \e(mi :
-.Bd -unfilled -offset indent
-a = 3 \e(mi 1;
-b = \e(mi2;
-.Ed
-.Pp
-The en-dash is used to separate the two elements of a range,
-or can be used the same way as an em-dash.
-It should be written as
-.Sq \e(en :
-.Bd -unfilled -offset indent
-pp. 95\e(en97.
-Go away \e(en or else!
-.Ed
-.Pp
-The em-dash can be used to show an interruption
-or can be used the same way as colons, semi-colons, or parentheses.
-It should be written as
-.Sq \e(em :
-.Bd -unfilled -offset indent
-Three things \e(em apples, oranges, and bananas.
-This is not that \e(em rather, this is that.
-.Ed
-.Pp
-Note:
-hyphens, minus signs, and en-dashes look identical under normal ASCII output.
-Other formats, such as PostScript, render them correctly,
-with differing widths.
 .Ss Spaces
 To separate words in normal text, for indenting and alignment
 in literal context, and when none of the following special cases apply,
@@ -319,8 +338,8 @@
 .It \e(rq    Ta \(rq        Ta right double-quote
 .It \e(oq    Ta \(oq        Ta left single-quote
 .It \e(cq    Ta \(cq        Ta right single-quote
-.It \e(aq    Ta \(aq        Ta apostrophe quote (text)
-.It \e(dq    Ta \(dq        Ta double quote (text)
+.It \e(aq    Ta \(aq        Ta apostrophe quote (ASCII character)
+.It \e(dq    Ta \(dq        Ta double quote (ASCII character)
 .It \e(Fo    Ta \(Fo        Ta left guillemet
 .It \e(Fc    Ta \(Fc        Ta right guillemet
 .It \e(fo    Ta \(fo        Ta left single guillemet
@@ -336,7 +355,7 @@
 .It \e(rC    Ta \(rC        Ta right brace
 .It \e(la    Ta \(la        Ta left angle
 .It \e(ra    Ta \(ra        Ta right angle
-.It \e(bv    Ta \(bv        Ta brace extension
+.It \e(bv    Ta \(bv        Ta brace extension (special font)
 .It \e[braceex] Ta \[braceex] Ta brace extension
 .It \e[bracketlefttp] Ta \[bracketlefttp] Ta top-left hooked bracket
 .It \e[bracketleftbt] Ta \[bracketleftbt] Ta bottom-left hooked bracket
@@ -389,8 +408,8 @@
 .It Em Input Ta Em Rendered Ta Em Description
 .It \e(AN    Ta \(AN        Ta logical and
 .It \e(OR    Ta \(OR        Ta logical or
-.It \e(no    Ta \(no        Ta logical not
-.It \e[tno]  Ta \[tno]      Ta logical not (text)
+.It \e[tno]  Ta \[tno]      Ta logical not (text font)
+.It \e(no    Ta \(no        Ta logical not (special font)
 .It \e(te    Ta \(te        Ta existential quantifier
 .It \e(fa    Ta \(fa        Ta universal quantifier
 .It \e(st    Ta \(st        Ta such that
@@ -402,19 +421,20 @@
 Mathematical:
 .Bl -column "xxcoproductxx" "Rendered" "Description" -offset indent -compact
 .It Em Input Ta Em Rendered Ta Em Description
-.It \e(pl    Ta \(pl        Ta plus
-.It \e(mi    Ta \(mi        Ta minus
-.It \e-      Ta \-          Ta minus (text)
+.It \e-      Ta \-          Ta minus (text font)
+.It \e(mi    Ta \(mi        Ta minus (special font)
+.It +        Ta +           Ta plus (text font)
+.It \e(pl    Ta \(pl        Ta plus (special font)
 .It \e(-+    Ta \(-+        Ta minus-plus
-.It \e(+-    Ta \(+-        Ta plus-minus
-.It \e[t+-]  Ta \[t+-]      Ta plus-minus (text)
+.It \e[t+-]  Ta \[t+-]      Ta plus-minus (text font)
+.It \e(+-    Ta \(+-        Ta plus-minus (special font)
 .It \e(pc    Ta \(pc        Ta center-dot
-.It \e(mu    Ta \(mu        Ta multiply
-.It \e[tmu]  Ta \[tmu]      Ta multiply (text)
+.It \e[tmu]  Ta \[tmu]      Ta multiply (text font)
+.It \e(mu    Ta \(mu        Ta multiply (special font)
 .It \e(c*    Ta \(c*        Ta circle-multiply
 .It \e(c+    Ta \(c+        Ta circle-plus
-.It \e(di    Ta \(di        Ta divide
-.It \e[tdi]  Ta \[tdi]      Ta divide (text)
+.It \e[tdi]  Ta \[tdi]      Ta divide (text font)
+.It \e(di    Ta \(di        Ta divide (special font)
 .It \e(f/    Ta \(f/        Ta fraction
 .It \e(**    Ta \(**        Ta asterisk
 .It \e(<=    Ta \(<=        Ta less-than-equal
@@ -511,8 +531,8 @@
 .It \e(ao    Ta \(ao        Ta ring
 .It \e(a\(ti Ta \(a~        Ta tilde
 .It \e(ho    Ta \(ho        Ta ogonek
-.It \e(ha    Ta \(ha        Ta hat (text)
-.It \e(ti    Ta \(ti        Ta tilde (text)
+.It \e(ha    Ta \(ha        Ta hat (ASCII character)
+.It \e(ti    Ta \(ti        Ta tilde (ASCII character)
 .El
 .Pp
 Accented letters:
--- old/usr/src/man/man5/mandoc_roff.5	Thu Aug  9 15:28:44 2018
+++ new/usr/src/man/man5/mandoc_roff.5	Thu Aug  9 15:28:44 2018
@@ -1,7 +1,7 @@
-.\"	$Id: roff.7,v 1.94 2017/07/05 12:25:17 schwarze Exp $
+.\"	$Id: roff.7,v 1.96 2018/04/10 00:52:30 schwarze Exp $
 .\"
 .\" Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
-.\" Copyright (c) 2010,2011,2013-2015,2017 Ingo Schwarze <schwarze@openbsd.org>
+.\" Copyright (c) 2010-2018 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
@@ -15,7 +15,7 @@
 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd $Mdocdate: July 5 2017 $
+.Dd $Mdocdate: April 10 2018 $
 .Dt ROFF 5
 .Os
 .Sh NAME
@@ -1348,7 +1348,7 @@
 .It Ic \&nop Ar body
 Execute the rest of the input line as a request or macro line.
 Currently unsupported.
-.It Ic \&nr Ar register Oo Cm + Ns | Ns Cm - Oc Ns Ar expression
+.It Ic \&nr Ar register Oo Cm + Ns | Ns Cm - Oc Ns Ar expression Op Ar stepsize
 Define or change a register.
 A register is an arbitrary string value that defines some sort of state,
 which influences parsing and/or formatting.
@@ -1360,6 +1360,14 @@
 If it is prefixed by a sign, the register will be
 incremented or decremented instead of assigned to.
 .Pp
+The
+.Ar stepsize
+is used by the
+.Ic \en+
+auto-increment feature.
+It remains unchanged when omitted while changing an existing register,
+and it defaults to 0 when defining a new register.
+.Pp
 The following
 .Ar register
 is handled specially:
@@ -1471,7 +1479,7 @@
 .It Ic \&rchar Ar glyph ...
 Remove glyph definitions.
 Currently unsupported.
-.It Ic \&rd Op Ar prompt Op Ar agument ...
+.It Ic \&rd Op Ar prompt Op Ar argument ...
 Read from standard input.
 Currently ignored.
 .It Ic \&recursionlimit Ar maxrec maxtail
@@ -1996,7 +2004,7 @@
 Character
 .Ar number
 on the current font.
-.Ss \en Ns Bq Ar name
+.Ss \en Ns Oo +|- Oc Ns Bq Ar name
 Interpolate the number register
 .Ar name .
 For short names, there are variants
@@ -2003,6 +2011,12 @@
 .No \en Ns Ar c
 and
 .No \en( Ns Ar cc .
+If the optional sign is specified,
+the register is first incremented or decremented by the
+.Ar stepsize
+that was specified in the relevant
+.Ic \&nr
+request, and the changed value is interpolated.
 .Ss \eo\(aq Ns Ar string Ns \(aq
 Overstrike, writing all the characters contained in the
 .Ar string
--- old/usr/src/man/man5/mdoc.5	Thu Aug  9 15:28:44 2018
+++ new/usr/src/man/man5/mdoc.5	Thu Aug  9 15:28:44 2018
@@ -1,7 +1,7 @@
-.\"	$Id: mdoc.7,v 1.269 2017/07/20 16:24:53 schwarze Exp $
+.\"	$Id: mdoc.7,v 1.271 2018/07/28 18:34:15 schwarze Exp $
 .\"
 .\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
-.\" Copyright (c) 2010, 2011, 2013-2017 Ingo Schwarze <schwarze@openbsd.org>
+.\" Copyright (c) 2010, 2011, 2013-2018 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
@@ -17,9 +17,9 @@
 .\"
 .\"
 .\" Copyright 2014 Garrett D'Amore <garrett@damore.org>
-.\" Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
+.\" Copyright 2018 Nexenta Systems, Inc.
 .\"
-.Dd $Mdocdate: July 20 2017 $
+.Dd $Mdocdate: July 28 2018 $
 .Dt MDOC 5
 .Os
 .Sh NAME
@@ -799,12 +799,10 @@
 .Ss \&Ao
 Begin a block enclosed by angle brackets.
 Does not have any head arguments.
-.Pp
-Examples:
-.Dl \&.Fl -key= \&Ns \&Ao \&Ar val \&Ac
-.Pp
-See also
-.Sx \&Aq .
+This macro is almost never useful.
+See
+.Sx \&Aq
+for more details.
 .Ss \&Ap
 Inserts an apostrophe without any surrounding whitespace.
 This is generally used as a grammatical device when referring to the verb
@@ -814,19 +812,45 @@
 .Dl \&.Fn execve \&Ap d
 .Ss \&Aq
 Encloses its arguments in angle brackets.
+The only important use case is for email addresses.
+See
+.Sx \&Mt
+for an example.
 .Pp
-Examples:
-.Dl \&.Fl -key= \&Ns \&Aq \&Ar val
+Occasionally, it is used for names of characters and keys, for example:
+.Bd -literal -offset indent
+Press the
+\&.Aq escape
+key to ...
+.Ed
 .Pp
-.Em Remarks :
-this macro is often abused for rendering URIs, which should instead use
+For URIs, use
 .Sx \&Lk
+instead, and
+.Sx \&In
+for
+.Dq #include
+directives.
+Never wrap
+.Sx \&Ar
+in
+.Sx \&Aq .
+.Pp
+Since
+.Sx \&Aq
+usually renders with non-ASCII characters in non-ASCII output modes,
+do not use it where the ASCII characters
+.Sq <
+and
+.Sq >
+are required as syntax elements.
+Instead, use these characters directly in such cases, combining them
+with the macros
+.Sx \&Pf ,
+.Sx \&Ns ,
 or
-.Sx \&Mt ,
-or to note pre-processor
-.Dq Li #include
-statements, which should use
-.Sx \&In .
+.Sx \&Eo
+as needed.
 .Pp
 See also
 .Sx \&Ao .
@@ -1335,7 +1359,7 @@
 .Ar month
 is the full English month name, the
 .Ar day
-is an optionally zero-padded numeral, and the
+is an integer number, and the
 .Ar year
 is the full four-digit year.
 .Pp
@@ -1365,8 +1389,8 @@
 .Pp
 Examples:
 .Dl \&.Dd $\&Mdocdate$
-.Dl \&.Dd $\&Mdocdate: July 21 2007$
-.Dl \&.Dd July 21, 2007
+.Dl \&.Dd $\&Mdocdate: July 2 2018$
+.Dl \&.Dd July 2, 2018
 .Pp
 See also
 .Sx \&Dt
--- old/usr/src/man/man5/tbl.5	Thu Aug  9 15:28:45 2018
+++ new/usr/src/man/man5/tbl.5	Thu Aug  9 15:28:45 2018
@@ -1,4 +1,4 @@
-.\"	$Id: tbl.7,v 1.28 2017/06/28 00:59:57 schwarze Exp $
+.\"	$Id: tbl.7,v 1.29 2017/10/17 23:19:12 schwarze Exp $
 .\"
 .\" Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
 .\" Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@@ -15,7 +15,7 @@
 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd $Mdocdate: June 28 2017 $
+.Dd $Mdocdate: October 17 2017 $
 .Dt TBL 5
 .Os
 .Sh NAME
@@ -420,7 +420,9 @@
 in 1990 by James Clark.
 A standalone tbl implementation was written by Kristaps Dzonsons in
 2010.
-This formed the basis of the implementation that is part of the
+This formed the basis of the implementation that first appeared in
+.Ox 4.9
+as a part of the
 .Xr mandoc 1
 utility.
 .Sh AUTHORS
--- old/usr/src/tools/scripts/webrev.sh	Thu Aug  9 15:28:46 2018
+++ new/usr/src/tools/scripts/webrev.sh	Thu Aug  9 15:28:46 2018
@@ -148,119 +148,261 @@
 '
 
 # CSS for the HTML version of the man pages.
-# Current version is from mandoc 1.14.2.
+# Current version is from mandoc 1.14.4.
 MANCSS='
-html { max-width: 100ex; }
-body { font-family: Helvetica,Arial,sans-serif; }
-table { margin-top: 0em; margin-bottom: 0em; }
-td { vertical-align: top; }
-ul, ol, dl { margin-top: 0em; margin-bottom: 0em; }
-li, dt { margin-top: 1em; }
-a.selflink { border-bottom: thin dotted; color: inherit; font: inherit;
-    text-decoration: inherit; }
-fieldset { border: thin solid silver; border-radius: 1em; text-align: center; }
-input[name=expr] { width: 25%; }
-table.results { margin-top: 1em; margin-left: 2em; font-size: smaller; }
-table.head { width: 100%; border-bottom: 1px dotted #808080; margin-bottom: 1em;
-    font-size: smaller; }
-td.head-vol { text-align: center; }
-td.head-rtitle { text-align: right; }
-span.Nd { }
-table.foot { width: 100%; border-top: 1px dotted #808080; margin-top: 1em;
-    font-size: smaller; }
-td.foot-os { text-align: right; }
-div.manual-text { margin-left: 5ex; }
-h1.Sh { margin-top: 2ex; margin-bottom: 1ex; margin-left: -4ex;
-    font-size: 110%; }
-h2.Ss { margin-top: 2ex; margin-bottom: 1ex; margin-left: -2ex;
-    font-size: 105%; }
-div.Pp { margin: 1ex 0ex; }
-a.Sx { }
-a.Xr { }
-div.Bd { }
-div.D1 { margin-left: 5ex; }
-ul.Bl-bullet { list-style-type: disc; padding-left: 1em; }
-li.It-bullet { }
-ul.Bl-dash { list-style-type: none; padding-left: 0em; }
-li.It-dash:before { content: "\2014  "; }
-ul.Bl-item { list-style-type: none; padding-left: 0em; }
-li.It-item { }
-ul.Bl-compact > li { margin-top: 0ex; }
-ol.Bl-enum { padding-left: 2em; }
-li.It-enum { }
-ol.Bl-compact > li { margin-top: 0ex; }
-dl.Bl-diag { }
-dt.It-diag { }
-dd.It-diag { margin-left: 0ex; }
-b.It-diag { font-style: normal; }
-dl.Bl-hang { }
-dt.It-hang { }
-dd.It-hang { margin-left: 10.2ex; }
-dl.Bl-inset { }
-dt.It-inset { }
-dd.It-inset { margin-left: 0ex; }
-dl.Bl-ohang { }
-dt.It-ohang { }
-dd.It-ohang { margin-left: 0ex; }
-dl.Bl-tag { margin-left: 10.2ex; }
-dt.It-tag { float: left; margin-top: 0ex; margin-left: -10.2ex;
-    padding-right: 2ex; vertical-align: top; }
-dd.It-tag { clear: right; width: 100%; margin-top: 0ex; margin-left: 0ex;
-    vertical-align: top; overflow: auto; }
-dl.Bl-compact > dt { margin-top: 0ex; }
-table.Bl-column { }
-tr.It-column { }
-td.It-column { margin-top: 1em; }
-table.Bl-compact > tbody > tr > td { margin-top: 0ex; }
-cite.Rs { font-style: normal; font-weight: normal; }
-span.RsA { }
-i.RsB { font-weight: normal; }
-span.RsC { }
-span.RsD { }
-i.RsI { font-weight: normal; }
-i.RsJ { font-weight: normal; }
-span.RsN { }
-span.RsO { }
-span.RsP { }
-span.RsQ { }
-span.RsR { }
-span.RsT { text-decoration: underline; }
-a.RsU { }
-span.RsV { }
-span.eqn { }
-table.tbl { }
+/* $Id: mandoc.css,v 1.36 2018/07/23 22:51:26 schwarze Exp $ */
+/*
+ * Standard style sheet for mandoc(1) -Thtml and man.cgi(8).
+ */
+
+/* Global defaults. */
+
+html {		max-width: 65em; }
+body {		font-family: Helvetica,Arial,sans-serif; }
+table {		margin-top: 0em;
+		margin-bottom: 0em; }
+td {		vertical-align: top; }
+ul, ol, dl {	margin-top: 0em;
+		margin-bottom: 0em; }
+li, dt {	margin-top: 1em; }
+
+.permalink {	border-bottom: thin dotted;
+		color: inherit;
+		font: inherit;
+		text-decoration: inherit; }
+* {		clear: both }
+
+/* Search form and search results. */
+
+fieldset {	border: thin solid silver;
+		border-radius: 1em;
+		text-align: center; }
+input[name=expr] {
+		width: 25%; }
+
+table.results {	margin-top: 1em;
+		margin-left: 2em;
+		font-size: smaller; }
+
+/* Header and footer lines. */
+
+table.head {	width: 100%;
+		border-bottom: 1px dotted #808080;
+		margin-bottom: 1em;
+		font-size: smaller; }
+td.head-vol {	text-align: center; }
+td.head-rtitle {
+		text-align: right; }
+
+table.foot {	width: 100%;
+		border-top: 1px dotted #808080;
+		margin-top: 1em;
+		font-size: smaller; }
+td.foot-os {	text-align: right; }
+
+/* Sections and paragraphs. */
+
+.manual-text {
+		margin-left: 3.8em; }
+.Nd {		display: inline; }
+.Sh {		margin-top: 1.2em;
+		margin-bottom: 0.6em;
+		margin-left: -3.2em;
+		font-size: 110%; }
+.Ss {		margin-top: 1.2em;
+		margin-bottom: 0.6em;
+		margin-left: -1.2em;
+		font-size: 105%; }
+.Pp {		margin: 0.6em 0em; }
+.Sx { }
+.Xr { }
+
+/* Displays and lists. */
+
+.Bd { }
+.Bd-indent {	margin-left: 3.8em; }
+
+.Bl-bullet {	list-style-type: disc;
+		padding-left: 1em; }
+.Bl-bullet > li { }
+.Bl-dash {	list-style-type: none;
+		padding-left: 0em; }
+.Bl-dash > li:before {
+		content: "\2014  "; }
+.Bl-item {	list-style-type: none;
+		padding-left: 0em; }
+.Bl-item > li { }
+.Bl-compact > li {
+		margin-top: 0em; }
+
+.Bl-enum {	padding-left: 2em; }
+.Bl-enum > li { }
+.Bl-compact > li {
+		margin-top: 0em; }
+
+.Bl-diag { }
+.Bl-diag > dt {
+		font-style: normal;
+		font-weight: bold; }
+.Bl-diag > dd {
+		margin-left: 0em; }
+.Bl-hang { }
+.Bl-hang > dt { }
+.Bl-hang > dd {
+		margin-left: 5.5em; }
+.Bl-inset { }
+.Bl-inset > dt { }
+.Bl-inset > dd {
+		margin-left: 0em; }
+.Bl-ohang { }
+.Bl-ohang > dt { }
+.Bl-ohang > dd {
+		margin-left: 0em; }
+.Bl-tag {	margin-left: 5.5em; }
+.Bl-tag > dt {
+		float: left;
+		margin-top: 0em;
+		margin-left: -5.5em;
+		padding-right: 1.2em;
+		vertical-align: top; }
+.Bl-tag > dd {
+		clear: right;
+		width: 100%;
+		margin-top: 0em;
+		margin-left: 0em;
+		vertical-align: top;
+		overflow: auto; }
+.Bl-compact > dt {
+		margin-top: 0em; }
+
+.Bl-column { }
+.Bl-column > tbody > tr { }
+.Bl-column > tbody > tr > td {
+		margin-top: 1em; }
+.Bl-compact > tbody > tr > td {
+		margin-top: 0em; }
+
+.Rs {		font-style: normal;
+		font-weight: normal; }
+.RsA { }
+.RsB {		font-style: italic;
+		font-weight: normal; }
+.RsC { }
+.RsD { }
+.RsI {		font-style: italic;
+		font-weight: normal; }
+.RsJ {		font-style: italic;
+		font-weight: normal; }
+.RsN { }
+.RsO { }
+.RsP { }
+.RsQ { }
+.RsR { }
+.RsT {		text-decoration: underline; }
+.RsU { }
+.RsV { }
+
+.eqn { }
+.tbl { }
+
+.HP {		margin-left: 3.8em;
+		text-indent: -3.8em; }
+
+/* Semantic markup for command line utilities. */
+
 table.Nm { }
-b.Nm { font-style: normal; }
-b.Fl { font-style: normal; }
-b.Cm { font-style: normal; }
-var.Ar { font-style: italic; font-weight: normal; }
-span.Op { }
-b.Ic { font-style: normal; }
-code.Ev { font-style: normal; font-weight: normal; font-family: monospace; }
-i.Pa { font-weight: normal; }
-span.Lb { }
-b.In { font-style: normal; }
+code.Nm {	font-style: normal;
+		font-weight: bold;
+		font-family: inherit; }
+.Fl {		font-style: normal;
+		font-weight: bold;
+		font-family: inherit; }
+.Cm {		font-style: normal;
+		font-weight: bold;
+		font-family: inherit; }
+.Ar {		font-style: italic;
+		font-weight: normal; }
+.Op {		display: inline; }
+.Ic {		font-style: normal;
+		font-weight: bold;
+		font-family: inherit; }
+.Ev {		font-style: normal;
+		font-weight: normal;
+		font-family: monospace; }
+.Pa {		font-style: italic;
+		font-weight: normal; }
+
+/* Semantic markup for function libraries. */
+
+.Lb { }
+code.In {	font-style: normal;
+		font-weight: bold;
+		font-family: inherit; }
 a.In { }
-b.Fd { font-style: normal; }
-var.Ft { font-style: italic; font-weight: normal; }
-b.Fn { font-style: normal; }
-var.Fa { font-style: italic; font-weight: normal; }
-var.Vt { font-style: italic; font-weight: normal; }
-var.Va { font-style: italic; font-weight: normal; }
-code.Dv { font-style: normal; font-weight: normal; font-family: monospace; }
-code.Er { font-style: normal; font-weight: normal; font-family: monospace; }
-span.An { }
-a.Lk { }
-a.Mt { }
-b.Cd { font-style: normal; }
-i.Ad { font-weight: normal; }
-b.Ms { font-style: normal; }
-span.St { }
-a.Ux { }
-.No { font-style: normal; font-weight: normal; }
-.Em { font-style: italic; font-weight: normal; }
-.Sy { font-style: normal; font-weight: bold; }
-.Li { font-style: normal; font-weight: normal; font-family: monospace; }
+.Fd {		font-style: normal;
+		font-weight: bold;
+		font-family: inherit; }
+.Ft {		font-style: italic;
+		font-weight: normal; }
+.Fn {		font-style: normal;
+		font-weight: bold;
+		font-family: inherit; }
+.Fa {		font-style: italic;
+		font-weight: normal; }
+.Vt {		font-style: italic;
+		font-weight: normal; }
+.Va {		font-style: italic;
+		font-weight: normal; }
+.Dv {		font-style: normal;
+		font-weight: normal;
+		font-family: monospace; }
+.Er {		font-style: normal;
+		font-weight: normal;
+		font-family: monospace; }
+
+/* Various semantic markup. */
+
+.An { }
+.Lk { }
+.Mt { }
+.Cd {		font-style: normal;
+		font-weight: bold;
+		font-family: inherit; }
+.Ad {		font-style: italic;
+		font-weight: normal; }
+.Ms {		font-style: normal;
+		font-weight: bold; }
+.St { }
+.Ux { }
+
+/* Physical markup. */
+
+.Bf {		display: inline; }
+.No {		font-style: normal;
+		font-weight: normal; }
+.Em {		font-style: italic;
+		font-weight: normal; }
+.Sy {		font-style: normal;
+		font-weight: bold; }
+.Li {		font-style: normal;
+		font-weight: normal;
+		font-family: monospace; }
+
+/* Overrides to avoid excessive margins on small devices. */
+
+@media (max-width: 37.5em) {
+.manual-text {
+		margin-left: 0.5em; }
+.Sh, .Ss {	margin-left: 0em; }
+.Bd-indent {	margin-left: 2em; }
+.Bl-hang > dd {
+		margin-left: 2em; }
+.Bl-tag {	margin-left: 2em; }
+.Bl-tag > dt {
+		margin-left: -2em; }
+.HP {		margin-left: 2em;
+		text-indent: -2em; }
+}
 '
 
 #
