Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 14 Jul 2025 16:47:21 GMT
From:      Alexander Ziaee <ziaee@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: a271d8fd33b5 - stable/14 - mandoc: Vendor import of upstream at 2025-04-08
Message-ID:  <202507141647.56EGlLwA065346@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch stable/14 has been updated by ziaee:

URL: https://cgit.FreeBSD.org/src/commit/?id=a271d8fd33b5356a06b0d18b16a7a1eb9d5af980

commit a271d8fd33b5356a06b0d18b16a7a1eb9d5af980
Author:     Alexander Ziaee <ziaee@FreeBSD.org>
AuthorDate: 2025-06-12 21:25:42 +0000
Commit:     Alexander Ziaee <ziaee@FreeBSD.org>
CommitDate: 2025-07-14 16:44:45 +0000

    mandoc: Vendor import of upstream at 2025-04-08
    
    Interesting changes:
    + correct legacy mandoc date typo, reported on our very own bugzilla
    + improve libmandoc manual
    + strengthen recommendations to omit macros from title lines in mdoc(7)
    + improve html5 compliance in html output
    + improve RFC linking in markdown output
    + libmandoc and mdoc manuals have been improved
    + support arithmetic operations in tbl(7) column widths for DocBook
    + define the St -isoC-2023 macro for referencing the C23 spec
    
    Approved by:    mhorne (mentor, implicit)
    Reviewed by:    imp
    Discussed with: adrian, bapt, brooks
    Closes:         https://github.com/freebsd/freebsd-src/pull/1689
    
    (cherry picked from commit 80c12959679ab203459dc20eb9ece3a7328b7de5)
---
 contrib/mandoc/TODO            |  11 +++-
 contrib/mandoc/libmandoc.h     |   3 +-
 contrib/mandoc/man.1           |  38 ++++++++++-
 contrib/mandoc/mandoc.1        |  14 ++--
 contrib/mandoc/mandoc.3        |  37 ++++++++++-
 contrib/mandoc/mandoc.css      |   5 +-
 contrib/mandoc/mandoc.h        |   5 +-
 contrib/mandoc/mandoc_msg.c    |   3 +-
 contrib/mandoc/mdoc.7          |  36 +++++-----
 contrib/mandoc/mdoc_html.c     |  61 ++++++++++++-----
 contrib/mandoc/mdoc_man.c      |   7 +-
 contrib/mandoc/mdoc_markdown.c |  35 +++++++++-
 contrib/mandoc/out.c           |  10 +--
 contrib/mandoc/roff.c          | 146 +++++++++++++++++++++--------------------
 contrib/mandoc/st.c            |   2 +-
 contrib/mandoc/tbl.c           |   3 +-
 contrib/mandoc/tbl.h           |   3 +-
 contrib/mandoc/tbl_layout.c    |  36 +++++-----
 18 files changed, 304 insertions(+), 151 deletions(-)

diff --git a/contrib/mandoc/TODO b/contrib/mandoc/TODO
index 58d0d6937746..3f5a449af68f 100644
--- a/contrib/mandoc/TODO
+++ b/contrib/mandoc/TODO
@@ -1,6 +1,6 @@
 ************************************************************************
 * Official mandoc TODO.
-* $Id: TODO,v 1.335 2024/09/21 12:08:54 schwarze Exp $
+* $Id: TODO,v 1.337 2025/04/08 21:53:14 schwarze Exp $
 ************************************************************************
 
 Many issues are annotated for difficulty as follows:
@@ -234,6 +234,11 @@ are mere guesses, and some may be wrong.
 
 --- missing man features -----------------------------------------------
 
+- When calling less(1), specify -P to print "name(sec) lines ..."
+  in the bottom line instead of "/tmp/man..."
+  Jan Engelhardt (SuSE) via Matej Cepl 06 Apr 2025 14:42:52 +0200
+  loc *  exist *  algo *  size *  imp **
+
 - MANWIDTH
   Markus Waldeck <waldeck at gmx dot de> 9 Jun 2015 05:49:56 +0200
   Laura Morales <lauretas at mail dot com> 26 Apr 2018 08:15:55 +0200
@@ -483,6 +488,10 @@ are mere guesses, and some may be wrong.
   reveals lots of bugs both in groff and mandoc...
   reported by bentley@  Wed, 22 May 2013 23:49:30 -0600
 
+- Make an underlined blank an underscore rather than a blank in both
+  groff and mandoc terminal output (likely tricky, needs investigation)
+  job@  21 Jan 2025 18:03:52 +0000
+
 --- PostScript and PDF issues ------------------------------------------
 
 - PDF output doesn't use a monospaced font for .Bd -literal
