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
This commit is contained in:
Alexander Ziaee
2025-06-12 17:25:42 -04:00
18 changed files with 303 additions and 150 deletions
+10 -1
View File
@@ -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
+2 -1
View File
@@ -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 *,
+35 -3
View File
@@ -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:
+10 -4
View File
@@ -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.
+35 -2
View File
@@ -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
+3 -2
View File
@@ -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 { }
+3 -2
View File
@@ -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 */
+2 -1
View File
@@ -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",
+20 -14
View File
@@ -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.
Use the conventional sections where applicable.
For unusually long and complicated manual pages,
adding custom sections is occasionally useful.
.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
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
+46 -15
View File
@@ -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;
+5 -2
View File
@@ -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);
+32 -3
View File
@@ -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)
{
+1 -9
View File
@@ -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 &&
+75 -71
View File
@@ -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));
roff_setstrn(&r->strtab, name, namesz, NULL, 0, 0);
roff_setstrn(&r->rentab, name, namesz, NULL, 0, 0);
if (name[namesz] == '\\' || name[namesz] == '\t')
@@ -3233,7 +3237,7 @@ roff_it(ROFF_ARGS)
/* Parse the number of lines. */
if ( ! roff_evalnum(r, ln, buf->buf, &pos, &iv, 0)) {
if ( ! roff_evalnum(ln, buf->buf, &pos, &iv, '\0', 0)) {
mandoc_msg(MANDOCERR_IT_NONUM,
ln, ppos, "%s", buf->buf + 1);
return ROFF_IGN;
@@ -3500,8 +3504,8 @@ roff_onearg(ROFF_ARGS)
r->man->last->flags |= NODE_NOSRC;
}
npos = 0;
if (roff_evalnum(r, ln, r->man->last->string, &npos,
&roffce_lines, 0) == 0) {
if (roff_evalnum(ln, r->man->last->string, &npos,
&roffce_lines, '\0', 0) == 0) {
mandoc_msg(MANDOCERR_CE_NONUM,
ln, pos, "ce %s", buf->buf + pos);
roffce_lines = 1;
@@ -3554,12 +3558,12 @@ roff_als(ROFF_ARGS)
if (*newn == '\0')
return ROFF_IGN;
newsz = roff_getname(r, &oldn, ln, pos);
newsz = roff_getname(&oldn, ln, pos);
if (newn[newsz] == '\\' || newn[newsz] == '\t' || *oldn == '\0')
return ROFF_IGN;
end = oldn;
oldsz = roff_getname(r, &end, ln, oldn - buf->buf);
oldsz = roff_getname(&end, ln, oldn - buf->buf);
if (oldsz == 0)
return ROFF_IGN;
@@ -3836,12 +3840,12 @@ roff_rn(ROFF_ARGS)
if (*oldn == '\0')
return ROFF_IGN;
oldsz = roff_getname(r, &newn, ln, pos);
oldsz = roff_getname(&newn, ln, pos);
if (oldn[oldsz] == '\\' || oldn[oldsz] == '\t' || *newn == '\0')
return ROFF_IGN;
end = newn;
newsz = roff_getname(r, &end, ln, newn - buf->buf);
newsz = roff_getname(&end, ln, newn - buf->buf);
if (newsz == 0)
return ROFF_IGN;
@@ -3883,7 +3887,7 @@ roff_shift(ROFF_ARGS)
argpos = pos;
levels = 1;
if (buf->buf[pos] != '\0' &&
roff_evalnum(r, ln, buf->buf, &pos, &levels, 0) == 0) {
roff_evalnum(ln, buf->buf, &pos, &levels, '\0', 0) == 0) {
mandoc_msg(MANDOCERR_CE_NONUM,
ln, pos, "shift %s", buf->buf + pos);
levels = 1;
@@ -4026,7 +4030,7 @@ roff_renamed(ROFF_ARGS)
* and advance the pointer to the next word.
*/
static size_t
roff_getname(struct roff *r, char **cpp, int ln, int pos)
roff_getname(char **cpp, int ln, int pos)
{
char *name, *cp;
int namesz, inam, iend;
+1 -1
View File
@@ -1,4 +1,4 @@
/* $Id: st.c,v 1.18 2024/06/16 18:49:04 schwarze Exp $ */
/* $Id: st.c,v 1.19 2025/01/02 13:34:04 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
*
+1 -2
View File
@@ -1,4 +1,4 @@
/* $Id: tbl.c,v 1.46 2018/12/14 06:33:14 schwarze Exp $ */
/* $Id: tbl.c,v 1.47 2025/01/05 18:14:39 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011, 2015 Ingo Schwarze <schwarze@openbsd.org>
@@ -118,7 +118,6 @@ tbl_free(struct tbl_node *tbl)
while (rp->first != NULL) {
cp = rp->first;
rp->first = cp->next;
free(cp->wstr);
free(cp);
}
free(rp);
+1 -2
View File
@@ -1,4 +1,4 @@
/* $Id: tbl.h,v 1.2 2021/08/10 12:55:04 schwarze Exp $ */
/* $Id: tbl.h,v 1.3 2025/01/05 18:14:39 schwarze Exp $ */
/*
* Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014,2015,2017,2018,2021 Ingo Schwarze <schwarze@openbsd.org>
@@ -51,7 +51,6 @@ enum tbl_cellt {
*/
struct tbl_cell {
struct tbl_cell *next; /* Layout cell to the right. */
char *wstr; /* Min width represented as a string. */
size_t width; /* Minimum column width. */
size_t spacing; /* To the right of the column. */
int vert; /* Width of subsequent vertical line. */
+21 -15
View File
@@ -1,8 +1,8 @@
/* $Id: tbl_layout.c,v 1.50 2021/08/10 12:55:04 schwarze Exp $ */
/* $Id: tbl_layout.c,v 1.51 2025/01/05 18:14:39 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2012, 2014, 2015, 2017, 2020, 2021
* Copyright (c) 2012, 2014, 2015, 2017, 2020, 2021, 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
* purpose with or without fee is hereby granted, provided that the above
@@ -67,7 +67,6 @@ mods(struct tbl_node *tbl, struct tbl_cell *cp,
{
char *endptr;
unsigned long spacing;
size_t sz;
int isz;
enum mandoc_esc fontesc;
@@ -138,20 +137,27 @@ mods(struct tbl_node *tbl, struct tbl_cell *cp,
cp->flags |= TBL_CELL_UP;
goto mod;
case 'w':
sz = 0;
if (p[*pos] == '(') {
(*pos)++;
while (p[*pos + sz] != '\0' && p[*pos + sz] != ')')
sz++;
} else
while (isdigit((unsigned char)p[*pos + sz]))
sz++;
if (sz) {
free(cp->wstr);
cp->wstr = mandoc_strndup(p + *pos, sz);
*pos += sz;
if (p[*pos] == ')')
isz = 0;
if (roff_evalnum(ln, p, pos, &isz, 'n', 1) == 0 ||
p[*pos] != ')')
mandoc_msg(MANDOCERR_TBLLAYOUT_WIDTH,
ln, *pos, "%s", p + *pos);
else {
/* Convert from BU to EN and round. */
cp->width = (isz + 11) /24;
(*pos)++;
}
} else {
cp->width = 0;
while (isdigit((unsigned char)p[*pos])) {
cp->width *= 10;
cp->width += p[(*pos)++] - '0';
}
if (cp->width == 0)
mandoc_msg(MANDOCERR_TBLLAYOUT_WIDTH,
ln, *pos, "%s", p + *pos);
}
goto mod;
case 'x':