diff --git a/contrib/mandoc/libmandoc.h b/contrib/mandoc/libmandoc.h
index ab7c29be510f..76183423603d 100644
--- a/contrib/mandoc/libmandoc.h
+++ b/contrib/mandoc/libmandoc.h
@@ -1,4 +1,4 @@
-/* $Id: libmandoc.h,v 1.80 2021/06/27 17:57:54 schwarze Exp $ */
+/* $Id: libmandoc.h,v 1.81 2025/01/05 16:58:22 schwarze Exp $ */
 /*
  * Copyright (c) 2013-2015,2017,2018,2020 Ingo Schwarze <schwarze@openbsd.org>
  * Copyright (c) 2009, 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -78,6 +78,7 @@ void		 roff_userret(struct roff *);
 void		 roff_endparse(struct roff *);
 void		 roff_setreg(struct roff *, const char *, int, char);
 int		 roff_getreg(struct roff *, const char *);
+int		 roff_evalnum(int, const char *, int *, int *, char, int);
 char		*roff_strdup(const struct roff *, const char *);
 char		*roff_getarg(struct roff *, char **, int, int *);
 int		 roff_getcontrol(const struct roff *,
diff --git a/contrib/mandoc/man.1 b/contrib/mandoc/man.1
index 888cabb4502b..b37d410e9130 100644
--- a/contrib/mandoc/man.1
+++ b/contrib/mandoc/man.1
@@ -1,4 +1,4 @@
-.\"	$Id: man.1,v 1.41 2022/08/04 11:32:23 schwarze Exp $
+.\" $Id: man.1,v 1.42 2025/01/26 14:43:25 schwarze Exp $
 .\"
 .\" Copyright (c) 1989, 1990, 1993
 .\"	The Regents of the University of California.  All rights reserved.
@@ -31,7 +31,7 @@
 .\"
 .\"     @(#)man.1	8.2 (Berkeley) 1/2/94
 .\"
-.Dd $Mdocdate: August 4 2022 $
+.Dd $Mdocdate: January 26 2025 $
 .Dt MAN 1
 .Os
 .Sh NAME
@@ -58,7 +58,19 @@ a specific category
 .Pq Ar section
 or
 machine architecture
-.Pq Ar subsection .
+.Pq Ar subsection ,
+or searched for with
+.Fl k
+using
+.Xr apropos 1
+search expressions.
+The default pager,
+.Xr less 1 ,
+supports the command
+.Ic :t
+to jump to definitions of specific terms (see
+.Dv MANPAGER ,
+below).
 .Pp
 The options are as follows:
 .Bl -tag -width Ds
@@ -345,6 +357,26 @@ See
 .Xr mandoc 1
 for details.
 .Sh EXAMPLES
+Show all manual pages that mention the
+.Ev PWD
+environment variable:
+.Pp
+.Dl $ man -ak Ev=PWD
+.Pp
+Show the
+.Xr ksh 1
+manual and jump to the place where the
+.Ic pwd
+builtin command is described:
+.Pp
+.Dl $ man -O tag=pwd ksh
+.Pp
+Equivalently, use the command
+.Ql man ksh ,
+then type
+.Ql :tpwd
+and press the return key.
+.Pp
 Format a page for pasting extracts into an email message \(em
 avoid printing any UTF-8 characters, reduce the width to ease
 quoting in replies, and remove markup:
diff --git a/contrib/mandoc/mandoc.1 b/contrib/mandoc/mandoc.1
index b1e0cf118336..32a3e2811513 100644
--- a/contrib/mandoc/mandoc.1
+++ b/contrib/mandoc/mandoc.1
@@ -1,6 +1,6 @@
-.\" $Id: mandoc.1,v 1.267 2023/11/13 19:13:01 schwarze Exp $
+.\" $Id: mandoc.1,v 1.270 2025/03/03 14:07:51 schwarze Exp $
 .\"
-.\" Copyright (c) 2012, 2014-2023 Ingo Schwarze <schwarze@openbsd.org>
+.\" Copyright (c) 2012, 2014-2023, 2025 Ingo Schwarze <schwarze@openbsd.org>
 .\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
 .\"
 .\" Permission to use, copy, modify, and distribute this software for any
@@ -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: November 13 2023 $
+.Dd $Mdocdate: March 3 2025 $
 .Dt MANDOC 1
 .Os
 .Sh NAME
@@ -954,7 +954,7 @@ The
 macro uses the legacy
 .Xr man 7
 date format
-.Dq yyyy-dd-mm .
+.Dq yyyy-mm-dd .
 Consider using the conventional
 .Xr mdoc 7
 date format
@@ -1896,6 +1896,12 @@ The invalid character is discarded.
 A table layout specification contains an opening parenthesis,
 but no matching closing parenthesis.
 The rest of the input line, starting from the parenthesis, has no effect.
+.It Sy "ignoring invalid column width in tbl layout"
+.Pq tbl
+A column width specifier in a table layout is empty, zero, or not a valid
+numerical expression.
+The width specifier is ignored and the column is made wide enough
+to accommodate all its data cells.
 .It Sy "ignoring excessive spacing in tbl layout"
 .Pq tbl
 A spacing modifier in a table layout is unreasonably large.
diff --git a/contrib/mandoc/mandoc.3 b/contrib/mandoc/mandoc.3
index 4ecfbdebd8c2..6b759558e488 100644
--- a/contrib/mandoc/mandoc.3
+++ b/contrib/mandoc/mandoc.3
@@ -1,4 +1,4 @@
-.\"	$Id: mandoc.3,v 1.44 2018/12/30 00:49:55 schwarze Exp $
+.\" $Id: mandoc.3,v 1.46 2025/02/25 17:03:54 schwarze Exp $
 .\"
 .\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
 .\" Copyright (c) 2010-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: December 30 2018 $
+.Dd $Mdocdate: February 25 2025 $
 .Dt MANDOC 3
 .Os
 .Sh NAME
@@ -33,6 +33,8 @@
 .In sys/types.h
 .In stdio.h
 .In mandoc.h
+.In roff.h
+.In mandoc_parse.h
 .Pp
 .Fd "#define ASCII_NBRSP"
 .Fd "#define ASCII_HYPH"
@@ -141,6 +143,37 @@ or invoke
 .Fn mparse_reset
 and go back to step 2 to parse new files.
 .El
+.Pp
+The design goals of the
+.Nm mandoc
+library are limited to providing the functionality required by the
+.Xr mandoc 1
+program.
+Consequently, the functions documented in the present manual page
+do not aim for API stability.
+Any third-party program using them typically requires adjustments after every
+.Nm mandoc
+release.
+Linking such a program requires
+.Fl lz
+because
+.Fn mparse_readfd
+calls
+.Xr gzdopen 3 ,
+.Xr gzread 3 ,
+.Xr gzerror 3 ,
+and
+.Xr gzclose 3 .
+For
+.Xr mandoc 1
+itself, the
+.Pa ./configure
+script automatically adds
+.Fl lz
+to the
+.Ev LDADD
+.Xr make 1
+variable.
 .Sh REFERENCE
 This section documents the functions, types, and variables available
 via
diff --git a/contrib/mandoc/mandoc.css b/contrib/mandoc/mandoc.css
index 1dae127059d6..88432b9322b7 100644
--- a/contrib/mandoc/mandoc.css
+++ b/contrib/mandoc/mandoc.css
@@ -1,4 +1,4 @@
-/* $Id: mandoc.css,v 1.52 2022/07/06 14:34:59 schwarze Exp $ */
+/* $Id: mandoc.css,v 1.54 2025/01/25 03:18:55 schwarze Exp $ */
 /*
  * Standard style sheet for mandoc(1) -Thtml and man.cgi(8).
  *
@@ -179,7 +179,8 @@ h3.Ss {		margin-top: 1.2em;
 .RsP { }
 .RsQ { }
 .RsR { }
-.RsT {		text-decoration: underline; }
+.RsT {		font-style: normal;
+		font-weight: normal; }
 .RsU { }
 .RsV { }
 
diff --git a/contrib/mandoc/mandoc.h b/contrib/mandoc/mandoc.h
index 9ab68327ecb4..ccbf90392f4c 100644
--- a/contrib/mandoc/mandoc.h
+++ b/contrib/mandoc/mandoc.h
@@ -1,6 +1,6 @@
-/* $Id: mandoc.h,v 1.282 2023/10/21 17:10:17 schwarze Exp $ */
+/* $Id: mandoc.h,v 1.283 2025/01/05 18:14:39 schwarze Exp $ */
 /*
- * Copyright (c) 2012-2022 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2012-2022, 2025 Ingo Schwarze <schwarze@openbsd.org>
  * Copyright (c) 2010, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -193,6 +193,7 @@ enum	mandocerr {
 	MANDOCERR_TBLLAYOUT_NONE, /* empty tbl layout */
 	MANDOCERR_TBLLAYOUT_CHAR, /* invalid character in tbl layout: char */
 	MANDOCERR_TBLLAYOUT_PAR, /* unmatched parenthesis in tbl layout */
+	MANDOCERR_TBLLAYOUT_WIDTH, /* invalid column width in tbl layout */
 	MANDOCERR_TBLLAYOUT_SPC, /* ignoring excessive spacing in tbl layout */
 	MANDOCERR_TBLDATA_NONE, /* tbl without any data cells */
 	MANDOCERR_TBLDATA_SPAN, /* ignoring data in spanned tbl cell: data */
diff --git a/contrib/mandoc/mandoc_msg.c b/contrib/mandoc/mandoc_msg.c
index baa709c70c83..b4ba9cec9683 100644
--- a/contrib/mandoc/mandoc_msg.c
+++ b/contrib/mandoc/mandoc_msg.c
@@ -1,6 +1,6 @@
 /* $OpenBSD: mandoc_msg.c,v 1.8 2020/01/19 17:59:01 schwarze Exp $ */
 /*
- * Copyright (c) 2014-2022 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2014-2022, 2025 Ingo Schwarze <schwarze@openbsd.org>
  * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -192,6 +192,7 @@ static	const char *const type_message[MANDOCERR_MAX] = {
 	"empty tbl layout",
 	"invalid character in tbl layout",
 	"unmatched parenthesis in tbl layout",
+	"ignoring invalid column width in tbl layout",
 	"ignoring excessive spacing in tbl layout",
 	"tbl without any data cells",
 	"ignoring data in spanned tbl cell",
diff --git a/contrib/mandoc/mdoc.7 b/contrib/mandoc/mdoc.7
index 9dbce2127361..edd74eafa328 100644
--- a/contrib/mandoc/mdoc.7
+++ b/contrib/mandoc/mdoc.7
@@ -1,4 +1,4 @@
-.\" $Id: mdoc.7,v 1.294 2024/09/22 10:34:58 schwarze Exp $
+.\" $Id: mdoc.7,v 1.296 2025/01/27 03:17:33 schwarze Exp $
 .\"
 .\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
 .\" Copyright (c) 2010, 2011, 2013-2020 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: September 22 2024 $
+.Dd $Mdocdate: January 27 2025 $
 .Dt MDOC 7
 .Os
 .Sh NAME
@@ -2304,13 +2304,14 @@ Close single-quoted context opened by
 Begin a new section.
 For a list of conventional manual sections, see
 .Sx MANUAL STRUCTURE .
-These sections should be used unless it's absolutely necessary that
-custom sections be used.
-.Pp
-Section names should be unique so that they may be keyed by
-.Ic \&Sx .
-Although this macro is parsed, it should not consist of child node or it
-may not be linked with
+Use the conventional sections where applicable.
+For unusually long and complicated manual pages,
+adding custom sections is occasionally useful.
+.Pp
+Avoid using macros inside the
+.Ar TITLE LINE
+and keep that line unique within the manual page,
+such that it can be pointed to with
 .Ic \&Sx .
 .Pp
 See also
@@ -2360,10 +2361,10 @@ the conventional sections described in
 .Sx MANUAL STRUCTURE
 rarely have subsections.
 .Pp
-Sub-section names should be unique so that they may be keyed by
-.Ic \&Sx .
-Although this macro is parsed, it should not consist of child node or it
-may not be linked with
+Avoid using macros inside the
+.Ar Title line
+and keep that line unique within the manual page,
+such that it can be pointed to with
 .Ic \&Sx .
 .Pp
 See also
@@ -2405,12 +2406,17 @@ The original C standard.
 .It \-isoC-99
 .St -isoC-99
 .br
-The second major version of the C language standard.
+Edition 2 of the C language standard.
 .Pp
 .It \-isoC-2011
 .St -isoC-2011
 .br
-The third major version of the C language standard.
+Edition 3 of the C language standard.
+.Pp
+.It \-isoC-2023
+.St -isoC-2023
+.br
+Edition 5 of the C language standard.
 .El
 .It POSIX.1 before XPG4.2
 .Pp
diff --git a/contrib/mandoc/mdoc_html.c b/contrib/mandoc/mdoc_html.c
index 74d753a76bfb..b67eac4be233 100644
--- a/contrib/mandoc/mdoc_html.c
+++ b/contrib/mandoc/mdoc_html.c
@@ -1,6 +1,6 @@
-/* $Id: mdoc_html.c,v 1.350 2022/07/06 16:05:40 schwarze Exp $ */
+/* $Id: mdoc_html.c,v 1.353 2025/01/25 00:22:28 schwarze Exp $ */
 /*
- * Copyright (c) 2014-2022 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2014-2022, 2025 Ingo Schwarze <schwarze@openbsd.org>
  * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2022 Anna Vyalkova <cyber@sysrq.in>
  *
@@ -1456,7 +1456,7 @@ mdoc_rs_pre(MDOC_ARGS)
 	case ROFFT_BODY:
 		if (n->sec == SEC_SEE_ALSO)
 			print_otag(h, TAG_P, "c", "Pp");
-		print_otag(h, TAG_CITE, "c", "Rs");
+		print_otag(h, TAG_SPAN, "c", "Rs");
 		break;
 	default:
 		abort();
@@ -1494,10 +1494,13 @@ static int
 mdoc__x_pre(MDOC_ARGS)
 {
 	struct roff_node	*nn;
-	const char		*cattr;
+	const unsigned char	*cp;
+	const char		*cattr, *arg;
+	char			*url;
 	enum htmltag		 t;
 
 	t = TAG_SPAN;
+	arg = n->child->string;
 
 	switch (n->tok) {
 	case MDOC__A:
@@ -1507,7 +1510,7 @@ mdoc__x_pre(MDOC_ARGS)
 			print_text(h, "and");
 		break;
 	case MDOC__B:
-		t = TAG_I;
+		t = TAG_CITE;
 		cattr = "RsB";
 		break;
 	case MDOC__C:
@@ -1537,13 +1540,32 @@ mdoc__x_pre(MDOC_ARGS)
 		cattr = "RsQ";
 		break;
 	case MDOC__R:
+		if (strncmp(arg, "RFC ", 4) == 0) {
+			cp = arg += 4;
+			while (isdigit(*cp))
+				cp++;
+			if (*cp == '\0') {
+				mandoc_asprintf(&url, "https://www.rfc-"
+				    "editor.org/rfc/rfc%s.html", arg);
+				print_otag(h, TAG_A, "ch", "RsR", url);
+				free(url);
+				return 1;
+			}
+		}
 		cattr = "RsR";
 		break;
 	case MDOC__T:
-		cattr = "RsT";
+		t = TAG_CITE;
+		if (n->parent != NULL && n->parent->tok == MDOC_Rs &&
+		    n->parent->norm->Rs.quote_T) {
+			print_text(h, "\\(lq");
+			h->flags |= HTML_NOSPACE;
+			cattr = "RsT";
+		} else
+			cattr = "RsB";
 		break;
 	case MDOC__U:
-		print_otag(h, TAG_A, "ch", "RsU", n->child->string);
+		print_otag(h, TAG_A, "ch", "RsU", arg);
 		return 1;
 	case MDOC__V:
 		cattr = "RsV";
@@ -1561,14 +1583,23 @@ mdoc__x_post(MDOC_ARGS)
 {
 	struct roff_node *nn;
 
-	if (n->tok == MDOC__A &&
-	    (nn = roff_node_next(n)) != NULL && nn->tok == MDOC__A &&
-	    ((nn = roff_node_next(nn)) == NULL || nn->tok != MDOC__A) &&
-	    ((nn = roff_node_prev(n)) == NULL || nn->tok != MDOC__A))
-		return;
-
-	/* TODO: %U */
-
+	switch (n->tok) {
+	case MDOC__A:
+		if ((nn = roff_node_next(n)) != NULL && nn->tok == MDOC__A &&
+		    ((nn = roff_node_next(nn)) == NULL || nn->tok != MDOC__A) &&
+		    ((nn = roff_node_prev(n)) == NULL || nn->tok != MDOC__A))
+			return;
+		break;
+	case MDOC__T:
+		if (n->parent != NULL && n->parent->tok == MDOC_Rs &&
+		    n->parent->norm->Rs.quote_T) {
+			h->flags |= HTML_NOSPACE;
+			print_text(h, "\\(rq");
+		}
+		break;
+	default:
+		break;
+	}
 	if (n->parent == NULL || n->parent->tok != MDOC_Rs)
 		return;
 
diff --git a/contrib/mandoc/mdoc_man.c b/contrib/mandoc/mdoc_man.c
index d4fd88304fb0..5438b2ba5941 100644
--- a/contrib/mandoc/mdoc_man.c
+++ b/contrib/mandoc/mdoc_man.c
@@ -1,6 +1,6 @@
-/* $Id: mdoc_man.c,v 1.138 2023/04/28 19:11:04 schwarze Exp $ */
+/* $Id: mdoc_man.c,v 1.139 2025/01/24 22:37:24 schwarze Exp $ */
 /*
- * Copyright (c) 2011-2021 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011-2021, 2025 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
@@ -796,6 +796,9 @@ post_percent(DECL_ARGS)
 	if (mdoc_man_act(n->tok)->pre == pre_em)
 		font_pop();
 
+	if (n->parent == NULL || n->parent->tok != MDOC_Rs)
+		return;
+
 	if ((nn = roff_node_next(n)) != NULL) {
 		np = roff_node_prev(n);
 		nnn = nn == NULL ? NULL : roff_node_next(nn);
diff --git a/contrib/mandoc/mdoc_markdown.c b/contrib/mandoc/mdoc_markdown.c
index ecad77e308e6..06ca839a58b8 100644
--- a/contrib/mandoc/mdoc_markdown.c
+++ b/contrib/mandoc/mdoc_markdown.c
@@ -1,6 +1,6 @@
-/* $Id: mdoc_markdown.c,v 1.38 2024/08/13 12:44:00 schwarze Exp $ */
+/* $Id: mdoc_markdown.c,v 1.39 2025/01/20 07:01:17 schwarze Exp $ */
 /*
- * Copyright (c) 2017, 2018, 2020 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2017, 2018, 2020, 2025 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
@@ -85,6 +85,7 @@ static	int	 md_pre_Sh(struct roff_node *);
 static	int	 md_pre_Sm(struct roff_node *);
 static	int	 md_pre_Vt(struct roff_node *);
 static	int	 md_pre_Xr(struct roff_node *);
+static	int	 md_pre__R(struct roff_node *);
 static	int	 md_pre__T(struct roff_node *);
 static	int	 md_pre_br(struct roff_node *);
 
@@ -159,7 +160,7 @@ static	const struct md_act md_acts[MDOC_MAX - MDOC_Dd] = {
 	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %N */
 	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %O */
 	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %P */
-	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %R */
+	{ NULL, md_pre__R, md_post_pc, NULL, NULL }, /* %R */
 	{ NULL, md_pre__T, md_post__T, NULL, NULL }, /* %T */
 	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %V */
 	{ NULL, NULL, NULL, NULL, NULL }, /* Ac */
@@ -1580,6 +1581,34 @@ md_pre_Xr(struct roff_node *n)
 	return 0;
 }
 
+static int
+md_pre__R(struct roff_node *n)
+{
+	const unsigned char	*cp;
+	const char		*arg;
+
+	arg = n->child->string;
+
+	if (strncmp(arg, "RFC ", 4) != 0)
+		return 1;
+	cp = arg += 4;
+	while (isdigit(*cp))
+		cp++;
+	if (*cp != '\0')
+		return 1;
+
+	md_rawword("[RFC ");
+	outflags &= ~MD_spc;
+	md_rawword(arg);
+	outflags &= ~MD_spc;
+	md_rawword("](http://www.rfc-editor.org/rfc/rfc");
+	outflags &= ~MD_spc;
+	md_rawword(arg);
+	outflags &= ~MD_spc;
+	md_rawword(".html)");
+	return 0;
+}
+
 static int
 md_pre__T(struct roff_node *n)
 {
diff --git a/contrib/mandoc/out.c b/contrib/mandoc/out.c
index bb29f78c9701..f6f5859a1629 100644
--- a/contrib/mandoc/out.c
+++ b/contrib/mandoc/out.c
@@ -1,4 +1,4 @@
-/*	$Id: out.c,v 1.85 2021/10/17 21:05:54 schwarze Exp $ */
+/*	$Id: out.c,v 1.86 2025/01/05 18:14:39 schwarze Exp $ */
 /*
  * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2011, 2014, 2015, 2017, 2018, 2019, 2021
@@ -117,7 +117,6 @@ void
 tblcalc(struct rofftbl *tbl, const struct tbl_span *sp_first,
     size_t offset, size_t rmargin)
 {
-	struct roffsu		 su;
 	const struct tbl_opts	*opts;
 	const struct tbl_span	*sp;
 	const struct tbl_dat	*dp;
@@ -159,13 +158,6 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp_first,
 				continue;
 
 			/* Handle explicit width specifications. */
-
-			if (dp->layout->wstr != NULL &&
-			    dp->layout->width == 0 &&
-			    a2roffsu(dp->layout->wstr, &su, SCALE_EN)
-			    != NULL)
-				dp->layout->width =
-				    (*tbl->sulen)(&su, tbl->arg);
 			if (col->width < dp->layout->width)
 				col->width = dp->layout->width;
 			if (dp->layout->spacing != SIZE_MAX &&
diff --git a/contrib/mandoc/roff.c b/contrib/mandoc/roff.c
index bdb02101c053..7425b56873a0 100644
--- a/contrib/mandoc/roff.c
+++ b/contrib/mandoc/roff.c
@@ -1,6 +1,6 @@
-/* $Id: roff.c,v 1.400 2023/10/24 20:53:12 schwarze Exp $ */
+/* $Id: roff.c,v 1.405 2025/04/08 14:05:09 schwarze Exp $ */
 /*
- * Copyright (c) 2010-2015, 2017-2023 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2015, 2017-2025 Ingo Schwarze <schwarze@openbsd.org>
  * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -192,10 +192,8 @@ static	int		 roff_ec(ROFF_ARGS);
 static	int		 roff_eo(ROFF_ARGS);
 static	int		 roff_eqndelim(struct roff *, struct buf *, int);
 static	int		 roff_evalcond(struct roff *, int, char *, int *);
-static	int		 roff_evalnum(struct roff *, int,
-				const char *, int *, int *, int);
-static	int		 roff_evalpar(struct roff *, int,
-				const char *, int *, int *, int);
+static	int		 roff_evalpar(int, const char *, int *, int *,
+				char, int);
 static	int		 roff_evalstrcond(const char *, int *);
 static	int		 roff_expand(struct roff *, struct buf *,
 				int, int, char);
@@ -204,8 +202,8 @@ static	void		 roff_expand_patch(struct buf *, int,
 static	void		 roff_free1(struct roff *);
 static	void		 roff_freereg(struct roffreg *);
 static	void		 roff_freestr(struct roffkv *);
-static	size_t		 roff_getname(struct roff *, char **, int, int);
-static	int		 roff_getnum(const char *, int *, int *, int);
+static	size_t		 roff_getname(char **, int, int);
+static	int		 roff_getnum(const char *, int *, int *, char, int);
 static	int		 roff_getop(const char *, int *, char *);
 static	int		 roff_getregn(struct roff *,
 				const char *, size_t, char);
@@ -258,9 +256,6 @@ static	int		 roff_userdef(ROFF_ARGS);
 
 /* --- constant data ------------------------------------------------------ */
 
-#define	ROFFNUM_SCALE	(1 << 0)  /* Honour scaling in roff_getnum(). */
-#define	ROFFNUM_WHITE	(1 << 1)  /* Skip whitespace in roff_evalnum(). */
-
 const char *__roff_name[MAN_MAX + 1] = {
 	"br",		"ce",		"fi",		"ft",
 	"ll",		"mc",		"nf",
@@ -1529,8 +1524,8 @@ roff_expand(struct roff *r, struct buf *buf, int ln, int pos, char ec)
 		case 'B':
 			npos = 0;
 			ubuf[0] = iendarg > iarg && iend > iendarg &&
-			    roff_evalnum(r, ln, buf->buf + iarg, &npos,
-					 NULL, ROFFNUM_SCALE) &&
+			    roff_evalnum(ln, buf->buf + iarg, &npos,
+					 NULL, 'u', 0) &&
 			    npos == iendarg - iarg ? '1' : '0';
 			ubuf[1] = '\0';
 			res = ubuf;
@@ -2002,7 +1997,7 @@ roff_parse(struct roff *r, char *buf, int *pos, int ln, int ppos)
 		return TOKEN_NONE;
 
 	mac = cp;
-	maclen = roff_getname(r, &cp, ln, ppos);
+	maclen = roff_getname(&cp, ln, ppos);
 
 	deftype = ROFFDEF_USER | ROFFDEF_REN;
 	r->current_string = roff_getstrn(r, mac, maclen, &deftype);
@@ -2155,7 +2150,7 @@ roff_block(ROFF_ARGS)
 		namesz = 0;
 	} else {
 		iname = cp;
-		namesz = roff_getname(r, &cp, ln, ppos);
+		namesz = roff_getname(&cp, ln, ppos);
 		iname[namesz] = '\0';
 	}
 
@@ -2226,7 +2221,7 @@ roff_block(ROFF_ARGS)
 	/* Get the custom end marker. */
 
 	iname = cp;
-	namesz = roff_getname(r, &cp, ln, ppos);
+	namesz = roff_getname(&cp, ln, ppos);
 
 	/* Resolve the end marker if it is indirect. */
 
@@ -2427,74 +2422,81 @@ roff_cond_text(ROFF_ARGS)
 /* --- handling of numeric and conditional expressions -------------------- */
 
 /*
- * Parse a single signed integer number.  Stop at the first non-digit.
+ * Parse a single signed decimal number.  Stop at the first non-digit.
  * If there is at least one digit, return success and advance the
  * parse point, else return failure and let the parse point unchanged.
  * Ignore overflows, treat them just like the C language.
  */
 static int
-roff_getnum(const char *v, int *pos, int *res, int flags)
+roff_getnum(const char *v, int *pos, int *res, char unit, int skipspace)
 {
-	int	 myres, scaled, n, p;
-
-	if (NULL == res)
-		res = &myres;
+	double	 frac, myres;
+	int	 n, p;
 
 	p = *pos;
 	n = v[p] == '-';
 	if (n || v[p] == '+')
 		p++;
 
-	if (flags & ROFFNUM_WHITE)
+	if (skipspace)
 		while (isspace((unsigned char)v[p]))
 			p++;
 
-	for (*res = 0; isdigit((unsigned char)v[p]); p++)
-		*res = 10 * *res + v[p] - '0';
+	for (myres = 0.0; isdigit((unsigned char)v[p]); p++)
+		myres = myres * 10.0 + (v[p] - '0');
+	if (v[p] == '.')
+		for (frac = 0.1; isdigit((unsigned char)v[++p]); frac *= 0.1)
+			myres += frac * (v[p] - '0');
+
 	if (p == *pos + n)
 		return 0;
 
 	if (n)
-		*res = -*res;
+		myres *= -1.0;
 
 	/* Each number may be followed by one optional scaling unit. */
 
-	switch (v[p]) {
+	if (v[p] != '\0' && strchr("ficvPmnpuM", v[p]) != NULL) {
+		if (unit != '\0')
+			unit = v[p];
+		p++;
+	}
+
+	switch (unit) {
 	case 'f':
-		scaled = *res * 65536;
+		myres *= 65536.0;
 		break;
 	case 'i':
-		scaled = *res * 240;
+		myres *= 240.0;
 		break;
 	case 'c':
-		scaled = *res * 240 / 2.54;
+		myres *= 24000.0;
+		myres /= 254.0;
 		break;
 	case 'v':
 	case 'P':
-		scaled = *res * 40;
+		myres *= 40.0;
 		break;
 	case 'm':
 	case 'n':
-		scaled = *res * 24;
+		myres *= 24.0;
 		break;
 	case 'p':
-		scaled = *res * 10 / 3;
+		myres *= 40.0;
+		myres /= 12.0;
 		break;
 	case 'u':
-		scaled = *res;
 		break;
 	case 'M':
-		scaled = *res * 6 / 25;
+		myres *= 24.0;
+		myres /= 100.0;
 		break;
 	default:
-		scaled = *res;
-		p--;
 		break;
 	}
-	if (flags & ROFFNUM_SCALE)
-		*res = scaled;
-
-	*pos = p + 1;
+	if (res != NULL)
+		*res = myres;
+	*pos = p;
 	return 1;
 }
 
@@ -2616,7 +2618,7 @@ roff_evalcond(struct roff *r, int ln, char *v, int *pos)
 		while (*cp == ' ')
 			cp++;
 		name = cp;
-		sz = roff_getname(r, &cp, ln, cp - v);
+		sz = roff_getname(&cp, ln, cp - v);
 		if (sz == 0)
 			istrue = 0;
 		else if (v[*pos] == 'r')
@@ -2633,7 +2635,7 @@ roff_evalcond(struct roff *r, int ln, char *v, int *pos)
 	}
 
 	savepos = *pos;
-	if (roff_evalnum(r, ln, v, pos, &number, ROFFNUM_SCALE))
+	if (roff_evalnum(ln, v, pos, &number, 'u', 0))
 		return (number > 0) == wanttrue;
 	else if (*pos == savepos)
 		return roff_evalstrcond(v, pos) == wanttrue;
@@ -2771,7 +2773,7 @@ roff_ds(ROFF_ARGS)
 	if (*name == '\0')
 		return ROFF_IGN;
 
-	namesz = roff_getname(r, &string, ln, pos);
+	namesz = roff_getname(&string, ln, pos);
 	switch (name[namesz]) {
 	case '\\':
 		return ROFF_IGN;
@@ -2862,15 +2864,15 @@ roff_getop(const char *v, int *pos, char *res)
  * or a single signed integer number.
  */
 static int
-roff_evalpar(struct roff *r, int ln,
-	const char *v, int *pos, int *res, int flags)
+roff_evalpar(int ln, const char *v, int *pos, int *res, char unit,
+    int skipspace)
 {
 
 	if ('(' != v[*pos])
-		return roff_getnum(v, pos, res, flags);
+		return roff_getnum(v, pos, res, unit, skipspace);
 
 	(*pos)++;
-	if ( ! roff_evalnum(r, ln, v, pos, res, flags | ROFFNUM_WHITE))
+	if ( ! roff_evalnum(ln, v, pos, res, unit, 1))
 		return 0;
 
 	/*
@@ -2891,9 +2893,9 @@ roff_evalpar(struct roff *r, int ln,
  * Evaluate a complete numeric expression.
  * Proceed left to right, there is no concept of precedence.
  */
-static int
-roff_evalnum(struct roff *r, int ln, const char *v,
-	int *pos, int *res, int flags)
+int
+roff_evalnum(int ln, const char *v, int *pos, int *res, char unit,
+    int skipspace)
 {
 	int		 mypos, operand2;
 	char		 operator;
@@ -2903,29 +2905,29 @@ roff_evalnum(struct roff *r, int ln, const char *v,
 		pos = &mypos;
 	}
 
-	if (flags & ROFFNUM_WHITE)
+	if (skipspace)
 		while (isspace((unsigned char)v[*pos]))
 			(*pos)++;
 
-	if ( ! roff_evalpar(r, ln, v, pos, res, flags))
+	if ( ! roff_evalpar(ln, v, pos, res, unit, skipspace))
 		return 0;
 
 	while (1) {
-		if (flags & ROFFNUM_WHITE)
+		if (skipspace)
 			while (isspace((unsigned char)v[*pos]))
 				(*pos)++;
 
 		if ( ! roff_getop(v, pos, &operator))
 			break;
 
-		if (flags & ROFFNUM_WHITE)
+		if (skipspace)
 			while (isspace((unsigned char)v[*pos]))
 				(*pos)++;
 
-		if ( ! roff_evalpar(r, ln, v, pos, &operand2, flags))
+		if ( ! roff_evalpar(ln, v, pos, &operand2, unit, skipspace))
 			return 0;
 
-		if (flags & ROFFNUM_WHITE)
+		if (skipspace)
 			while (isspace((unsigned char)v[*pos]))
 				(*pos)++;
 
@@ -3062,6 +3064,8 @@ roff_getregro(const struct roff *r, const char *name)
 		return 24;
 	case 'j':  /* Always adjust left margin only. */
 		return 0;
+	case 'l':  /* Fixed line width for DocBook. */
+		return 78 * 24;
 	case 'T':  /* Some output device is always defined. */
 		return 1;
 	case 'V':  /* Fixed vertical resolution. */
@@ -3155,7 +3159,7 @@ roff_nr(ROFF_ARGS)
 	if (*key == '\0')
 		return ROFF_IGN;
 
-	keysz = roff_getname(r, &val, ln, pos);
+	keysz = roff_getname(&val, ln, pos);
 	if (key[keysz] == '\\' || key[keysz] == '\t')
 		return ROFF_IGN;
 
@@ -3164,13 +3168,13 @@ roff_nr(ROFF_ARGS)
 		val++;
 
 	len = 0;
-	if (roff_evalnum(r, ln, val, &len, &iv, ROFFNUM_SCALE) == 0)
+	if (roff_evalnum(ln, val, &len, &iv, 'u', 0) == 0)
 		return ROFF_IGN;
 
 	step = val + len;
 	while (isspace((unsigned char)*step))
 		step++;
-	if (roff_evalnum(r, ln, step, NULL, &is, 0) == 0)
+	if (roff_evalnum(ln, step, NULL, &is, '\0', 0) == 0)
 		is = INT_MIN;
 
 	roff_setregn(r, key, keysz, iv, sign, is);
@@ -3187,7 +3191,7 @@ roff_rr(ROFF_ARGS)
 	name = cp = buf->buf + pos;
 	if (*name == '\0')
 		return ROFF_IGN;
-	namesz = roff_getname(r, &cp, ln, pos);
+	namesz = roff_getname(&cp, ln, pos);
 	name[namesz] = '\0';
 
 	prev = &r->regtab;
@@ -3217,7 +3221,7 @@ roff_rm(ROFF_ARGS)
 	cp = buf->buf + pos;
 	while (*cp != '\0') {
 		name = cp;
-		namesz = roff_getname(r, &cp, ln, (int)(cp - buf->buf));
+		namesz = roff_getname(&cp, ln, (int)(cp - buf->buf));
*** 180 LINES SKIPPED ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202507141647.56EGlLwA065346>