diff options
author | Jerry Jelinek <jerry.jelinek@joyent.com> | 2019-06-24 13:13:08 +0000 |
---|---|---|
committer | Jerry Jelinek <jerry.jelinek@joyent.com> | 2019-06-24 13:13:08 +0000 |
commit | 981376523286ca1b5e8013bd974546dac7cf4602 (patch) | |
tree | b9c7e14ba10808d5fce59040e58584acc953149e | |
parent | c6ce7a25abbb33fa38edd55230b7992c5a36ce91 (diff) | |
parent | f2dbfd322ec9cd157a6e2cd8a53569e718a4b0af (diff) | |
download | illumos-joyent-981376523286ca1b5e8013bd974546dac7cf4602.tar.gz |
[illumos-gate merge]
commit f2dbfd322ec9cd157a6e2cd8a53569e718a4b0af
11184 Want CPU Temperature Sensors
11185 i86pc chip module should be smatch clean
commit 6ec1c6665dfa54c991783acaf82f51a97aa79267
11105 scsi_hba_tgtmap_create(9F) tgtmapout argument is incorrect
commit b73ccab03ec36581b1ae5945ef1fee1d06c79ccf
9318 vol_volsize_to_reservation does not account for raidz skip blocks
commit 29d33d4278d4226572dfc214775224334bc444a6
11260 mdb zfs metaslab statistics are unavailable
commit c1d5c2a48971d1705730e1ade6a1bc4d56587416
11084 clean up file-backed l2arc support
commit ba6bf04be4fe9d821c75a16fdebd3af3bffdbf26
11254 usb_parse_data.9f: WARNING: skipping paragraph macro: PP after SH
commit cec8643b41ebefad6c677010fc784dc4bb0550f3
11190 Update mandoc to 1.14.5
commit 07188943efdbeedd24142a14db7384af1478ba54
11264 tid::errno would be handy in mdb
Conflicts:
usr/src/uts/intel/sys/x86_archext.h
usr/src/uts/intel/Makefile.intel
usr/src/uts/intel/Makefile.files
usr/src/uts/i86pc/os/cpuid.c
usr/src/uts/common/sys/sunddi.h
usr/src/lib/fm/topo/modules/i86pc/chip/Makefile
usr/src/lib/fm/topo/modules/common/shared/topo_sensor.c
108 files changed, 7913 insertions, 5306 deletions
diff --git a/exception_lists/packaging b/exception_lists/packaging index 9916b48e59..cf220bce28 100644 --- a/exception_lists/packaging +++ b/exception_lists/packaging @@ -864,3 +864,8 @@ usr/lib/libdwarf.so # usr/bin/ctfconvert usr/bin/ctfmerge + +# +# SPARC doesn't currently use this today, though it may in the future. +# +usr/include/sys/sensors.h sparc @@ -4513,6 +4513,7 @@ f usr/include/sys/sem_impl.h 0644 root bin f usr/include/sys/sema_impl.h 0644 root bin f usr/include/sys/semaphore.h 0644 root bin f usr/include/sys/sendfile.h 0644 root bin +f usr/include/sys/sensors.h 0644 root bin f usr/include/sys/ser_sync.h 0644 root bin f usr/include/sys/serializer.h 0644 root bin f usr/include/sys/session.h 0644 root bin diff --git a/usr/src/cmd/mandoc/Makefile.common b/usr/src/cmd/mandoc/Makefile.common index f8834bb4a8..42d73be9f5 100644 --- a/usr/src/cmd/mandoc/Makefile.common +++ b/usr/src/cmd/mandoc/Makefile.common @@ -17,7 +17,8 @@ PROG= mandoc -OBJS= att.o \ +OBJS= arch.o \ + att.o \ chars.o \ dba.o \ dba_array.o \ @@ -39,6 +40,7 @@ OBJS= att.o \ man_validate.o \ mandoc.o \ mandoc_aux.o \ + mandoc_msg.o \ mandoc_ohash.o \ mandoc_xr.o \ mandocdb.o \ diff --git a/usr/src/cmd/mandoc/THIRDPARTYLICENSE b/usr/src/cmd/mandoc/THIRDPARTYLICENSE index 34420d2920..45ac298093 100644 --- a/usr/src/cmd/mandoc/THIRDPARTYLICENSE +++ b/usr/src/cmd/mandoc/THIRDPARTYLICENSE @@ -1,24 +1,25 @@ -$Id: LICENSE,v 1.17 2017/06/23 15:58:14 schwarze Exp $ +$Id: LICENSE,v 1.21 2018/11/26 17:11:11 schwarze Exp $ -With the exceptions noted below, all code and documentation -contained in the mandoc toolkit is protected by the Copyright -of the following developers: +With the exceptions noted below, all non-trivial files contained +in the mandoc toolkit are protected by the Copyright of the following +developers: Copyright (c) 2008-2012, 2014 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) 1999, 2004, 2017 Marc Espie <espie@openbsd.org> Copyright (c) 2009, 2010, 2011, 2012 Joerg Sonnenberger <joerg@netbsd.org> Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de> Copyright (c) 2014 Baptiste Daroussin <bapt@freebsd.org> Copyright (c) 2016 Ed Maste <emaste@freebsd.org> Copyright (c) 2017 Michael Stapelberg <stapelberg@debian.org> -Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org> +Copyright (c) 2017 Anthony Bentley <bentley@openbsd.org> Copyright (c) 1998, 2004, 2010 Todd C. Miller <Todd.Miller@courtesan.com> Copyright (c) 2008, 2017 Otto Moerbeek <otto@drijf.net> Copyright (c) 2004 Ted Unangst <tedu@openbsd.org> Copyright (c) 1994 Christos Zoulas <christos@netbsd.org> Copyright (c) 2003, 2007, 2008, 2014 Jason McIntyre <jmc@openbsd.org> -See the individual source files for information about who contributed +See the individual files for information about who contributed to which file during which years. diff --git a/usr/src/cmd/mandoc/arch.c b/usr/src/cmd/mandoc/arch.c new file mode 100644 index 0000000000..56b937ec84 --- /dev/null +++ b/usr/src/cmd/mandoc/arch.c @@ -0,0 +1,54 @@ +/* $Id: arch.c,v 1.14 2019/03/04 13:01:57 schwarze Exp $ */ +/* + * Copyright (c) 2017, 2019 Ingo Schwarze <schwarze@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" + +#include <string.h> + +#include "roff.h" + +int +arch_valid(const char *arch, enum mandoc_os os) +{ + const char *openbsd_arch[] = { + "alpha", "amd64", "arm64", "armv7", "hppa", "i386", + "landisk", "loongson", "luna88k", "macppc", "mips64", + "octeon", "sgi", "socppc", "sparc64", NULL + }; + const char *netbsd_arch[] = { + "acorn26", "acorn32", "algor", "alpha", "amiga", + "arc", "atari", + "bebox", "cats", "cesfic", "cobalt", "dreamcast", + "emips", "evbarm", "evbmips", "evbppc", "evbsh3", "evbsh5", + "hp300", "hpcarm", "hpcmips", "hpcsh", "hppa", + "i386", "ibmnws", "luna68k", + "mac68k", "macppc", "mipsco", "mmeye", "mvme68k", "mvmeppc", + "netwinder", "news68k", "newsmips", "next68k", + "pc532", "playstation2", "pmax", "pmppc", "prep", + "sandpoint", "sbmips", "sgimips", "shark", + "sparc", "sparc64", "sun2", "sun3", + "vax", "walnut", "x68k", "x86", "x86_64", "xen", NULL + }; + const char **arches[] = { NULL, netbsd_arch, openbsd_arch }; + const char **arch_p; + + if ((arch_p = arches[os]) == NULL) + return 1; + for (; *arch_p != NULL; arch_p++) + if (strcmp(*arch_p, arch) == 0) + return 1; + return 0; +} diff --git a/usr/src/cmd/mandoc/att.c b/usr/src/cmd/mandoc/att.c index dd7f2a0d77..5575bed54a 100644 --- a/usr/src/cmd/mandoc/att.c +++ b/usr/src/cmd/mandoc/att.c @@ -1,4 +1,4 @@ -/* $Id: att.c,v 1.16 2017/06/24 14:38:32 schwarze Exp $ */ +/* $Id: att.c,v 1.18 2018/12/13 11:55:46 schwarze Exp $ */ /* * Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -19,9 +19,7 @@ #include <sys/types.h> #include <string.h> -#include "mandoc.h" #include "roff.h" -#include "mdoc.h" #include "libmdoc.h" #define LINE(x, y) \ diff --git a/usr/src/cmd/mandoc/chars.c b/usr/src/cmd/mandoc/chars.c index fb9ded8bae..24166dbd9f 100644 --- a/usr/src/cmd/mandoc/chars.c +++ b/usr/src/cmd/mandoc/chars.c @@ -1,7 +1,7 @@ -/* $Id: chars.c,v 1.73 2017/08/23 13:01:29 schwarze Exp $ */ +/* $Id: chars.c,v 1.78 2018/12/15 19:30:26 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2011, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2011,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 @@ -23,6 +23,7 @@ #include <ctype.h> #include <stddef.h> #include <stdint.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> @@ -47,20 +48,13 @@ static struct ln lines[] = { { " ", ascii_nbrsp, 0x00a0 }, { "~", ascii_nbrsp, 0x00a0 }, { "0", " ", 0x2002 }, - { "|", "", 0 }, - { "^", "", 0 }, - { "&", "", 0 }, - { "%", "", 0 }, { ":", ascii_break, 0 }, - /* XXX The following three do not really belong here. */ - { "t", "", 0 }, - { "c", "", 0 }, - { "}", "", 0 }, /* Lines. */ { "ba", "|", 0x007c }, { "br", "|", 0x2502 }, { "ul", "_", 0x005f }, + { "_", "_", 0x005f }, { "ru", "_", 0x005f }, { "rn", "-", 0x203e }, { "bb", "|", 0x00a6 }, @@ -82,10 +76,10 @@ static struct ln lines[] = { { "sh", "#", 0x0023 }, { "CR", "<cr>", 0x21b5 }, { "OK", "\\/", 0x2713 }, - { "CL", "<club>", 0x2663 }, - { "SP", "<spade>", 0x2660 }, - { "HE", "<heart>", 0x2665 }, - { "DI", "<diamond>", 0x2666 }, + { "CL", "C", 0x2663 }, + { "SP", "S", 0x2660 }, + { "HE", "H", 0x2665 }, + { "DI", "D", 0x2666 }, /* Legal symbols. */ { "co", "(C)", 0x00a9 }, @@ -240,7 +234,7 @@ static struct ln lines[] = { { "Ah", "<Aleph>", 0x2135 }, { "Im", "<Im>", 0x2111 }, { "Re", "<Re>", 0x211c }, - { "wp", "P", 0x2118 }, + { "wp", "p", 0x2118 }, { "pd", "<del>", 0x2202 }, { "-h", "/h", 0x210f }, { "hbar", "/h", 0x210f }, @@ -287,6 +281,7 @@ static struct ln lines[] = { { "ho", ",", 0x02db }, { "ha", "^", 0x005e }, { "ti", "~", 0x007e }, + { "u02DC", "~", 0x02dc }, /* Accented letters. */ { "'A", "'\bA", 0x00c1 }, @@ -294,11 +289,13 @@ static struct ln lines[] = { { "'I", "'\bI", 0x00cd }, { "'O", "'\bO", 0x00d3 }, { "'U", "'\bU", 0x00da }, + { "'Y", "'\bY", 0x00dd }, { "'a", "'\ba", 0x00e1 }, { "'e", "'\be", 0x00e9 }, { "'i", "'\bi", 0x00ed }, { "'o", "'\bo", 0x00f3 }, { "'u", "'\bu", 0x00fa }, + { "'y", "'\by", 0x00fd }, { "`A", "`\bA", 0x00c0 }, { "`E", "`\bE", 0x00c8 }, { "`I", "`\bI", 0x00cc }, @@ -359,7 +356,7 @@ static struct ln lines[] = { { "Eu", "EUR", 0x20ac }, { "eu", "EUR", 0x20ac }, { "Ye", "=\bY", 0x00a5 }, - { "Po", "GBP", 0x00a3 }, + { "Po", "-\bL", 0x00a3 }, { "Cs", "o\bx", 0x00a4 }, { "Fn", ",\bf", 0x0192 }, @@ -460,7 +457,7 @@ mchars_spec2cp(const char *p, size_t sz) end = p + sz; ln = ohash_find(&mchars, ohash_qlookupi(&mchars, p, &end)); - return ln != NULL ? ln->unicode : sz == 1 ? (unsigned char)*p : -1; + return ln != NULL ? ln->unicode : -1; } int @@ -490,10 +487,8 @@ mchars_spec2str(const char *p, size_t sz, size_t *rsz) end = p + sz; ln = ohash_find(&mchars, ohash_qlookupi(&mchars, p, &end)); - if (ln == NULL) { - *rsz = 1; - return sz == 1 ? p : NULL; - } + if (ln == NULL) + return NULL; *rsz = strlen(ln->ascii); return ln->ascii; diff --git a/usr/src/cmd/mandoc/config.h b/usr/src/cmd/mandoc/config.h index 75f62a9339..3ae0245c08 100644 --- a/usr/src/cmd/mandoc/config.h +++ b/usr/src/cmd/mandoc/config.h @@ -40,6 +40,8 @@ #define HAVE_WCHAR 1 #define HAVE_OHASH 0 +#define OSENUM MANDOC_OS_OTHER + #define BINM_APROPOS "apropos" #define BINM_MAKEWHATIS "man -w" #define BINM_MAN "man" diff --git a/usr/src/cmd/mandoc/dbm.c b/usr/src/cmd/mandoc/dbm.c index 4aedf66d13..7637a036a5 100644 --- a/usr/src/cmd/mandoc/dbm.c +++ b/usr/src/cmd/mandoc/dbm.c @@ -1,4 +1,4 @@ -/* $Id: dbm.c,v 1.5 2016/10/18 22:27:25 schwarze Exp $ */ +/* $Id: dbm.c,v 1.6 2018/11/19 19:22:07 schwarze Exp $ */ /* * Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org> * @@ -151,17 +151,17 @@ dbm_page_get(int32_t ip) assert(ip < npages); res.name = dbm_get(pages[ip].name); if (res.name == NULL) - res.name = "(NULL)"; + res.name = "(NULL)\0"; res.sect = dbm_get(pages[ip].sect); if (res.sect == NULL) - res.sect = "(NULL)"; + res.sect = "(NULL)\0"; res.arch = pages[ip].arch ? dbm_get(pages[ip].arch) : NULL; res.desc = dbm_get(pages[ip].desc); if (res.desc == NULL) res.desc = "(NULL)"; res.file = dbm_get(pages[ip].file); if (res.file == NULL) - res.file = " (NULL)"; + res.file = " (NULL)\0"; res.addr = dbm_addr(pages + ip); return &res; } @@ -233,7 +233,7 @@ static struct dbm_res page_bytitle(enum iter arg_iter, const struct dbm_match *arg_match) { static const struct dbm_match *match; - static const char *cp; + static const char *cp; static int32_t ip; struct dbm_res res = {-1, 0}; @@ -315,7 +315,7 @@ page_byarch(const struct dbm_match *arg_match) static const struct dbm_match *match; struct dbm_res res = {-1, 0}; static int32_t ip; - const char *cp; + const char *cp; /* Initialize for a new iteration. */ diff --git a/usr/src/cmd/mandoc/eqn.c b/usr/src/cmd/mandoc/eqn.c index 01601a7137..3d63382ab3 100644 --- a/usr/src/cmd/mandoc/eqn.c +++ b/usr/src/cmd/mandoc/eqn.c @@ -1,7 +1,7 @@ -/* $Id: eqn.c,v 1.78 2017/07/15 16:26:17 schwarze Exp $ */ +/* $Id: eqn.c,v 1.83 2018/12/14 06:33:14 schwarze Exp $ */ /* * Copyright (c) 2011, 2014 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 @@ -30,8 +30,9 @@ #include "mandoc_aux.h" #include "mandoc.h" #include "roff.h" +#include "eqn.h" #include "libmandoc.h" -#include "libroff.h" +#include "eqn_parse.h" #define EQN_NEST_MAX 128 /* maximum nesting of defines */ #define STRNEQ(p1, sz1, p2, sz2) \ @@ -284,6 +285,13 @@ enum parse_mode { MODE_TOK }; +struct eqn_def { + char *key; + size_t keysz; + char *val; + size_t valsz; +}; + static struct eqn_box *eqn_box_alloc(struct eqn_node *, struct eqn_box *); static struct eqn_box *eqn_box_makebinary(struct eqn_node *, struct eqn_box *); @@ -295,12 +303,11 @@ static void eqn_undef(struct eqn_node *); struct eqn_node * -eqn_alloc(struct mparse *parse) +eqn_alloc(void) { struct eqn_node *ep; ep = mandoc_calloc(1, sizeof(*ep)); - ep->parse = parse; ep->gsize = EQN_DEFSIZE; return ep; } @@ -399,7 +406,7 @@ eqn_next(struct eqn_node *ep, enum parse_mode mode) ep->end = strchr(ep->start + 1, *ep->start); ep->start++; /* Skip opening quote. */ if (ep->end == NULL) { - mandoc_msg(MANDOCERR_ARG_QUOTE, ep->parse, + mandoc_msg(MANDOCERR_ARG_QUOTE, ep->node->line, ep->node->pos, NULL); ep->end = strchr(ep->start, '\0'); } @@ -420,7 +427,7 @@ eqn_next(struct eqn_node *ep, enum parse_mode mode) if ((def = eqn_def_find(ep)) == NULL) break; if (++lim > EQN_NEST_MAX) { - mandoc_msg(MANDOCERR_ROFFLOOP, ep->parse, + mandoc_msg(MANDOCERR_ROFFLOOP, ep->node->line, ep->node->pos, NULL); return EQN_TOK_EOF; } @@ -468,6 +475,8 @@ eqn_next(struct eqn_node *ep, enum parse_mode mode) void eqn_box_free(struct eqn_box *bp) { + if (bp == NULL) + return; if (bp->first) eqn_box_free(bp->first); @@ -482,6 +491,16 @@ eqn_box_free(struct eqn_box *bp) free(bp); } +struct eqn_box * +eqn_box_new(void) +{ + struct eqn_box *bp; + + bp = mandoc_calloc(1, sizeof(*bp)); + bp->expectargs = UINT_MAX; + return bp; +} + /* * Allocate a box as the last child of the parent node. */ @@ -490,10 +509,9 @@ eqn_box_alloc(struct eqn_node *ep, struct eqn_box *parent) { struct eqn_box *bp; - bp = mandoc_calloc(1, sizeof(struct eqn_box)); + bp = eqn_box_new(); bp->parent = parent; bp->parent->args++; - bp->expectargs = UINT_MAX; bp->font = bp->parent->font; bp->size = ep->gsize; @@ -542,7 +560,7 @@ static void eqn_delim(struct eqn_node *ep) { if (ep->end[0] == '\0' || ep->end[1] == '\0') { - mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse, + mandoc_msg(MANDOCERR_REQ_EMPTY, ep->node->line, ep->node->pos, "delim"); if (ep->end[0] != '\0') ep->end++; @@ -569,7 +587,7 @@ eqn_undef(struct eqn_node *ep) struct eqn_def *def; if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF) { - mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse, + mandoc_msg(MANDOCERR_REQ_EMPTY, ep->node->line, ep->node->pos, "undef"); return; } @@ -588,7 +606,7 @@ eqn_def(struct eqn_node *ep) int i; if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF) { - mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse, + mandoc_msg(MANDOCERR_REQ_EMPTY, ep->node->line, ep->node->pos, "define"); return; } @@ -617,7 +635,7 @@ eqn_def(struct eqn_node *ep) } if (eqn_next(ep, MODE_QUOTED) == EQN_TOK_EOF) { - mandoc_vmsg(MANDOCERR_REQ_EMPTY, ep->parse, + mandoc_msg(MANDOCERR_REQ_EMPTY, ep->node->line, ep->node->pos, "define %s", def->key); free(def->key); free(def->val); @@ -666,7 +684,7 @@ next_tok: case EQN_TOK_TDEFINE: if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF || eqn_next(ep, MODE_QUOTED) == EQN_TOK_EOF) - mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse, + mandoc_msg(MANDOCERR_REQ_EMPTY, ep->node->line, ep->node->pos, "tdefine"); break; case EQN_TOK_DELIM: @@ -674,8 +692,8 @@ next_tok: break; case EQN_TOK_GFONT: if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) - mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse, - ep->node->line, ep->node->pos, eqn_toks[tok]); + mandoc_msg(MANDOCERR_REQ_EMPTY, ep->node->line, + ep->node->pos, "%s", eqn_toks[tok]); break; case EQN_TOK_MARK: case EQN_TOK_LINEUP: @@ -690,8 +708,8 @@ next_tok: case EQN_TOK_DOT: case EQN_TOK_DOTDOT: if (parent->last == NULL) { - mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse, - ep->node->line, ep->node->pos, eqn_toks[tok]); + mandoc_msg(MANDOCERR_EQN_NOBOX, ep->node->line, + ep->node->pos, "%s", eqn_toks[tok]); cur = eqn_box_alloc(ep, parent); cur->type = EQN_TEXT; cur->text = mandoc_strdup(""); @@ -735,8 +753,8 @@ next_tok: case EQN_TOK_DOWN: case EQN_TOK_UP: if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) - mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse, - ep->node->line, ep->node->pos, eqn_toks[tok]); + mandoc_msg(MANDOCERR_REQ_EMPTY, ep->node->line, + ep->node->pos, "%s", eqn_toks[tok]); break; case EQN_TOK_FAT: case EQN_TOK_ROMAN: @@ -773,14 +791,14 @@ next_tok: case EQN_TOK_GSIZE: /* Accept two values: integral size and a single. */ if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) { - mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse, - ep->node->line, ep->node->pos, eqn_toks[tok]); + mandoc_msg(MANDOCERR_REQ_EMPTY, ep->node->line, + ep->node->pos, "%s", eqn_toks[tok]); break; } size = mandoc_strntoi(ep->start, ep->toksz, 10); if (-1 == size) { - mandoc_msg(MANDOCERR_IT_NONUM, ep->parse, - ep->node->line, ep->node->pos, eqn_toks[tok]); + mandoc_msg(MANDOCERR_IT_NONUM, ep->node->line, + ep->node->pos, "%s", eqn_toks[tok]); break; } if (EQN_TOK_GSIZE == tok) { @@ -804,8 +822,8 @@ next_tok: * and keep on reading. */ if (parent->last == NULL) { - mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse, - ep->node->line, ep->node->pos, eqn_toks[tok]); + mandoc_msg(MANDOCERR_EQN_NOBOX, ep->node->line, + ep->node->pos, "%s", eqn_toks[tok]); cur = eqn_box_alloc(ep, parent); cur->type = EQN_TEXT; cur->text = mandoc_strdup(""); @@ -871,8 +889,8 @@ next_tok: * rebalance and continue reading. */ if (parent->last == NULL) { - mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse, - ep->node->line, ep->node->pos, eqn_toks[tok]); + mandoc_msg(MANDOCERR_EQN_NOBOX, ep->node->line, + ep->node->pos, "%s", eqn_toks[tok]); cur = eqn_box_alloc(ep, parent); cur->type = EQN_TEXT; cur->text = mandoc_strdup(""); @@ -898,16 +916,16 @@ next_tok: cur->left != NULL)) break; if (cur == NULL) { - mandoc_msg(MANDOCERR_BLK_NOTOPEN, ep->parse, - ep->node->line, ep->node->pos, eqn_toks[tok]); + mandoc_msg(MANDOCERR_BLK_NOTOPEN, ep->node->line, + ep->node->pos, "%s", eqn_toks[tok]); break; } parent = cur; if (EQN_TOK_RIGHT == tok) { if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) { mandoc_msg(MANDOCERR_REQ_EMPTY, - ep->parse, ep->node->line, - ep->node->pos, eqn_toks[tok]); + ep->node->line, ep->node->pos, + "%s", eqn_toks[tok]); break; } /* Handling depends on right/left. */ @@ -941,8 +959,8 @@ next_tok: parent = parent->parent; if (EQN_TOK_LEFT == tok && eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) { - mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse, - ep->node->line, ep->node->pos, eqn_toks[tok]); + mandoc_msg(MANDOCERR_REQ_EMPTY, ep->node->line, + ep->node->pos, "%s", eqn_toks[tok]); break; } parent = eqn_box_alloc(ep, parent); @@ -975,8 +993,8 @@ next_tok: if (cur->type == EQN_PILE) break; if (cur == NULL) { - mandoc_msg(MANDOCERR_IT_STRAY, ep->parse, - ep->node->line, ep->node->pos, eqn_toks[tok]); + mandoc_msg(MANDOCERR_IT_STRAY, ep->node->line, + ep->node->pos, "%s", eqn_toks[tok]); break; } parent = eqn_box_alloc(ep, cur); @@ -1092,6 +1110,9 @@ eqn_free(struct eqn_node *p) { int i; + if (p == NULL) + return; + for (i = 0; i < (int)p->defsz; i++) { free(p->defs[i].key); free(p->defs[i].val); diff --git a/usr/src/cmd/mandoc/eqn.h b/usr/src/cmd/mandoc/eqn.h new file mode 100644 index 0000000000..c7c7aa15a7 --- /dev/null +++ b/usr/src/cmd/mandoc/eqn.h @@ -0,0 +1,72 @@ +/* $Id: eqn.h,v 1.1 2018/12/13 05:23:38 schwarze Exp $ */ +/* + * Copyright (c) 2011, 2014 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 + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Public data types for eqn(7) syntax trees. + */ + +enum eqn_boxt { + EQN_TEXT, /* Text, e.g. number, variable, operator, ... */ + EQN_SUBEXPR, /* Nested eqn(7) subexpression. */ + EQN_LIST, /* List, for example in braces. */ + EQN_PILE, /* Vertical pile. */ + EQN_MATRIX /* List of columns. */ +}; + +enum eqn_fontt { + EQNFONT_NONE = 0, + EQNFONT_ROMAN, + EQNFONT_BOLD, + EQNFONT_FAT, + EQNFONT_ITALIC, + EQNFONT__MAX +}; + +enum eqn_post { + EQNPOS_NONE = 0, + EQNPOS_SUP, + EQNPOS_SUBSUP, + EQNPOS_SUB, + EQNPOS_TO, + EQNPOS_FROM, + EQNPOS_FROMTO, + EQNPOS_OVER, + EQNPOS_SQRT, + EQNPOS__MAX +}; + + /* + * A "box" is a parsed mathematical expression as defined by the eqn.7 + * grammar. + */ +struct eqn_box { + struct eqn_box *parent; + struct eqn_box *prev; + struct eqn_box *next; + struct eqn_box *first; /* First child node. */ + struct eqn_box *last; /* Last child node. */ + char *text; /* Text (or NULL). */ + char *left; /* Left-hand fence. */ + char *right; /* Right-hand fence. */ + char *top; /* Symbol above. */ + char *bottom; /* Symbol below. */ + size_t expectargs; /* Maximal number of arguments. */ + size_t args; /* Actual number of arguments. */ + int size; /* Font size. */ +#define EQN_DEFSIZE INT_MIN + enum eqn_boxt type; /* Type of node. */ + enum eqn_fontt font; /* Font in this box. */ + enum eqn_post pos; /* Position of the next box. */ +}; diff --git a/usr/src/cmd/mandoc/eqn_html.c b/usr/src/cmd/mandoc/eqn_html.c index 51f1442342..1fe41ecbfa 100644 --- a/usr/src/cmd/mandoc/eqn_html.c +++ b/usr/src/cmd/mandoc/eqn_html.c @@ -1,4 +1,4 @@ -/* $Id: eqn_html.c,v 1.17 2017/07/14 13:32:35 schwarze Exp $ */ +/* $Id: eqn_html.c,v 1.18 2018/12/13 05:23:38 schwarze Exp $ */ /* * Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org> @@ -26,6 +26,7 @@ #include <string.h> #include "mandoc.h" +#include "eqn.h" #include "out.h" #include "html.h" diff --git a/usr/src/cmd/mandoc/eqn_parse.h b/usr/src/cmd/mandoc/eqn_parse.h new file mode 100644 index 0000000000..a2a4e6fd7d --- /dev/null +++ b/usr/src/cmd/mandoc/eqn_parse.h @@ -0,0 +1,48 @@ +/* $Id: eqn_parse.h,v 1.3 2018/12/14 06:33:14 schwarze Exp $ */ +/* + * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * 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 + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * External interface of the eqn(7) parser. + * For use in the roff(7) and eqn(7) parsers only. + */ + +struct roff_node; +struct eqn_box; +struct eqn_def; + +struct eqn_node { + struct roff_node *node; /* Syntax tree of this equation. */ + struct eqn_def *defs; /* Array of definitions. */ + char *data; /* Source code of this equation. */ + char *start; /* First byte of the current token. */ + char *end; /* First byte of the next token. */ + size_t defsz; /* Number of definitions. */ + size_t sz; /* Length of the source code. */ + size_t toksz; /* Length of the current token. */ + int gsize; /* Default point size. */ + int delim; /* In-line delimiters enabled. */ + char odelim; /* In-line opening delimiter. */ + char cdelim; /* In-line closing delimiter. */ +}; + + +struct eqn_node *eqn_alloc(void); +struct eqn_box *eqn_box_new(void); +void eqn_box_free(struct eqn_box *); +void eqn_free(struct eqn_node *); +void eqn_parse(struct eqn_node *); +void eqn_read(struct eqn_node *, const char *); +void eqn_reset(struct eqn_node *); diff --git a/usr/src/cmd/mandoc/eqn_term.c b/usr/src/cmd/mandoc/eqn_term.c index 669c3c56cf..3e27233b30 100644 --- a/usr/src/cmd/mandoc/eqn_term.c +++ b/usr/src/cmd/mandoc/eqn_term.c @@ -1,4 +1,4 @@ -/* $Id: eqn_term.c,v 1.17 2017/08/23 21:56:20 schwarze Exp $ */ +/* $Id: eqn_term.c,v 1.19 2018/12/13 05:23:38 schwarze Exp $ */ /* * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org> @@ -25,7 +25,7 @@ #include <stdlib.h> #include <string.h> -#include "mandoc.h" +#include "eqn.h" #include "out.h" #include "term.h" @@ -106,7 +106,7 @@ eqn_box(struct termp *p, const struct eqn_box *bp) /* Special box types. */ if (bp->pos == EQNPOS_SQRT) { - term_word(p, "sqrt"); + term_word(p, "\\(sr"); if (bp->first != NULL) { p->flags |= TERMP_NOSPACE; eqn_box(p, bp->first); diff --git a/usr/src/cmd/mandoc/html.c b/usr/src/cmd/mandoc/html.c index 70935dcd57..1302972a4e 100644 --- a/usr/src/cmd/mandoc/html.c +++ b/usr/src/cmd/mandoc/html.c @@ -1,7 +1,7 @@ -/* $Id: html.c,v 1.238 2018/06/25 16:54:59 schwarze Exp $ */ +/* $Id: html.c,v 1.254 2019/03/03 13:02:11 schwarze Exp $ */ /* * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2011-2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2011-2015, 2017-2019 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 @@ -18,6 +18,7 @@ #include "config.h" #include <sys/types.h> +#include <sys/stat.h> #include <assert.h> #include <ctype.h> @@ -62,6 +63,7 @@ static const struct htmldata htmltags[TAG_MAX] = { {"title", HTML_NLAROUND}, {"div", HTML_NLAROUND}, {"div", 0}, + {"section", HTML_NLALL}, {"h1", HTML_NLAROUND}, {"h2", HTML_NLAROUND}, {"span", 0}, @@ -77,6 +79,7 @@ static const struct htmldata htmltags[TAG_MAX] = { {"dl", HTML_NLALL | HTML_INDENT}, {"dt", HTML_NLAROUND}, {"dd", HTML_NLAROUND | HTML_INDENT}, + {"p", HTML_NLAROUND | HTML_INDENT}, {"pre", HTML_NLALL | HTML_NOINDENT}, {"var", 0}, {"cite", 0}, @@ -107,6 +110,7 @@ static const struct htmldata htmltags[TAG_MAX] = { /* Avoid duplicate HTML id= attributes. */ static struct ohash id_unique; +static void html_reset_internal(struct html *); static void print_byte(struct html *, char); static void print_endword(struct html *); static void print_indent(struct html *); @@ -116,7 +120,6 @@ static void print_ctag(struct html *, struct tag *); static int print_escape(struct html *, char); static int print_encode(struct html *, const char *, const char *, int); static void print_href(struct html *, const char *, const char *, int); -static void print_metaf(struct html *, enum mandoc_esc); void * @@ -128,31 +131,32 @@ html_alloc(const struct manoutput *outopts) h->tag = NULL; h->style = outopts->style; - h->base_man = outopts->man; + if ((h->base_man1 = outopts->man) == NULL) + h->base_man2 = NULL; + else if ((h->base_man2 = strchr(h->base_man1, ';')) != NULL) + *h->base_man2++ = '\0'; h->base_includes = outopts->includes; if (outopts->fragment) h->oflags |= HTML_FRAGMENT; + if (outopts->toc) + h->oflags |= HTML_TOC; mandoc_ohash_init(&id_unique, 4, 0); return h; } -void -html_free(void *p) +static void +html_reset_internal(struct html *h) { 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); @@ -162,6 +166,20 @@ html_free(void *p) } void +html_reset(void *p) +{ + html_reset_internal(p); + mandoc_ohash_init(&id_unique, 4, 0); +} + +void +html_free(void *p) +{ + html_reset_internal(p); + free(p); +} + +void print_gen_head(struct html *h) { struct tag *t; @@ -204,7 +222,7 @@ print_gen_head(struct html *h) print_tagq(h, t); } -static void +void print_metaf(struct html *h, enum mandoc_esc deco) { enum htmlfont font; @@ -222,12 +240,15 @@ print_metaf(struct html *h, enum mandoc_esc deco) case ESCAPE_FONTBI: font = HTMLFONT_BI; break; + case ESCAPE_FONTCW: + font = HTMLFONT_CW; + break; case ESCAPE_FONT: case ESCAPE_FONTROMAN: font = HTMLFONT_NONE; break; default: - abort(); + return; } if (h->metaf) { @@ -249,11 +270,69 @@ print_metaf(struct html *h, enum mandoc_esc deco) h->metaf = print_otag(h, TAG_B, ""); print_otag(h, TAG_I, ""); break; + case HTMLFONT_CW: + h->metaf = print_otag(h, TAG_SPAN, "c", "Li"); + break; default: break; } } +void +html_close_paragraph(struct html *h) +{ + struct tag *t; + + for (t = h->tag; t != NULL && t->closed == 0; t = t->next) { + switch(t->tag) { + case TAG_P: + case TAG_PRE: + print_tagq(h, t); + break; + case TAG_A: + print_tagq(h, t); + continue; + default: + continue; + } + break; + } +} + +/* + * ROFF_nf switches to no-fill mode, ROFF_fi to fill mode. + * TOKEN_NONE does not switch. The old mode is returned. + */ +enum roff_tok +html_fillmode(struct html *h, enum roff_tok want) +{ + struct tag *t; + enum roff_tok had; + + for (t = h->tag; t != NULL; t = t->next) + if (t->tag == TAG_PRE) + break; + + had = t == NULL ? ROFF_fi : ROFF_nf; + + if (want != had) { + switch (want) { + case ROFF_fi: + print_tagq(h, t); + break; + case ROFF_nf: + html_close_paragraph(h); + print_otag(h, TAG_PRE, ""); + break; + case TOKEN_NONE: + break; + default: + abort(); + } + } + return had; +} + char * html_make_id(const struct roff_node *n, int unique) { @@ -345,7 +424,6 @@ static int print_encode(struct html *h, const char *p, const char *pend, int norecurse) { char numbuf[16]; - struct tag *t; const char *seq; size_t sz; int c, len, breakline, nospace; @@ -371,9 +449,7 @@ print_encode(struct html *h, const char *p, const char *pend, int norecurse) if (breakline && (p >= pend || *p == ' ' || *p == ASCII_NBRSP)) { - t = print_otag(h, TAG_DIV, ""); - print_text(h, "\\~"); - print_tagq(h, t); + print_otag(h, TAG_BR, ""); breakline = 0; while (p < pend && (*p == ' ' || *p == ASCII_NBRSP)) p++; @@ -393,22 +469,25 @@ print_encode(struct html *h, const char *p, const char *pend, int norecurse) continue; esc = mandoc_escape(&p, &seq, &len); - if (ESCAPE_ERROR == esc) - break; - switch (esc) { case ESCAPE_FONT: case ESCAPE_FONTPREV: case ESCAPE_FONTBOLD: case ESCAPE_FONTITALIC: case ESCAPE_FONTBI: + case ESCAPE_FONTCW: case ESCAPE_FONTROMAN: - if (0 == norecurse) + if (0 == norecurse) { + h->flags |= HTML_NOSPACE; print_metaf(h, esc); + h->flags &= ~HTML_NOSPACE; + } continue; case ESCAPE_SKIPCHAR: h->flags |= HTML_SKIPCHAR; continue; + case ESCAPE_ERROR: + continue; default: break; } @@ -433,6 +512,12 @@ print_encode(struct html *h, const char *p, const char *pend, int norecurse) if (c <= 0) continue; break; + case ESCAPE_UNDEF: + c = *seq; + break; + case ESCAPE_DEVICE: + print_word(h, "html"); + continue; case ESCAPE_BREAK: breakline = 1; continue; @@ -464,9 +549,21 @@ print_encode(struct html *h, const char *p, const char *pend, int norecurse) static void print_href(struct html *h, const char *name, const char *sec, int man) { + struct stat sb; const char *p, *pp; + char *filename; + + if (man) { + pp = h->base_man1; + if (h->base_man2 != NULL) { + mandoc_asprintf(&filename, "%s.%s", name, sec); + if (stat(filename, &sb) == -1) + pp = h->base_man2; + free(filename); + } + } else + pp = h->base_includes; - pp = man ? h->base_man : h->base_includes; while ((p = strchr(pp, '%')) != NULL) { print_encode(h, pp, p, 1); if (man && p[1] == 'S') { @@ -492,7 +589,7 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...) struct tag *t; const char *attr; char *arg1, *arg2; - int tflags; + int style_written, tflags; tflags = htmltags[tag].flags; @@ -502,6 +599,8 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...) t = mandoc_malloc(sizeof(struct tag)); t->tag = tag; t->next = h->tag; + t->refcnt = 0; + t->closed = 0; h->tag = t; } else t = NULL; @@ -532,7 +631,7 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...) va_start(ap, fmt); - while (*fmt != '\0') { + while (*fmt != '\0' && *fmt != 's') { /* Parse attributes and arguments. */ @@ -548,10 +647,6 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...) case 'i': attr = "id"; break; - case 's': - attr = "style"; - arg2 = va_arg(ap, char *); - break; case '?': attr = arg1; arg1 = va_arg(ap, char *); @@ -584,26 +679,33 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...) print_encode(h, arg1, NULL, 1); fmt++; break; - case 'T': - print_encode(h, arg1, NULL, 1); - print_word(h, "\" title=\""); - print_encode(h, arg1, NULL, 1); - fmt++; - break; default: - 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, ';'); - } + print_encode(h, arg1, NULL, 1); break; } print_byte(h, '"'); } + + style_written = 0; + while (*fmt++ == 's') { + arg1 = va_arg(ap, char *); + arg2 = va_arg(ap, char *); + if (arg2 == NULL) + continue; + print_byte(h, ' '); + if (style_written == 0) { + print_word(h, "style=\""); + style_written = 1; + } + print_word(h, arg1); + print_byte(h, ':'); + print_byte(h, ' '); + print_word(h, arg2); + print_byte(h, ';'); + } + if (style_written) + print_byte(h, '"'); + va_end(ap); /* Accommodate for "well-formed" singleton escaping. */ @@ -631,33 +733,32 @@ print_ctag(struct html *h, struct tag *tag) { int tflags; - /* - * Remember to close out and nullify the current - * meta-font and table, if applicable. - */ - if (tag == h->metaf) - h->metaf = NULL; - if (tag == h->tblt) - h->tblt = NULL; - - tflags = htmltags[tag->tag].flags; - - if (tflags & HTML_INDENT) - h->indent--; - if (tflags & HTML_NOINDENT) - h->noindent--; - if (tflags & HTML_NLEND) - print_endline(h); - print_indent(h); - print_byte(h, '<'); - print_byte(h, '/'); - print_word(h, htmltags[tag->tag].name); - print_byte(h, '>'); - if (tflags & HTML_NLAFTER) - print_endline(h); - - h->tag = tag->next; - free(tag); + if (tag->closed == 0) { + tag->closed = 1; + if (tag == h->metaf) + h->metaf = NULL; + if (tag == h->tblt) + h->tblt = NULL; + + tflags = htmltags[tag->tag].flags; + if (tflags & HTML_INDENT) + h->indent--; + if (tflags & HTML_NOINDENT) + h->noindent--; + if (tflags & HTML_NLEND) + print_endline(h); + print_indent(h); + print_byte(h, '<'); + print_byte(h, '/'); + print_word(h, htmltags[tag->tag].name); + print_byte(h, '>'); + if (tflags & HTML_NLAFTER) + print_endline(h); + } + if (tag->refcnt == 0) { + h->tag = tag->next; + free(tag); + } } void @@ -717,6 +818,9 @@ print_text(struct html *h, const char *word) h->metaf = print_otag(h, TAG_B, ""); print_otag(h, TAG_I, ""); break; + case HTMLFONT_CW: + h->metaf = print_otag(h, TAG_SPAN, "c", "Li"); + break; default: print_indent(h); break; @@ -741,36 +845,33 @@ print_text(struct html *h, const char *word) void print_tagq(struct html *h, const struct tag *until) { - struct tag *tag; + struct tag *this, *next; - while ((tag = h->tag) != NULL) { - print_ctag(h, tag); - if (until && tag == until) - return; + for (this = h->tag; this != NULL; this = next) { + next = this == until ? NULL : this->next; + print_ctag(h, this); } } +/* + * Close out all open elements up to but excluding suntil. + * Note that a paragraph just inside stays open together with it + * because paragraphs include subsequent phrasing content. + */ void print_stagq(struct html *h, const struct tag *suntil) { - struct tag *tag; + struct tag *this, *next; - while ((tag = h->tag) != NULL) { - if (suntil && tag == suntil) - return; - print_ctag(h, tag); + for (this = h->tag; this != NULL; this = next) { + next = this->next; + if (this == suntil || (next == suntil && + (this->tag == TAG_P || this->tag == TAG_PRE))) + break; + print_ctag(h, this); } } -void -print_paragraph(struct html *h) -{ - struct tag *t; - - t = print_otag(h, TAG_DIV, "c", "Pp"); - print_tagq(h, t); -} - /*********************************************************************** * Low level output functions. diff --git a/usr/src/cmd/mandoc/html.h b/usr/src/cmd/mandoc/html.h index 6d44a47383..a6bf891190 100644 --- a/usr/src/cmd/mandoc/html.h +++ b/usr/src/cmd/mandoc/html.h @@ -1,7 +1,7 @@ -/* $Id: html.h,v 1.92 2018/06/25 16:54:59 schwarze Exp $ */ +/* $Id: html.h,v 1.102 2019/03/01 10:57:18 schwarze Exp $ */ /* * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2017, 2018 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2017, 2018, 2019 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 @@ -24,6 +24,7 @@ enum htmltag { TAG_TITLE, TAG_DIV, TAG_IDIV, + TAG_SECTION, TAG_H1, TAG_H2, TAG_SPAN, @@ -39,6 +40,7 @@ enum htmltag { TAG_DL, TAG_DT, TAG_DD, + TAG_P, TAG_PRE, TAG_VAR, TAG_CITE, @@ -72,11 +74,14 @@ enum htmlfont { HTMLFONT_BOLD, HTMLFONT_ITALIC, HTMLFONT_BI, + HTMLFONT_CW, HTMLFONT_MAX }; struct tag { struct tag *next; + int refcnt; + int closed; enum htmltag tag; }; @@ -87,12 +92,12 @@ struct html { #define HTML_KEEP (1 << 2) #define HTML_PREKEEP (1 << 3) #define HTML_NONOSPACE (1 << 4) /* never add spaces */ -#define HTML_LITERAL (1 << 5) /* literal (e.g., <PRE>) context */ #define HTML_SKIPCHAR (1 << 6) /* skip the next character */ #define HTML_NOSPLIT (1 << 7) /* do not break line before .An */ #define HTML_SPLIT (1 << 8) /* break line before .An */ #define HTML_NONEWLINE (1 << 9) /* No line break in nofill mode. */ #define HTML_BUFFER (1 << 10) /* Collect a word to see if it fits. */ +#define HTML_TOCDONE (1 << 11) /* The TOC was already written. */ size_t indent; /* current output indentation level */ int noindent; /* indent disabled by <pre> */ size_t col; /* current output byte position */ @@ -101,7 +106,8 @@ struct html { struct tag *tag; /* last open tag */ struct rofftbl tbl; /* current table */ struct tag *tblt; /* current open table scope */ - char *base_man; /* base for manpage href */ + char *base_man1; /* bases for manpage href */ + char *base_man2; char *base_includes; /* base for include href */ char *style; /* style-sheet URI */ struct tag *metaf; /* current open font scope */ @@ -109,6 +115,7 @@ struct html { enum htmlfont metac; /* current font mode */ int oflags; /* output options */ #define HTML_FRAGMENT (1 << 0) /* don't emit HTML/HEAD/BODY */ +#define HTML_TOC (1 << 1) /* emit a table of contents */ }; @@ -121,6 +128,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 *); +void print_metaf(struct html *, enum mandoc_esc); struct tag *print_otag(struct html *, enum htmltag, const char *, ...); void print_tagq(struct html *, const struct tag *); void print_stagq(struct html *, const struct tag *); @@ -128,7 +136,8 @@ void print_text(struct html *, const char *); void print_tblclose(struct html *); void print_tbl(struct html *, const struct tbl_span *); void print_eqn(struct html *, const struct eqn_box *); -void print_paragraph(struct html *); void print_endline(struct html *); +void html_close_paragraph(struct html *); +enum roff_tok html_fillmode(struct html *, enum roff_tok); char *html_make_id(const struct roff_node *, int); diff --git a/usr/src/cmd/mandoc/lib.c b/usr/src/cmd/mandoc/lib.c index 0474924d73..e377c1bced 100644 --- a/usr/src/cmd/mandoc/lib.c +++ b/usr/src/cmd/mandoc/lib.c @@ -1,4 +1,4 @@ -/* $Id: lib.c,v 1.14 2017/06/24 14:38:32 schwarze Exp $ */ +/* $Id: lib.c,v 1.15 2018/12/13 11:55:46 schwarze Exp $ */ /* * Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -17,12 +17,9 @@ #include "config.h" #include <sys/types.h> - #include <string.h> -#include "mandoc.h" #include "roff.h" -#include "mdoc.h" #include "libmdoc.h" #define LINE(x, y) \ diff --git a/usr/src/cmd/mandoc/libman.h b/usr/src/cmd/mandoc/libman.h index 312093dd01..ac960a6858 100644 --- a/usr/src/cmd/mandoc/libman.h +++ b/usr/src/cmd/mandoc/libman.h @@ -1,7 +1,7 @@ -/* $Id: libman.h,v 1.81 2017/04/29 12:45:41 schwarze Exp $ */ +/* $Id: libman.h,v 1.86 2018/12/31 10:04:39 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2014, 2015, 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 @@ -16,6 +16,9 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +struct roff_node; +struct roff_man; + #define MACRO_PROT_ARGS struct roff_man *man, \ enum roff_tok tok, \ int line, \ @@ -26,15 +29,14 @@ struct man_macro { void (*fp)(MACRO_PROT_ARGS); int flags; -#define MAN_SCOPED (1 << 0) /* Optional next-line scope. */ -#define MAN_NSCOPED (1 << 1) /* Allowed in next-line element scope. */ -#define MAN_BSCOPE (1 << 2) /* Break next-line block scope. */ -#define MAN_JOIN (1 << 3) /* Join arguments together. */ +#define MAN_BSCOPED (1 << 0) /* Optional next-line block scope. */ +#define MAN_ESCOPED (1 << 1) /* Optional next-line element scope. */ +#define MAN_NSCOPED (1 << 2) /* Allowed in next-line element scope. */ +#define MAN_XSCOPE (1 << 3) /* Exit next-line block scope. */ +#define MAN_JOIN (1 << 4) /* Join arguments together. */ }; -extern const struct man_macro *const man_macros; - +const struct man_macro *man_macro(enum roff_tok); -void man_node_validate(struct roff_man *); -void man_state(struct roff_man *, struct roff_node *); +void man_descope(struct roff_man *, int, int, char *); void man_unscope(struct roff_man *, const struct roff_node *); diff --git a/usr/src/cmd/mandoc/libmandoc.h b/usr/src/cmd/mandoc/libmandoc.h index 9cc8cce4ec..ff6f4692f0 100644 --- a/usr/src/cmd/mandoc/libmandoc.h +++ b/usr/src/cmd/mandoc/libmandoc.h @@ -1,7 +1,7 @@ -/* $Id: libmandoc.h,v 1.71 2018/04/09 22:27:04 schwarze Exp $ */ +/* $Id: libmandoc.h,v 1.77 2018/12/21 17:15:18 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011, 2012 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 @@ -16,31 +16,38 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -enum rofferr { - ROFF_CONT, /* continue processing line */ - ROFF_RERUN, /* re-run roff interpreter with offset */ - ROFF_APPEND, /* re-run main parser, appending next line */ - ROFF_REPARSE, /* re-run main parser on the result */ - ROFF_SO, /* include another file */ - ROFF_IGN, /* ignore current line */ -}; +/* + * Return codes passed from the roff parser to the main parser. + */ + +/* Main instruction: what to do with the returned line. */ +#define ROFF_IGN 0x000 /* Don't do anything with it. */ +#define ROFF_CONT 0x001 /* Give it to the high-level parser. */ +#define ROFF_RERUN 0x002 /* Re-run the roff parser with an offset. */ +#define ROFF_REPARSE 0x004 /* Recursively run the main parser on it. */ +#define ROFF_SO 0x008 /* Include the named file. */ +#define ROFF_MASK 0x00f /* Only one of these bits should be set. */ + +/* Options for further parsing, to be OR'ed with the above. */ +#define ROFF_APPEND 0x010 /* Append the next line to this one. */ +#define ROFF_USERCALL 0x020 /* Start execution of a new macro. */ +#define ROFF_USERRET 0x040 /* Abort execution of the current macro. */ +#define ROFF_WHILE 0x100 /* Start a new .while loop. */ +#define ROFF_LOOPCONT 0x200 /* Iterate the current .while loop. */ +#define ROFF_LOOPEXIT 0x400 /* Exit the current .while loop. */ +#define ROFF_LOOPMASK 0xf00 + struct buf { - char *buf; - size_t sz; + char *buf; + size_t sz; + struct buf *next; }; -struct mparse; struct roff; struct roff_man; -void mandoc_msg(enum mandocerr, struct mparse *, - int, int, const char *); -void mandoc_vmsg(enum mandocerr, struct mparse *, - int, int, const char *, ...) - __attribute__((__format__ (__printf__, 5, 6))); -char *mandoc_getarg(struct mparse *, char **, int, int *); char *mandoc_normdate(struct roff_man *, char *, int, int); int mandoc_eos(const char *, size_t); int mandoc_strntoi(const char *, size_t, int); @@ -57,17 +64,18 @@ int preconv_encode(const struct buf *, size_t *, struct buf *, size_t *, int *); void roff_free(struct roff *); -struct roff *roff_alloc(struct mparse *, int); +struct roff *roff_alloc(int); void roff_reset(struct roff *); void roff_man_free(struct roff_man *); -struct roff_man *roff_man_alloc(struct roff *, struct mparse *, - const char *, int); +struct roff_man *roff_man_alloc(struct roff *, const char *, int); void roff_man_reset(struct roff_man *); -enum rofferr roff_parseln(struct roff *, int, struct buf *, int *); +int roff_parseln(struct roff *, int, struct buf *, int *); +void roff_userret(struct roff *); void roff_endparse(struct roff *); void roff_setreg(struct roff *, const char *, int, char sign); int roff_getreg(struct roff *, const char *); char *roff_strdup(const struct roff *, const char *); +char *roff_getarg(struct roff *, char **, int, int *); int roff_getcontrol(const struct roff *, const char *, int *); int roff_getformat(const struct roff *); diff --git a/usr/src/cmd/mandoc/libmdoc.h b/usr/src/cmd/mandoc/libmdoc.h index 57dff61b4a..ff29625194 100644 --- a/usr/src/cmd/mandoc/libmdoc.h +++ b/usr/src/cmd/mandoc/libmdoc.h @@ -1,7 +1,7 @@ -/* $Id: libmdoc.h,v 1.112 2017/05/30 16:22:03 schwarze Exp $ */ +/* $Id: libmdoc.h,v 1.117 2018/12/31 04:55:46 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 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 @@ -16,6 +16,10 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +struct roff_node; +struct roff_man; +struct mdoc_arg; + #define MACRO_PROT_ARGS struct roff_man *mdoc, \ enum roff_tok tok, \ int line, \ @@ -38,6 +42,7 @@ enum margserr { ARGS_ERROR, ARGS_EOLN, /* end-of-line */ ARGS_WORD, /* normal word */ + ARGS_ALLOC, /* normal word from roff_getarg() */ ARGS_PUNCT, /* series of punctuation */ ARGS_PHRASE /* Bl -column phrase */ }; @@ -59,10 +64,8 @@ enum mdelim { DELIM_MAX }; -extern const struct mdoc_macro *const mdoc_macros; - +const struct mdoc_macro *mdoc_macro(enum roff_tok); -void mdoc_macro(MACRO_PROT_ARGS); void mdoc_elem_alloc(struct roff_man *, int, int, enum roff_tok, struct mdoc_arg *); struct roff_node *mdoc_block_alloc(struct roff_man *, int, int, @@ -71,10 +74,7 @@ void mdoc_tail_alloc(struct roff_man *, int, int, enum roff_tok); struct roff_node *mdoc_endbody_alloc(struct roff_man *, int, int, enum roff_tok, struct roff_node *); -void mdoc_node_relink(struct roff_man *, struct roff_node *); -void mdoc_node_validate(struct roff_man *); void mdoc_state(struct roff_man *, struct roff_node *); -void mdoc_state_reset(struct roff_man *); const char *mdoc_a2arch(const char *); const char *mdoc_a2att(const char *); const char *mdoc_a2lib(const char *); diff --git a/usr/src/cmd/mandoc/libroff.h b/usr/src/cmd/mandoc/libroff.h deleted file mode 100644 index b6a026d820..0000000000 --- a/usr/src/cmd/mandoc/libroff.h +++ /dev/null @@ -1,80 +0,0 @@ -/* $Id: libroff.h,v 1.42 2017/07/08 17:52:49 schwarze Exp $ */ -/* - * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -enum tbl_part { - TBL_PART_OPTS, /* in options (first line) */ - TBL_PART_LAYOUT, /* describing layout */ - TBL_PART_DATA, /* creating data rows */ - TBL_PART_CDATA /* continue previous row */ -}; - -struct tbl_node { - struct mparse *parse; /* parse point */ - int pos; /* invocation column */ - int line; /* invocation line */ - enum tbl_part part; - struct tbl_opts opts; - struct tbl_row *first_row; - struct tbl_row *last_row; - struct tbl_span *first_span; - struct tbl_span *current_span; - struct tbl_span *last_span; - struct tbl_node *next; -}; - -struct eqn_node { - struct mparse *parse; /* main parser, for error reporting */ - struct roff_node *node; /* syntax tree of this equation */ - struct eqn_def *defs; /* array of definitions */ - char *data; /* source code of this equation */ - char *start; /* first byte of the current token */ - char *end; /* first byte of the next token */ - size_t defsz; /* number of definitions */ - size_t sz; /* length of the source code */ - size_t toksz; /* length of the current token */ - int gsize; /* default point size */ - int delim; /* in-line delimiters enabled */ - char odelim; /* in-line opening delimiter */ - char cdelim; /* in-line closing delimiter */ -}; - -struct eqn_def { - char *key; - size_t keysz; - char *val; - size_t valsz; -}; - - -struct tbl_node *tbl_alloc(int, int, struct mparse *); -void tbl_restart(int, int, struct tbl_node *); -void tbl_free(struct tbl_node *); -void tbl_reset(struct tbl_node *); -void tbl_read(struct tbl_node *, int, const char *, int); -void tbl_option(struct tbl_node *, int, const char *, int *); -void tbl_layout(struct tbl_node *, int, const char *, int); -void tbl_data(struct tbl_node *, int, const char *, int); -void tbl_cdata(struct tbl_node *, int, const char *, int); -const struct tbl_span *tbl_span(struct tbl_node *); -int tbl_end(struct tbl_node *); -struct eqn_node *eqn_alloc(struct mparse *); -void eqn_box_free(struct eqn_box *); -void eqn_free(struct eqn_node *); -void eqn_parse(struct eqn_node *); -void eqn_read(struct eqn_node *, const char *); -void eqn_reset(struct eqn_node *); diff --git a/usr/src/cmd/mandoc/main.c b/usr/src/cmd/mandoc/main.c index 600bc9bb4b..b91c15860a 100644 --- a/usr/src/cmd/mandoc/main.c +++ b/usr/src/cmd/mandoc/main.c @@ -1,7 +1,7 @@ -/* $Id: main.c,v 1.306 2018/05/14 14:10:23 schwarze Exp $ */ +/* $Id: main.c,v 1.322 2019/03/06 10:18:58 schwarze Exp $ */ /* * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2010-2012, 2014-2018 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2010-2012, 2014-2019 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org> * * Permission to use, copy, modify, and distribute this software for any @@ -21,7 +21,6 @@ #include <sys/types.h> #include <sys/ioctl.h> #include <sys/param.h> /* MACHINE */ -#include <sys/termios.h> #include <sys/wait.h> #include <assert.h> @@ -40,6 +39,7 @@ #include <stdint.h> #include <stdlib.h> #include <string.h> +#include <termios.h> #include <time.h> #include <unistd.h> @@ -49,6 +49,7 @@ #include "roff.h" #include "mdoc.h" #include "man.h" +#include "mandoc_parse.h" #include "tag.h" #include "main.h" #include "manconf.h" @@ -81,7 +82,6 @@ struct curparse { void *outdata; /* data for output */ char *os_s; /* operating system for display */ int wstop; /* stop after a file with a warning */ - enum mandocerr mmin; /* ignore messages below this */ enum mandoc_os os_e; /* check base system conventions */ enum outt outtype; /* which output to use */ }; @@ -89,7 +89,7 @@ struct curparse { int mandocdb(int, char *[]); -static void check_xr(const char *); +static void check_xr(void); static int fs_lookup(const struct manpaths *, size_t ipath, const char *, const char *, const char *, @@ -99,8 +99,6 @@ static int fs_search(const struct mansearch *, struct manpage **, size_t *); static int koptions(int *, char *); static void moptions(int *, char *); -static void mmsg(enum mandocerr, enum mandoclevel, - const char *, int, int, const char *); static void outdata_alloc(struct curparse *); static void parse(struct curparse *, int, const char *); static void passthrough(const char *, int, int); @@ -112,8 +110,6 @@ static int woptions(struct curparse *, char *); static const int sec_prios[] = {1, 4, 5, 8, 6, 3, 7, 2, 9}; static char help_arg[] = "help"; static char *help_argv[] = {help_arg, NULL}; -static enum mandoclevel rc; -static FILE *mmsg_stream; int @@ -127,7 +123,7 @@ main(int argc, char *argv[]) struct manpage *res, *resp; const char *progname, *sec, *thisarg; char *conf_file, *defpaths, *auxpaths; - char *oarg; + char *oarg, *tagarg; unsigned char *uc; size_t i, sz; int prio, best_prio; @@ -152,6 +148,7 @@ main(int argc, char *argv[]) setprogname(progname); #endif + mandoc_msg_setoutfile(stderr); if (strncmp(progname, "mandocdb", 8) == 0 || strcmp(progname, BINM_MAKEWHATIS) == 0) return mandocdb(argc, argv); @@ -191,10 +188,8 @@ main(int argc, char *argv[]) memset(&curp, 0, sizeof(struct curparse)); curp.outtype = OUTT_LOCALE; - curp.mmin = MANDOCERR_MAX; curp.outopts = &conf.output; options = MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1; - mmsg_stream = stderr; use_pager = 1; tag_files = NULL; @@ -314,6 +309,9 @@ main(int argc, char *argv[]) } } + if (curp.outtype != OUTT_TREE || !curp.outopts->noval) + options |= MPARSE_VALIDATE; + if (outmode == OUTMODE_FLN || outmode == OUTMODE_LST || !isatty(STDOUT_FILENO)) @@ -371,7 +369,16 @@ main(int argc, char *argv[]) #endif } - rc = MANDOCLEVEL_OK; + /* + * Use the first argument for -O tag in addition to + * using it as a search term for man(1) or apropos(1). + */ + + if (conf.output.tag != NULL && *conf.output.tag == '\0') { + tagarg = argc > 0 && search.argmode == ARG_EXPR ? + strchr(*argv, '=') : NULL; + conf.output.tag = tagarg == NULL ? *argv : tagarg + 1; + } /* man(1), whatis(1), apropos(1) */ @@ -405,7 +412,6 @@ main(int argc, char *argv[]) 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++; @@ -415,7 +421,7 @@ main(int argc, char *argv[]) if (sz == 0) { if (search.argmode != ARG_NAME) warnx("nothing appropriate"); - rc = MANDOCLEVEL_BADARG; + mandoc_msg_setrc(MANDOCLEVEL_BADARG); goto out; } @@ -483,19 +489,17 @@ main(int argc, char *argv[]) moptions(&options, auxpaths); mchars_alloc(); - curp.mp = mparse_alloc(options, curp.mmin, mmsg, - curp.os_e, curp.os_s); - - /* - * Conditionally start up the lookaside buffer before parsing. - */ - if (OUTT_MAN == curp.outtype) - mparse_keep(curp.mp); + curp.mp = mparse_alloc(options, curp.os_e, curp.os_s); if (argc < 1) { - if (use_pager) + if (use_pager) { tag_files = tag_init(); - parse(&curp, STDIN_FILENO, "<stdin>"); + tag_files->tagname = conf.output.tag; + } + thisarg = "<stdin>"; + mandoc_msg_setinfilename(thisarg); + parse(&curp, STDIN_FILENO, thisarg); + mandoc_msg_setinfilename(NULL); } /* @@ -519,22 +523,25 @@ main(int argc, char *argv[]) (void)chdir(conf.manpath.paths[resp->ipath]); else if (startdir != -1) (void)fchdir(startdir); - } + thisarg = resp->file; + } else + thisarg = *argv; - fd = mparse_open(curp.mp, resp != NULL ? resp->file : *argv); + fd = mparse_open(curp.mp, thisarg); if (fd != -1) { if (use_pager) { - tag_files = tag_init(); use_pager = 0; + tag_files = tag_init(); + tag_files->tagname = conf.output.tag; } - if (resp == NULL) - parse(&curp, fd, *argv); - else if (resp->form == FORM_SRC) - parse(&curp, fd, resp->file); + mandoc_msg_setinfilename(thisarg); + if (resp == NULL || resp->form == FORM_SRC) + parse(&curp, fd, thisarg); else passthrough(resp->file, fd, conf.output.synopsisonly); + mandoc_msg_setinfilename(NULL); if (ferror(stdout)) { if (tag_files != NULL) { @@ -543,7 +550,7 @@ main(int argc, char *argv[]) tag_files = NULL; } else warn("stdout"); - rc = MANDOCLEVEL_SYSERR; + mandoc_msg_setrc(MANDOCLEVEL_SYSERR); break; } @@ -552,10 +559,11 @@ main(int argc, char *argv[]) outdata_alloc(&curp); terminal_sepline(curp.outdata); } - } else if (rc < MANDOCLEVEL_ERROR) - rc = MANDOCLEVEL_ERROR; + } else + mandoc_msg(MANDOCERR_FILE, 0, 0, + "%s: %s", thisarg, strerror(errno)); - if (MANDOCLEVEL_OK != rc && curp.wstop) + if (curp.wstop && mandoc_msg_getrc() != MANDOCLEVEL_OK) break; if (resp != NULL) @@ -646,7 +654,7 @@ out: if (pid == -1) { warn("wait"); - rc = MANDOCLEVEL_SYSERR; + mandoc_msg_setrc(MANDOCLEVEL_SYSERR); break; } if (!WIFSTOPPED(status)) @@ -656,8 +664,7 @@ out: } tag_unlink(); } - - return (int)rc; + return (int)mandoc_msg_getrc(); } static void @@ -755,7 +762,6 @@ found: page->names = NULL; page->output = NULL; page->ipath = ipath; - page->bits = NAME_FILE & NAME_MASK; page->sec = (*sec >= '1' && *sec <= '9') ? *sec - '1' + 1 : 10; page->form = form; return 1; @@ -790,8 +796,18 @@ fs_search(const struct mansearch *cfg, const struct manpaths *paths, return 1; } if (res != NULL && *ressz == lastsz && - strchr(*argv, '/') == NULL) - warnx("No entry for %s in the manual.", *argv); + strchr(*argv, '/') == NULL) { + if (cfg->arch != NULL && + arch_valid(cfg->arch, OSENUM) == 0) + warnx("Unknown architecture \"%s\".", + cfg->arch); + else if (cfg->sec == NULL) + warnx("No entry for %s in the manual.", + *argv); + else + warnx("No entry for %s in section %s " + "of the manual.", *argv, cfg->sec); + } lastsz = *ressz; argv++; argc--; @@ -802,101 +818,92 @@ fs_search(const struct mansearch *cfg, const struct manpaths *paths, static void parse(struct curparse *curp, int fd, const char *file) { - enum mandoclevel rctmp; - struct roff_man *man; + struct roff_meta *meta; /* Begin by parsing the file itself. */ assert(file); assert(fd >= 0); - rctmp = mparse_readfd(curp->mp, fd, file); + mparse_readfd(curp->mp, fd, file); if (fd != STDIN_FILENO) close(fd); - if (rc < rctmp) - rc = rctmp; /* * With -Wstop and warnings or errors of at least the requested * level, do not produce output. */ - if (rctmp != MANDOCLEVEL_OK && curp->wstop) + if (curp->wstop && mandoc_msg_getrc() != MANDOCLEVEL_OK) return; if (curp->outdata == NULL) outdata_alloc(curp); + else if (curp->outtype == OUTT_HTML) + html_reset(curp); - mparse_result(curp->mp, &man, NULL); + mandoc_xr_reset(); + meta = mparse_result(curp->mp); /* Execute the out device, if it exists. */ - if (man == NULL) - return; - mandoc_xr_reset(); - if (man->macroset == MACROSET_MDOC) { - if (curp->outtype != OUTT_TREE || !curp->outopts->noval) - mdoc_validate(man); + if (meta->macroset == MACROSET_MDOC) { switch (curp->outtype) { case OUTT_HTML: - html_mdoc(curp->outdata, man); + html_mdoc(curp->outdata, meta); break; case OUTT_TREE: - tree_mdoc(curp->outdata, man); + tree_mdoc(curp->outdata, meta); break; case OUTT_MAN: - man_mdoc(curp->outdata, man); + man_mdoc(curp->outdata, meta); break; case OUTT_PDF: case OUTT_ASCII: case OUTT_UTF8: case OUTT_LOCALE: case OUTT_PS: - terminal_mdoc(curp->outdata, man); + terminal_mdoc(curp->outdata, meta); break; case OUTT_MARKDOWN: - markdown_mdoc(curp->outdata, man); + markdown_mdoc(curp->outdata, meta); break; default: break; } } - if (man->macroset == MACROSET_MAN) { - if (curp->outtype != OUTT_TREE || !curp->outopts->noval) - man_validate(man); + if (meta->macroset == MACROSET_MAN) { switch (curp->outtype) { case OUTT_HTML: - html_man(curp->outdata, man); + html_man(curp->outdata, meta); break; case OUTT_TREE: - tree_man(curp->outdata, man); + tree_man(curp->outdata, meta); break; case OUTT_MAN: - man_man(curp->outdata, man); + mparse_copy(curp->mp); break; case OUTT_PDF: case OUTT_ASCII: case OUTT_UTF8: case OUTT_LOCALE: case OUTT_PS: - terminal_man(curp->outdata, man); + terminal_man(curp->outdata, meta); break; default: break; } } - if (curp->mmin < MANDOCERR_STYLE) - check_xr(file); - mparse_updaterc(curp->mp, &rc); + if (mandoc_msg_getmin() < MANDOCERR_STYLE) + check_xr(); } static void -check_xr(const char *file) +check_xr(void) { static struct manpaths paths; struct mansearch search; struct mandoc_xr *xr; - char *cp; size_t sz; if (paths.sz == 0) @@ -915,13 +922,12 @@ check_xr(const char *file) if (fs_search(&search, &paths, 1, &xr->name, NULL, &sz)) continue; if (xr->count == 1) - mandoc_asprintf(&cp, "Xr %s %s", xr->name, xr->sec); + mandoc_msg(MANDOCERR_XR_BAD, xr->line, + xr->pos + 1, "Xr %s %s", xr->name, xr->sec); else - mandoc_asprintf(&cp, "Xr %s %s (%d times)", + mandoc_msg(MANDOCERR_XR_BAD, xr->line, + xr->pos + 1, "Xr %s %s (%d times)", xr->name, xr->sec, xr->count); - mmsg(MANDOCERR_XR_BAD, MANDOCLEVEL_STYLE, - file, xr->line, xr->pos + 1, cp); - free(cp); } } @@ -1020,8 +1026,7 @@ done: fail: free(line); warn("%s: SYSERR: %s", file, syscall); - if (rc < MANDOCLEVEL_SYSERR) - rc = MANDOCLEVEL_SYSERR; + mandoc_msg_setrc(MANDOCLEVEL_SYSERR); } static int @@ -1063,8 +1068,8 @@ toptions(struct curparse *curp, char *arg) curp->outtype = OUTT_ASCII; else if (0 == strcmp(arg, "lint")) { curp->outtype = OUTT_LINT; - curp->mmin = MANDOCERR_BASE; - mmsg_stream = stdout; + mandoc_msg_setoutfile(stdout); + mandoc_msg_setmin(MANDOCERR_BASE); } else if (0 == strcmp(arg, "tree")) curp->outtype = OUTT_TREE; else if (0 == strcmp(arg, "man")) @@ -1115,29 +1120,29 @@ woptions(struct curparse *curp, char *arg) break; case 1: case 2: - curp->mmin = MANDOCERR_BASE; + mandoc_msg_setmin(MANDOCERR_BASE); break; case 3: - curp->mmin = MANDOCERR_STYLE; + mandoc_msg_setmin(MANDOCERR_STYLE); break; case 4: - curp->mmin = MANDOCERR_WARNING; + mandoc_msg_setmin(MANDOCERR_WARNING); break; case 5: - curp->mmin = MANDOCERR_ERROR; + mandoc_msg_setmin(MANDOCERR_ERROR); break; case 6: - curp->mmin = MANDOCERR_UNSUPP; + mandoc_msg_setmin(MANDOCERR_UNSUPP); break; case 7: - curp->mmin = MANDOCERR_MAX; + mandoc_msg_setmin(MANDOCERR_MAX); break; case 8: - curp->mmin = MANDOCERR_BASE; + mandoc_msg_setmin(MANDOCERR_BASE); curp->os_e = MANDOC_OS_OPENBSD; break; case 9: - curp->mmin = MANDOCERR_BASE; + mandoc_msg_setmin(MANDOCERR_BASE); curp->os_e = MANDOC_OS_NETBSD; break; default: @@ -1148,29 +1153,6 @@ woptions(struct curparse *curp, char *arg) return 1; } -static void -mmsg(enum mandocerr t, enum mandoclevel lvl, - const char *file, int line, int col, const char *msg) -{ - const char *mparse_msg; - - fprintf(mmsg_stream, "%s: %s:", getprogname(), - file == NULL ? "<stdin>" : file); - - if (line) - fprintf(mmsg_stream, "%d:%d:", line, col + 1); - - fprintf(mmsg_stream, " %s", mparse_strlevel(lvl)); - - if ((mparse_msg = mparse_strerror(t)) != NULL) - fprintf(mmsg_stream, ": %s", mparse_msg); - - if (msg) - fprintf(mmsg_stream, ": %s", msg); - - fputc('\n', mmsg_stream); -} - static pid_t spawn_pager(struct tag_files *tag_files) { @@ -1179,8 +1161,10 @@ spawn_pager(struct tag_files *tag_files) char *argv[MAX_PAGER_ARGS]; const char *pager; char *cp; +#if HAVE_LESS_T size_t cmdlen; - int argc; +#endif + int argc, use_ofn; pid_t pager_pid; pager = getenv("MANPAGER"); @@ -1196,7 +1180,7 @@ spawn_pager(struct tag_files *tag_files) */ argc = 0; - while (argc + 4 < MAX_PAGER_ARGS) { + while (argc + 5 < MAX_PAGER_ARGS) { argv[argc++] = cp; cp = strchr(cp, ' '); if (cp == NULL) @@ -1210,14 +1194,23 @@ spawn_pager(struct tag_files *tag_files) /* For less(1), use the tag file. */ + use_ofn = 1; +#if HAVE_LESS_T if ((cmdlen = strlen(argv[0])) >= 4) { cp = argv[0] + cmdlen - 4; if (strcmp(cp, "less") == 0) { argv[argc++] = mandoc_strdup("-T"); argv[argc++] = tag_files->tfn; + if (tag_files->tagname != NULL) { + argv[argc++] = mandoc_strdup("-t"); + argv[argc++] = tag_files->tagname; + use_ofn = 0; + } } } - argv[argc++] = tag_files->ofn; +#endif + if (use_ofn) + argv[argc++] = tag_files->ofn; argv[argc] = NULL; switch (pager_pid = fork()) { diff --git a/usr/src/cmd/mandoc/main.h b/usr/src/cmd/mandoc/main.h index f9b8f135f8..19a630cde8 100644 --- a/usr/src/cmd/mandoc/main.h +++ b/usr/src/cmd/mandoc/main.h @@ -1,7 +1,7 @@ -/* $Id: main.h,v 1.27 2017/03/03 14:23:23 schwarze Exp $ */ +/* $Id: main.h,v 1.30 2019/03/03 13:02:11 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2014, 2015, 2019 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 @@ -16,7 +16,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -struct roff_man; +struct roff_meta; struct manoutput; /* @@ -27,15 +27,15 @@ struct manoutput; */ void *html_alloc(const struct manoutput *); -void html_mdoc(void *, const struct roff_man *); -void html_man(void *, const struct roff_man *); +void html_mdoc(void *, const struct roff_meta *); +void html_man(void *, const struct roff_meta *); +void html_reset(void *); void html_free(void *); -void tree_mdoc(void *, const struct roff_man *); -void tree_man(void *, const struct roff_man *); +void tree_mdoc(void *, const struct roff_meta *); +void tree_man(void *, const struct roff_meta *); -void man_mdoc(void *, const struct roff_man *); -void man_man(void *, const struct roff_man *); +void man_mdoc(void *, const struct roff_meta *); void *locale_alloc(const struct manoutput *); void *utf8_alloc(const struct manoutput *); @@ -46,8 +46,8 @@ void *pdf_alloc(const struct manoutput *); void *ps_alloc(const struct manoutput *); void pspdf_free(void *); -void terminal_mdoc(void *, const struct roff_man *); -void terminal_man(void *, const struct roff_man *); +void terminal_mdoc(void *, const struct roff_meta *); +void terminal_man(void *, const struct roff_meta *); void terminal_sepline(void *); -void markdown_mdoc(void *, const struct roff_man *); +void markdown_mdoc(void *, const struct roff_meta *); diff --git a/usr/src/cmd/mandoc/man.c b/usr/src/cmd/mandoc/man.c index 7a2bcc9688..f0e4002b2a 100644 --- a/usr/src/cmd/mandoc/man.c +++ b/usr/src/cmd/mandoc/man.c @@ -1,7 +1,7 @@ -/* $Id: man.c,v 1.176 2017/06/28 12:52:45 schwarze Exp $ */ +/* $Id: man.c,v 1.187 2019/01/05 00:36:50 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2013-2015, 2017-2019 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2011 Joerg Sonnenberger <joerg@netbsd.org> * * Permission to use, copy, modify, and distribute this software for any @@ -35,7 +35,7 @@ #include "roff_int.h" #include "libman.h" -static void man_descope(struct roff_man *, int, int); +static char *man_hasc(char *); static int man_ptext(struct roff_man *, int, char *, int); static int man_pmacro(struct roff_man *, int, char *, int); @@ -52,38 +52,62 @@ man_parseln(struct roff_man *man, int ln, char *buf, int offs) man_ptext(man, ln, buf, offs); } -static void -man_descope(struct roff_man *man, int line, int offs) +/* + * If the string ends with \c, return a pointer to the backslash. + * Otherwise, return NULL. + */ +static char * +man_hasc(char *start) { + char *cp, *ep; + + ep = strchr(start, '\0') - 2; + if (ep < start || ep[0] != '\\' || ep[1] != 'c') + return NULL; + for (cp = ep; cp > start; cp--) + if (cp[-1] != '\\') + break; + return (ep - cp) % 2 ? NULL : ep; +} + +void +man_descope(struct roff_man *man, int line, int offs, char *start) +{ + /* Trailing \c keeps next-line scope open. */ + + if (start != NULL && man_hasc(start) != NULL) + return; + /* * Co-ordinate what happens with having a next-line scope open: - * first close out the element scope (if applicable), then close - * out the block scope (also if applicable). + * first close out the element scopes (if applicable), + * then close out the block scope (also if applicable). */ if (man->flags & MAN_ELINE) { + while (man->last->parent->type != ROFFT_ROOT && + man_macro(man->last->parent->tok)->flags & MAN_ESCOPED) + man_unscope(man, man->last->parent); man->flags &= ~MAN_ELINE; - man_unscope(man, man->last->parent); } if ( ! (man->flags & MAN_BLINE)) return; - man->flags &= ~MAN_BLINE; man_unscope(man, man->last->parent); roff_body_alloc(man, line, offs, man->last->tok); + man->flags &= ~(MAN_BLINE | ROFF_NONOFILL); } static int man_ptext(struct roff_man *man, int line, char *buf, int offs) { int i; - const char *cp, *sp; char *ep; - /* Literal free-form text whitespace is preserved. */ + /* In no-fill mode, whitespace is preserved on text lines. */ - if (man->flags & MAN_LITERAL) { + if (man->flags & ROFF_NOFILL) { roff_word_alloc(man, line, offs, buf + offs); - man_descope(man, line, offs); + man_descope(man, line, offs, buf + offs); return 1; } @@ -98,26 +122,15 @@ man_ptext(struct roff_man *man, int line, char *buf, int offs) if (buf[i] == '\0') { if (man->flags & (MAN_ELINE | MAN_BLINE)) { - mandoc_msg(MANDOCERR_BLK_BLANK, man->parse, - line, 0, NULL); + mandoc_msg(MANDOCERR_BLK_BLANK, line, 0, NULL); return 1; } if (man->last->tok == MAN_SH || man->last->tok == MAN_SS) return 1; - switch (man->last->type) { - case ROFFT_TEXT: - sp = man->last->string; - cp = ep = strchr(sp, '\0') - 2; - if (cp < sp || cp[0] != '\\' || cp[1] != 'c') - break; - while (cp > sp && cp[-1] == '\\') - cp--; - if ((ep - cp) % 2) - break; + if (man->last->type == ROFFT_TEXT && + ((ep = man_hasc(man->last->string)) != NULL)) { *ep = '\0'; return 1; - default: - break; } roff_elem_alloc(man, line, offs, ROFF_sp); man->next = ROFF_NEXT_SIBLING; @@ -134,8 +147,7 @@ man_ptext(struct roff_man *man, int line, char *buf, int offs) if (' ' == buf[i - 1] || '\t' == buf[i - 1]) { if (i > 1 && '\\' != buf[i - 2]) - mandoc_msg(MANDOCERR_SPACE_EOL, man->parse, - line, i - 1, NULL); + mandoc_msg(MANDOCERR_SPACE_EOL, line, i - 1, NULL); for (--i; i && ' ' == buf[i]; i--) /* Spin back to non-space. */ ; @@ -157,7 +169,7 @@ man_ptext(struct roff_man *man, int line, char *buf, int offs) if (mandoc_eos(buf, (size_t)i)) man->last->flags |= NODE_EOS; - man_descope(man, line, offs); + man_descope(man, line, offs, buf + offs); return 1; } @@ -180,8 +192,7 @@ man_pmacro(struct roff_man *man, int ln, char *buf, int offs) if (sz > 0 && sz < 4) tok = roffhash_find(man->manmac, buf + ppos, sz); if (tok == TOKEN_NONE) { - mandoc_msg(MANDOCERR_MACRO, man->parse, - ln, ppos, buf + ppos - 1); + mandoc_msg(MANDOCERR_MACRO, ln, ppos, "%s", buf + ppos - 1); return 1; } @@ -211,8 +222,7 @@ man_pmacro(struct roff_man *man, int ln, char *buf, int offs) */ if (buf[offs] == '\0' && buf[offs - 1] == ' ') - mandoc_msg(MANDOCERR_SPACE_EOL, man->parse, - ln, offs - 1, NULL); + mandoc_msg(MANDOCERR_SPACE_EOL, ln, offs - 1, NULL); /* * Some macros break next-line scopes; otherwise, remember @@ -230,16 +240,12 @@ man_pmacro(struct roff_man *man, int ln, char *buf, int offs) * page, that's very likely what the author intended. */ - if (bline) { - cp = strchr(buf + offs, '\0') - 2; - if (cp >= buf && cp[0] == '\\' && cp[1] == 'c') - bline = 0; - } + if (bline && man_hasc(buf + offs)) + bline = 0; /* Call to handler... */ - assert(man_macros[tok].fp); - (*man_macros[tok].fp)(man, tok, ln, ppos, &offs, buf); + (*man_macro(tok)->fp)(man, tok, ln, ppos, &offs, buf); /* In quick mode (for mandocdb), abort after the NAME section. */ @@ -256,15 +262,15 @@ man_pmacro(struct roff_man *man, int ln, char *buf, int offs) * unless the next-line scope is allowed to continue. */ - if ( ! bline || man->flags & MAN_ELINE || - man_macros[tok].flags & MAN_NSCOPED) + if (bline == 0 || + (man->flags & MAN_BLINE) == 0 || + man->flags & MAN_ELINE || + man_macro(tok)->flags & MAN_NSCOPED) return 1; - assert(man->flags & MAN_BLINE); - man->flags &= ~MAN_BLINE; - man_unscope(man, man->last->parent); roff_body_alloc(man, ln, ppos, man->last->tok); + man->flags &= ~(MAN_BLINE | ROFF_NONOFILL); return 1; } @@ -280,17 +286,17 @@ man_breakscope(struct roff_man *man, int tok) */ if (man->flags & MAN_ELINE && (tok < MAN_TH || - ! (man_macros[tok].flags & MAN_NSCOPED))) { + (man_macro(tok)->flags & MAN_NSCOPED) == 0)) { n = man->last; if (n->type == ROFFT_TEXT) n = n->parent; if (n->tok < MAN_TH || - man_macros[n->tok].flags & MAN_NSCOPED) + (man_macro(n->tok)->flags & (MAN_NSCOPED | MAN_ESCOPED)) + == MAN_NSCOPED) n = n->parent; - mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse, - n->line, n->pos, "%s breaks %s", - roff_name[tok], roff_name[n->tok]); + mandoc_msg(MANDOCERR_BLK_LINE, n->line, n->pos, + "%s breaks %s", roff_name[tok], roff_name[n->tok]); roff_node_delete(man, n); man->flags &= ~MAN_ELINE; @@ -302,12 +308,12 @@ man_breakscope(struct roff_man *man, int tok) */ if (man->flags & MAN_BLINE && - (tok == MAN_nf || tok == MAN_fi) && + (tok == ROFF_nf || tok == ROFF_fi) && (man->last->tok == MAN_SH || man->last->tok == MAN_SS)) { n = man->last; man_unscope(man, n); roff_body_alloc(man, n->line, n->pos, n->tok); - man->flags &= ~MAN_BLINE; + man->flags &= ~(MAN_BLINE | ROFF_NONOFILL); } /* @@ -316,68 +322,24 @@ man_breakscope(struct roff_man *man, int tok) * Delete the block that is being broken. */ - if (man->flags & MAN_BLINE && (tok < MAN_TH || - man_macros[tok].flags & MAN_BSCOPE)) { + if (man->flags & MAN_BLINE && tok != ROFF_nf && tok != ROFF_fi && + (tok < MAN_TH || man_macro(tok)->flags & MAN_XSCOPE)) { n = man->last; if (n->type == ROFFT_TEXT) n = n->parent; if (n->tok < MAN_TH || - (man_macros[n->tok].flags & MAN_BSCOPE) == 0) + (man_macro(n->tok)->flags & MAN_XSCOPE) == 0) n = n->parent; assert(n->type == ROFFT_HEAD); n = n->parent; assert(n->type == ROFFT_BLOCK); - assert(man_macros[n->tok].flags & MAN_SCOPED); + assert(man_macro(n->tok)->flags & MAN_BSCOPED); - mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse, - n->line, n->pos, "%s breaks %s", - roff_name[tok], roff_name[n->tok]); + mandoc_msg(MANDOCERR_BLK_LINE, n->line, n->pos, + "%s breaks %s", roff_name[tok], roff_name[n->tok]); roff_node_delete(man, n); - man->flags &= ~MAN_BLINE; + man->flags &= ~(MAN_BLINE | ROFF_NONOFILL); } } - -const struct mparse * -man_mparse(const struct roff_man *man) -{ - - assert(man && man->parse); - return man->parse; -} - -void -man_state(struct roff_man *man, struct roff_node *n) -{ - - switch(n->tok) { - case MAN_nf: - case MAN_EX: - if (man->flags & MAN_LITERAL && ! (n->flags & NODE_VALID)) - mandoc_msg(MANDOCERR_NF_SKIP, man->parse, - n->line, n->pos, "nf"); - man->flags |= MAN_LITERAL; - break; - case MAN_fi: - case MAN_EE: - if ( ! (man->flags & MAN_LITERAL) && - ! (n->flags & NODE_VALID)) - mandoc_msg(MANDOCERR_FI_SKIP, man->parse, - n->line, n->pos, "fi"); - man->flags &= ~MAN_LITERAL; - break; - default: - break; - } - man->last->flags |= NODE_VALID; -} - -void -man_validate(struct roff_man *man) -{ - - man->last = man->first; - man_node_validate(man); - man->flags &= ~MAN_LITERAL; -} diff --git a/usr/src/cmd/mandoc/man.h b/usr/src/cmd/mandoc/man.h index d671f9a9e4..ed4375c0c0 100644 --- a/usr/src/cmd/mandoc/man.h +++ b/usr/src/cmd/mandoc/man.h @@ -1,4 +1,4 @@ -/* $Id: man.h,v 1.78 2017/04/24 23:06:18 schwarze Exp $ */ +/* $Id: man.h,v 1.79 2018/08/23 19:33:27 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org> @@ -18,5 +18,4 @@ struct roff_man; -const struct mparse *man_mparse(const struct roff_man *); void man_validate(struct roff_man *); diff --git a/usr/src/cmd/mandoc/man_html.c b/usr/src/cmd/mandoc/man_html.c index ae5dac1ad9..994a208aa0 100644 --- a/usr/src/cmd/mandoc/man_html.c +++ b/usr/src/cmd/mandoc/man_html.c @@ -1,7 +1,7 @@ -/* $Id: man_html.c,v 1.153 2018/07/27 17:49:31 schwarze Exp $ */ +/* $Id: man_html.c,v 1.173 2019/03/02 16:30:53 schwarze Exp $ */ /* * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2013,2014,2015,2017,2018 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2013-2015, 2017-2019 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 @@ -33,26 +33,22 @@ #include "html.h" #include "main.h" -/* FIXME: have PD set the default vspace width. */ - #define MAN_ARGS const struct roff_meta *man, \ const struct roff_node *n, \ struct html *h -struct htmlman { +struct man_html_act { int (*pre)(MAN_ARGS); int (*post)(MAN_ARGS); }; -static void print_bvspace(struct html *, - const struct roff_node *); 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 char list_continues(const struct roff_node *, + const struct roff_node *); static int man_B_pre(MAN_ARGS); -static int man_HP_pre(MAN_ARGS); static int man_IP_pre(MAN_ARGS); static int man_I_pre(MAN_ARGS); static int man_OP_pre(MAN_ARGS); @@ -60,8 +56,9 @@ static int man_PP_pre(MAN_ARGS); static int man_RS_pre(MAN_ARGS); static int man_SH_pre(MAN_ARGS); static int man_SM_pre(MAN_ARGS); -static int man_SS_pre(MAN_ARGS); +static int man_SY_pre(MAN_ARGS); static int man_UR_pre(MAN_ARGS); +static int man_abort_pre(MAN_ARGS); static int man_alt_pre(MAN_ARGS); static int man_ign_pre(MAN_ARGS); static int man_in_pre(MAN_ARGS); @@ -70,16 +67,17 @@ static void man_root_post(const struct roff_meta *, static void man_root_pre(const struct roff_meta *, struct html *); -static const struct htmlman __mans[MAN_MAX - MAN_TH] = { +static const struct man_html_act man_html_acts[MAN_MAX - MAN_TH] = { { NULL, NULL }, /* TH */ { man_SH_pre, NULL }, /* SH */ - { man_SS_pre, NULL }, /* SS */ + { man_SH_pre, NULL }, /* SS */ { man_IP_pre, NULL }, /* TP */ - { man_PP_pre, NULL }, /* LP */ + { man_IP_pre, NULL }, /* TQ */ + { man_abort_pre, NULL }, /* LP */ { man_PP_pre, NULL }, /* PP */ - { man_PP_pre, NULL }, /* P */ + { man_abort_pre, NULL }, /* P */ { man_IP_pre, NULL }, /* IP */ - { man_HP_pre, NULL }, /* HP */ + { man_PP_pre, NULL }, /* HP */ { man_SM_pre, NULL }, /* SM */ { man_SM_pre, NULL }, /* SB */ { man_alt_pre, NULL }, /* BI */ @@ -91,8 +89,6 @@ static const struct htmlman __mans[MAN_MAX - MAN_TH] = { { man_I_pre, NULL }, /* I */ { man_alt_pre, NULL }, /* IR */ { man_alt_pre, NULL }, /* RI */ - { NULL, NULL }, /* nf */ - { NULL, NULL }, /* fi */ { NULL, NULL }, /* RE */ { man_RS_pre, NULL }, /* RS */ { man_ign_pre, NULL }, /* DT */ @@ -100,6 +96,8 @@ static const struct htmlman __mans[MAN_MAX - MAN_TH] = { { man_ign_pre, NULL }, /* PD */ { man_ign_pre, NULL }, /* AT */ { man_in_pre, NULL }, /* in */ + { man_SY_pre, NULL }, /* SY */ + { NULL, NULL }, /* YS */ { man_OP_pre, NULL }, /* OP */ { NULL, NULL }, /* EX */ { NULL, NULL }, /* EE */ @@ -108,34 +106,10 @@ static const struct htmlman __mans[MAN_MAX - MAN_TH] = { { man_UR_pre, NULL }, /* MT */ { NULL, NULL }, /* ME */ }; -static const struct htmlman *const mans = __mans - MAN_TH; - - -/* - * Printing leading vertical space before a block. - * This is used for the paragraph macros. - * The rules are pretty simple, since there's very little nesting going - * on here. Basically, if we're the first within another block (SS/SH), - * then don't emit vertical space. If we are (RS), then do. If not the - * first, print it. - */ -static void -print_bvspace(struct html *h, const struct roff_node *n) -{ - if (n->body && n->body->child) - if (n->body->child->type == ROFFT_TBL) - return; - - if (n->parent->type == ROFFT_ROOT || n->parent->tok != MAN_RS) - if (NULL == n->prev) - return; - - print_paragraph(h); -} void -html_man(void *arg, const struct roff_man *man) +html_man(void *arg, const struct roff_meta *man) { struct html *h; struct roff_node *n; @@ -147,19 +121,19 @@ html_man(void *arg, const struct roff_man *man) if ((h->oflags & HTML_FRAGMENT) == 0) { print_gen_decls(h); print_otag(h, TAG_HTML, ""); - if (n->type == ROFFT_COMMENT) + if (n != NULL && n->type == ROFFT_COMMENT) print_gen_comment(h, n); t = print_otag(h, TAG_HEAD, ""); - print_man_head(&man->meta, h); + print_man_head(man, h); print_tagq(h, t); print_otag(h, TAG_BODY, ""); } - man_root_pre(&man->meta, h); + man_root_pre(man, h); t = print_otag(h, TAG_DIV, "c", "manual-text"); - print_man_nodelist(&man->meta, n, h); + print_man_nodelist(man, n, h); print_tagq(h, t); - man_root_post(&man->meta, h); + man_root_post(man, h); print_tagq(h, NULL); } @@ -178,7 +152,6 @@ print_man_head(const struct roff_meta *man, struct html *h) static void print_man_nodelist(MAN_ARGS) { - while (n != NULL) { print_man_node(man, n, h); n = n->next; @@ -188,99 +161,33 @@ print_man_nodelist(MAN_ARGS) static void print_man_node(MAN_ARGS) { - static int want_fillmode = MAN_fi; - static int save_fillmode; - struct tag *t; int child; - /* - * Handle fill mode switch requests up front, - * they would just cause trouble in the subsequent code. - */ - - switch (n->tok) { - case MAN_nf: - case MAN_EX: - want_fillmode = MAN_nf; + if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT) return; - case MAN_fi: - case MAN_EE: - want_fillmode = MAN_fi; - if (fillmode(h, 0) == MAN_fi) - print_otag(h, TAG_BR, ""); - return; - default: - break; - } - /* Set up fill mode for the upcoming node. */ - - switch (n->type) { - case ROFFT_BLOCK: - save_fillmode = 0; - /* Some block macros suspend or cancel .nf. */ - switch (n->tok) { - case MAN_TP: /* Tagged paragraphs */ - case MAN_IP: /* temporarily disable .nf */ - case MAN_HP: /* for the head. */ - save_fillmode = want_fillmode; - /* FALLTHROUGH */ - case MAN_SH: /* Section headers */ - case MAN_SS: /* permanently cancel .nf. */ - want_fillmode = MAN_fi; - /* FALLTHROUGH */ - case MAN_PP: /* These have no head. */ - case MAN_LP: /* They will simply */ - case MAN_P: /* reopen .nf in the body. */ - case MAN_RS: - case MAN_UR: - case MAN_MT: - fillmode(h, MAN_fi); - break; - default: - break; - } - break; - case ROFFT_TBL: - fillmode(h, MAN_fi); - break; - case ROFFT_ELEM: - /* - * Some in-line macros produce tags and/or text - * in the handler, so they require fill mode to be - * configured up front just like for text nodes. - * For the others, keep the traditional approach - * of doing the same, for now. - */ - fillmode(h, want_fillmode); - break; - case ROFFT_TEXT: - if (fillmode(h, want_fillmode) == MAN_fi && - want_fillmode == MAN_fi && - n->flags & NODE_LINE && *n->string == ' ' && - (h->flags & HTML_NONEWLINE) == 0) - print_otag(h, TAG_BR, ""); - if (*n->string != '\0') - break; - print_paragraph(h); - return; - case ROFFT_COMMENT: - return; - default: - break; - } - - /* Produce output for this node. */ + html_fillmode(h, n->flags & NODE_NOFILL ? ROFF_nf : ROFF_fi); child = 1; switch (n->type) { case ROFFT_TEXT: + if (*n->string == '\0') { + print_endline(h); + return; + } + if (*n->string == ' ' && n->flags & NODE_LINE && + (h->flags & HTML_NONEWLINE) == 0) + print_endline(h); + else if (n->flags & NODE_DELIMC) + h->flags |= HTML_NOSPACE; t = h->tag; + t->refcnt++; print_text(h, n->string); break; case ROFFT_EQN: t = h->tag; + t->refcnt++; print_eqn(h, n->eqn); break; case ROFFT_TBL: @@ -306,62 +213,51 @@ print_man_node(MAN_ARGS) * the "meta" table state. This will be reopened on the * next table element. */ - if (h->tblt) + if (h->tblt != NULL) print_tblclose(h); - t = h->tag; + t->refcnt++; if (n->tok < ROFF_MAX) { roff_html_pre(h, n); - child = 0; - break; + t->refcnt--; + print_stagq(h, t); + return; } - assert(n->tok >= MAN_TH && n->tok < MAN_MAX); - if (mans[n->tok].pre) - child = (*mans[n->tok].pre)(man, n, h); - - /* Some block macros resume .nf in the body. */ - if (save_fillmode && n->type == ROFFT_BODY) - want_fillmode = save_fillmode; - + if (man_html_acts[n->tok - MAN_TH].pre != NULL) + child = (*man_html_acts[n->tok - MAN_TH].pre)(man, + n, h); break; } - if (child && n->child) + if (child && n->child != NULL) print_man_nodelist(man, n->child, h); /* This will automatically close out any font scope. */ - print_stagq(h, t); + t->refcnt--; + if (n->type == ROFFT_BLOCK && + (n->tok == MAN_IP || n->tok == MAN_TP || n->tok == MAN_TQ)) { + t = h->tag; + while (t->tag != TAG_DL && t->tag != TAG_UL) + t = t->next; + /* + * Close the list if no further item of the same type + * follows; otherwise, close the item only. + */ + if (list_continues(n, n->next) == '\0') { + print_tagq(h, t); + t = NULL; + } + } + if (t != NULL) + print_stagq(h, t); - if (fillmode(h, 0) == MAN_nf && - n->next != NULL && n->next->flags & NODE_LINE) + if (n->flags & NODE_NOFILL && n->tok != MAN_YS && + (n->next != NULL && n->next->flags & NODE_LINE)) { + /* In .nf = <pre>, print even empty lines. */ + h->col++; print_endline(h); -} - -/* - * MAN_nf switches to no-fill mode, MAN_fi to fill mode. - * Other arguments do not switch. - * The old mode is returned. - */ -static int -fillmode(struct html *h, int want) -{ - struct tag *pre; - int had; - - for (pre = h->tag; pre != NULL; pre = pre->next) - if (pre->tag == TAG_PRE) - break; - - had = pre == NULL ? MAN_fi : MAN_nf; - - if (want && want != had) { - if (want == MAN_nf) - print_otag(h, TAG_PRE, ""); - else - print_tagq(h, pre); } - return had; } static void @@ -382,7 +278,7 @@ man_root_pre(const struct roff_meta *man, struct html *h) print_stagq(h, tt); print_otag(h, TAG_TD, "c", "head-vol"); - if (NULL != man->vol) + if (man->vol != NULL) print_text(h, man->vol); print_stagq(h, tt); @@ -405,7 +301,7 @@ man_root_post(const struct roff_meta *man, struct html *h) print_stagq(h, tt); print_otag(h, TAG_TD, "c", "foot-os"); - if (man->os) + if (man->os != NULL) print_text(h, man->os); print_tagq(h, t); } @@ -413,13 +309,32 @@ man_root_post(const struct roff_meta *man, struct html *h) static int man_SH_pre(MAN_ARGS) { - char *id; - - if (n->type == ROFFT_HEAD) { + const char *class; + char *id; + enum htmltag tag; + + if (n->tok == MAN_SH) { + tag = TAG_H1; + class = "Sh"; + } else { + tag = TAG_H2; + class = "Ss"; + } + switch (n->type) { + case ROFFT_BLOCK: + html_close_paragraph(h); + print_otag(h, TAG_SECTION, "c", class); + break; + case ROFFT_HEAD: id = html_make_id(n, 1); - print_otag(h, TAG_H1, "cTi", "Sh", id); + print_otag(h, tag, "ci", class, id); if (id != NULL) print_otag(h, TAG_A, "chR", "permalink", id); + break; + case ROFFT_BODY: + break; + default: + abort(); } return 1; } @@ -428,11 +343,11 @@ static int man_alt_pre(MAN_ARGS) { const struct roff_node *nn; + struct tag *t; int i; enum htmltag fp; - struct tag *t; - for (i = 0, nn = n->child; nn; nn = nn->next, i++) { + for (i = 0, nn = n->child; nn != NULL; nn = nn->next, i++) { switch (n->tok) { case MAN_BI: fp = i % 2 ? TAG_I : TAG_B; @@ -474,88 +389,135 @@ static int man_SM_pre(MAN_ARGS) { print_otag(h, TAG_SMALL, ""); - if (MAN_SB == n->tok) + if (n->tok == MAN_SB) print_otag(h, TAG_B, ""); return 1; } static int -man_SS_pre(MAN_ARGS) +man_PP_pre(MAN_ARGS) { - char *id; - - if (n->type == ROFFT_HEAD) { - id = html_make_id(n, 1); - print_otag(h, TAG_H2, "cTi", "Ss", id); - if (id != NULL) - print_otag(h, TAG_A, "chR", "permalink", id); + switch (n->type) { + case ROFFT_BLOCK: + html_close_paragraph(h); + break; + case ROFFT_HEAD: + return 0; + case ROFFT_BODY: + if (n->child != NULL && + (n->child->flags & NODE_NOFILL) == 0) + print_otag(h, TAG_P, "c", + n->tok == MAN_PP ? "Pp" : "Pp HP"); + break; + default: + abort(); } return 1; } -static int -man_PP_pre(MAN_ARGS) +static char +list_continues(const struct roff_node *n1, const struct roff_node *n2) { - - if (n->type == ROFFT_HEAD) - return 0; - else if (n->type == ROFFT_BLOCK) - print_bvspace(h, n); - - return 1; + const char *s1, *s2; + char c1, c2; + + if (n1 == NULL || n1->type != ROFFT_BLOCK || + n2 == NULL || n2->type != ROFFT_BLOCK) + return '\0'; + if ((n1->tok == MAN_TP || n1->tok == MAN_TQ) && + (n2->tok == MAN_TP || n2->tok == MAN_TQ)) + return ' '; + if (n1->tok != MAN_IP || n2->tok != MAN_IP) + return '\0'; + n1 = n1->head->child; + n2 = n2->head->child; + s1 = n1 == NULL ? "" : n1->string; + s2 = n2 == NULL ? "" : n2->string; + c1 = strcmp(s1, "*") == 0 ? '*' : + strcmp(s1, "\\-") == 0 ? '-' : + strcmp(s1, "\\(bu") == 0 ? 'b' : ' '; + c2 = strcmp(s2, "*") == 0 ? '*' : + strcmp(s2, "\\-") == 0 ? '-' : + strcmp(s2, "\\(bu") == 0 ? 'b' : ' '; + return c1 != c2 ? '\0' : c1 == 'b' ? '*' : c1; } static int man_IP_pre(MAN_ARGS) { const struct roff_node *nn; + const char *list_class; + enum htmltag list_elem, body_elem; + char list_type; + + nn = n->type == ROFFT_BLOCK ? n : n->parent; + if ((list_type = list_continues(nn->prev, nn)) == '\0') { + /* Start a new list. */ + if ((list_type = list_continues(nn, nn->next)) == '\0') + list_type = ' '; + switch (list_type) { + case ' ': + list_class = "Bl-tag"; + list_elem = TAG_DL; + break; + case '*': + list_class = "Bl-bullet"; + list_elem = TAG_UL; + break; + case '-': + list_class = "Bl-dash"; + list_elem = TAG_UL; + break; + default: + abort(); + } + } else { + /* Continue a list that was started earlier. */ + list_class = NULL; + list_elem = TAG_MAX; + } + body_elem = list_type == ' ' ? TAG_DD : TAG_LI; - if (n->type == ROFFT_BODY) { - print_otag(h, TAG_DD, ""); + switch (n->type) { + case ROFFT_BLOCK: + html_close_paragraph(h); + if (list_elem != TAG_MAX) + print_otag(h, list_elem, "c", list_class); return 1; - } else if (n->type != ROFFT_HEAD) { - print_otag(h, TAG_DL, "c", "Bl-tag"); + case ROFFT_HEAD: + if (body_elem == TAG_LI) + return 0; + print_otag(h, TAG_DT, ""); + break; + case ROFFT_BODY: + print_otag(h, body_elem, ""); return 1; + default: + abort(); } - /* FIXME: width specification. */ - - print_otag(h, TAG_DT, ""); - - /* For IP, only print the first header element. */ - - if (MAN_IP == n->tok && n->child) - print_man_node(man, n->child, h); - - /* For TP, only print next-line header elements. */ - - if (MAN_TP == n->tok) { + switch(n->tok) { + case MAN_IP: /* Only print the first header element. */ + if (n->child != NULL) + print_man_node(man, n->child, h); + break; + case MAN_TP: /* Only print next-line header elements. */ + case MAN_TQ: nn = n->child; - while (NULL != nn && 0 == (NODE_LINE & nn->flags)) + while (nn != NULL && (NODE_LINE & nn->flags) == 0) nn = nn->next; - while (NULL != nn) { + while (nn != NULL) { print_man_node(man, nn, h); nn = nn->next; } + break; + default: + abort(); } - return 0; } static int -man_HP_pre(MAN_ARGS) -{ - if (n->type == ROFFT_HEAD) - return 0; - - if (n->type == ROFFT_BLOCK) { - print_bvspace(h, n); - print_otag(h, TAG_DIV, "c", "HP"); - } - return 1; -} - -static int man_OP_pre(MAN_ARGS) { struct tag *tt; @@ -564,14 +526,14 @@ man_OP_pre(MAN_ARGS) h->flags |= HTML_NOSPACE; tt = print_otag(h, TAG_SPAN, "c", "Op"); - if (NULL != (n = n->child)) { + if ((n = n->child) != NULL) { print_otag(h, TAG_B, ""); print_text(h, n->string); } print_stagq(h, tt); - if (NULL != n && NULL != n->next) { + if (n != NULL && n->next != NULL) { print_otag(h, TAG_I, ""); print_text(h, n->next->string); } @@ -606,17 +568,46 @@ man_in_pre(MAN_ARGS) static int man_ign_pre(MAN_ARGS) { - return 0; } static int man_RS_pre(MAN_ARGS) { - if (n->type == ROFFT_HEAD) + switch (n->type) { + case ROFFT_BLOCK: + html_close_paragraph(h); + break; + case ROFFT_HEAD: return 0; - if (n->type == ROFFT_BLOCK) + case ROFFT_BODY: print_otag(h, TAG_DIV, "c", "Bd-indent"); + break; + default: + abort(); + } + return 1; +} + +static int +man_SY_pre(MAN_ARGS) +{ + switch (n->type) { + case ROFFT_BLOCK: + html_close_paragraph(h); + print_otag(h, TAG_TABLE, "c", "Nm"); + print_otag(h, TAG_TR, ""); + break; + case ROFFT_HEAD: + print_otag(h, TAG_TD, ""); + print_otag(h, TAG_CODE, "c", "Nm"); + break; + case ROFFT_BODY: + print_otag(h, TAG_TD, ""); + break; + default: + abort(); + } return 1; } @@ -624,16 +615,17 @@ static int man_UR_pre(MAN_ARGS) { char *cp; + n = n->child; assert(n->type == ROFFT_HEAD); if (n->child != NULL) { assert(n->child->type == ROFFT_TEXT); if (n->tok == MAN_MT) { mandoc_asprintf(&cp, "mailto:%s", n->child->string); - print_otag(h, TAG_A, "cTh", "Mt", cp); + print_otag(h, TAG_A, "ch", "Mt", cp); free(cp); } else - print_otag(h, TAG_A, "cTh", "Lk", n->child->string); + print_otag(h, TAG_A, "ch", "Lk", n->child->string); } assert(n->next->type == ROFFT_BODY); @@ -641,6 +633,11 @@ man_UR_pre(MAN_ARGS) n = n->next; print_man_nodelist(man, n->child, h); - return 0; } + +static int +man_abort_pre(MAN_ARGS) +{ + abort(); +} diff --git a/usr/src/cmd/mandoc/man_macro.c b/usr/src/cmd/mandoc/man_macro.c index aa8b200196..d195576dee 100644 --- a/usr/src/cmd/mandoc/man_macro.c +++ b/usr/src/cmd/mandoc/man_macro.c @@ -1,7 +1,7 @@ -/* $Id: man_macro.c,v 1.123 2017/06/25 11:45:37 schwarze Exp $ */ +/* $Id: man_macro.c,v 1.144 2019/01/05 18:59:46 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2012-2015, 2017 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2012-2015, 2017-2019 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de> * * Permission to use, copy, modify, and distribute this software for any @@ -22,6 +22,7 @@ #include <assert.h> #include <ctype.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> @@ -40,47 +41,54 @@ static int man_args(struct roff_man *, int, int *, char *, char **); static void rew_scope(struct roff_man *, enum roff_tok); -const struct man_macro __man_macros[MAN_MAX - MAN_TH] = { - { in_line_eoln, MAN_BSCOPE }, /* TH */ - { blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* SH */ - { blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* SS */ - { blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* TP */ - { blk_imp, MAN_BSCOPE }, /* LP */ - { blk_imp, MAN_BSCOPE }, /* PP */ - { blk_imp, MAN_BSCOPE }, /* P */ - { blk_imp, MAN_BSCOPE }, /* IP */ - { blk_imp, MAN_BSCOPE }, /* HP */ - { in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* SM */ - { in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* SB */ +static const struct man_macro man_macros[MAN_MAX - MAN_TH] = { + { in_line_eoln, MAN_XSCOPE }, /* TH */ + { blk_imp, MAN_XSCOPE | MAN_BSCOPED }, /* SH */ + { blk_imp, MAN_XSCOPE | MAN_BSCOPED }, /* SS */ + { blk_imp, MAN_XSCOPE | MAN_BSCOPED }, /* TP */ + { blk_imp, MAN_XSCOPE | MAN_BSCOPED }, /* TQ */ + { blk_imp, MAN_XSCOPE }, /* LP */ + { blk_imp, MAN_XSCOPE }, /* PP */ + { blk_imp, MAN_XSCOPE }, /* P */ + { blk_imp, MAN_XSCOPE }, /* IP */ + { blk_imp, MAN_XSCOPE }, /* HP */ + { in_line_eoln, MAN_NSCOPED | MAN_ESCOPED | MAN_JOIN }, /* SM */ + { in_line_eoln, MAN_NSCOPED | MAN_ESCOPED | MAN_JOIN }, /* SB */ { in_line_eoln, 0 }, /* BI */ { in_line_eoln, 0 }, /* IB */ { in_line_eoln, 0 }, /* BR */ { in_line_eoln, 0 }, /* RB */ - { in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* R */ - { in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* B */ - { in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* I */ + { in_line_eoln, MAN_NSCOPED | MAN_ESCOPED | MAN_JOIN }, /* R */ + { in_line_eoln, MAN_NSCOPED | MAN_ESCOPED | MAN_JOIN }, /* B */ + { in_line_eoln, MAN_NSCOPED | MAN_ESCOPED | MAN_JOIN }, /* I */ { in_line_eoln, 0 }, /* IR */ { in_line_eoln, 0 }, /* RI */ - { in_line_eoln, MAN_NSCOPED }, /* nf */ - { in_line_eoln, MAN_NSCOPED }, /* fi */ - { blk_close, MAN_BSCOPE }, /* RE */ - { blk_exp, MAN_BSCOPE }, /* RS */ + { blk_close, MAN_XSCOPE }, /* RE */ + { blk_exp, MAN_XSCOPE }, /* RS */ { in_line_eoln, 0 }, /* DT */ { in_line_eoln, 0 }, /* UC */ { in_line_eoln, MAN_NSCOPED }, /* PD */ { in_line_eoln, 0 }, /* AT */ { in_line_eoln, MAN_NSCOPED }, /* in */ + { blk_imp, MAN_XSCOPE }, /* SY */ + { blk_close, MAN_XSCOPE }, /* YS */ { in_line_eoln, 0 }, /* OP */ - { in_line_eoln, MAN_BSCOPE }, /* EX */ - { in_line_eoln, MAN_BSCOPE }, /* EE */ - { blk_exp, MAN_BSCOPE }, /* UR */ - { blk_close, MAN_BSCOPE }, /* UE */ - { blk_exp, MAN_BSCOPE }, /* MT */ - { blk_close, MAN_BSCOPE }, /* ME */ + { in_line_eoln, MAN_XSCOPE }, /* EX */ + { in_line_eoln, MAN_XSCOPE }, /* EE */ + { blk_exp, MAN_XSCOPE }, /* UR */ + { blk_close, MAN_XSCOPE }, /* UE */ + { blk_exp, MAN_XSCOPE }, /* MT */ + { blk_close, MAN_XSCOPE }, /* ME */ }; -const struct man_macro *const man_macros = __man_macros - MAN_TH; +const struct man_macro * +man_macro(enum roff_tok tok) +{ + assert(tok >= MAN_TH && tok <= MAN_MAX); + return man_macros + (tok - MAN_TH); +} + void man_unscope(struct roff_man *man, const struct roff_node *to) { @@ -94,9 +102,10 @@ man_unscope(struct roff_man *man, const struct roff_node *to) if (to == NULL && ! (n->flags & NODE_VALID)) { if (man->flags & (MAN_BLINE | MAN_ELINE) && - man_macros[n->tok].flags & MAN_SCOPED) { - mandoc_vmsg(MANDOCERR_BLK_LINE, - man->parse, n->line, n->pos, + man_macro(n->tok)->flags & + (MAN_BSCOPED | MAN_NSCOPED)) { + mandoc_msg(MANDOCERR_BLK_LINE, + n->line, n->pos, "EOF breaks %s", roff_name[n->tok]); if (man->flags & MAN_ELINE) man->flags &= ~MAN_ELINE; @@ -111,9 +120,9 @@ man_unscope(struct roff_man *man, const struct roff_node *to) continue; } if (n->type == ROFFT_BLOCK && - man_macros[n->tok].fp == blk_exp) + man_macro(n->tok)->fp == blk_exp) mandoc_msg(MANDOCERR_BLK_NOEND, - man->parse, n->line, n->pos, + n->line, n->pos, "%s", roff_name[n->tok]); } @@ -175,7 +184,7 @@ rew_scope(struct roff_man *man, enum roff_tok tok) } if (tok != MAN_SH && (n->tok == MAN_SH || (tok != MAN_SS && (n->tok == MAN_SS || - man_macros[n->tok].fp == blk_exp)))) + man_macro(n->tok)->fp == blk_exp)))) return; man_unscope(man, n); n = man->last; @@ -189,33 +198,39 @@ rew_scope(struct roff_man *man, enum roff_tok tok) void blk_close(MACRO_PROT_ARGS) { - enum roff_tok ntok; + enum roff_tok ctok, ntok; const struct roff_node *nn; - char *p; - int nrew, target; + char *p, *ep; + int cline, cpos, la, nrew, target; nrew = 1; switch (tok) { case MAN_RE: ntok = MAN_RS; + la = *pos; if ( ! man_args(man, line, pos, buf, &p)) break; for (nn = man->last->parent; nn; nn = nn->parent) if (nn->tok == ntok && nn->type == ROFFT_BLOCK) nrew++; - target = strtol(p, &p, 10); - if (*p != '\0') - mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse, - line, p - buf, "RE ... %s", p); + target = strtol(p, &ep, 10); + if (*ep != '\0') + mandoc_msg(MANDOCERR_ARG_EXCESS, line, + la + (buf[la] == '"') + (int)(ep - p), + "RE ... %s", ep); + free(p); if (target == 0) target = 1; nrew -= target; if (nrew < 1) { - mandoc_vmsg(MANDOCERR_RE_NOTOPEN, man->parse, + mandoc_msg(MANDOCERR_RE_NOTOPEN, line, ppos, "RE %d", target); return; } break; + case MAN_YS: + ntok = MAN_SY; + break; case MAN_UE: ntok = MAN_UR; break; @@ -231,25 +246,47 @@ blk_close(MACRO_PROT_ARGS) break; if (nn == NULL) { - mandoc_msg(MANDOCERR_BLK_NOTOPEN, man->parse, - line, ppos, roff_name[tok]); + mandoc_msg(MANDOCERR_BLK_NOTOPEN, + line, ppos, "%s", roff_name[tok]); rew_scope(man, MAN_PP); - } else { - line = man->last->line; - ppos = man->last->pos; - ntok = man->last->tok; - man_unscope(man, nn); + if (tok == MAN_RE) { + roff_elem_alloc(man, line, ppos, ROFF_br); + man->last->flags |= NODE_LINE | + NODE_VALID | NODE_ENDED; + man->next = ROFF_NEXT_SIBLING; + } + return; + } - if (tok == MAN_RE && nn->head->aux > 0) - roff_setreg(man->roff, "an-margin", - nn->head->aux, '-'); + cline = man->last->line; + cpos = man->last->pos; + ctok = man->last->tok; + man_unscope(man, nn); - /* Move a trailing paragraph behind the block. */ + if (tok == MAN_RE && nn->head->aux > 0) + roff_setreg(man->roff, "an-margin", nn->head->aux, '-'); - if (ntok == MAN_LP || ntok == MAN_PP || ntok == MAN_P) { - *pos = strlen(buf); - blk_imp(man, ntok, line, ppos, pos, buf); - } + /* Trailing text. */ + + if (buf[*pos] != '\0') { + roff_word_alloc(man, line, ppos, buf + *pos); + man->last->flags |= NODE_DELIMC; + if (mandoc_eos(man->last->string, strlen(man->last->string))) + man->last->flags |= NODE_EOS; + } + + /* Move a trailing paragraph behind the block. */ + + if (ctok == MAN_LP || ctok == MAN_PP || ctok == MAN_P) { + *pos = strlen(buf); + blk_imp(man, ctok, cline, cpos, pos, buf); + } + + /* Synopsis blocks need an explicit end marker for spacing. */ + + if (tok == MAN_YS && man->last == nn) { + roff_elem_alloc(man, line, ppos, tok); + man_unscope(man, man->last); } } @@ -260,7 +297,10 @@ blk_exp(MACRO_PROT_ARGS) char *p; int la; - rew_scope(man, tok); + if (tok == MAN_RS) { + rew_scope(man, tok); + man->flags |= ROFF_NONOFILL; + } roff_block_alloc(man, line, ppos, tok); head = roff_head_alloc(man, line, ppos, tok); @@ -275,14 +315,16 @@ blk_exp(MACRO_PROT_ARGS) roff_setreg(man->roff, "an-margin", head->aux, '+'); } + free(p); } if (buf[*pos] != '\0') - mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse, line, - *pos, "%s ... %s", roff_name[tok], buf + *pos); + mandoc_msg(MANDOCERR_ARG_EXCESS, line, *pos, + "%s ... %s", roff_name[tok], buf + *pos); man_unscope(man, head); roff_body_alloc(man, line, ppos, tok); + man->flags &= ~ROFF_NONOFILL; } /* @@ -299,9 +341,10 @@ blk_imp(MACRO_PROT_ARGS) struct roff_node *n; rew_scope(man, tok); - n = roff_block_alloc(man, line, ppos, tok); - if (n->tok == MAN_SH || n->tok == MAN_SS) - man->flags &= ~MAN_LITERAL; + man->flags |= ROFF_NONOFILL; + if (tok == MAN_SH || tok == MAN_SS) + man->flags &= ~ROFF_NOFILL; + roff_block_alloc(man, line, ppos, tok); n = roff_head_alloc(man, line, ppos, tok); /* Add line arguments. */ @@ -311,16 +354,17 @@ blk_imp(MACRO_PROT_ARGS) if ( ! man_args(man, line, pos, buf, &p)) break; roff_word_alloc(man, line, la, p); + free(p); } /* * For macros having optional next-line scope, * keep the head open if there were no arguments. - * For `TP', always keep the head open. + * For `TP' and `TQ', always keep the head open. */ - if (man_macros[tok].flags & MAN_SCOPED && - (tok == MAN_TP || n == man->last)) { + if (man_macro(tok)->flags & MAN_BSCOPED && + (tok == MAN_TP || tok == MAN_TQ || n == man->last)) { man->flags |= MAN_BLINE; return; } @@ -329,6 +373,7 @@ blk_imp(MACRO_PROT_ARGS) man_unscope(man, n); roff_body_alloc(man, line, ppos, tok); + man->flags &= ~ROFF_NONOFILL; } void @@ -341,27 +386,26 @@ in_line_eoln(MACRO_PROT_ARGS) roff_elem_alloc(man, line, ppos, tok); n = man->last; + if (tok == MAN_EX) + man->flags |= ROFF_NOFILL; + else if (tok == MAN_EE) + man->flags &= ~ROFF_NOFILL; + for (;;) { - if (buf[*pos] != '\0' && (tok == MAN_fi || tok == MAN_nf)) { - mandoc_vmsg(MANDOCERR_ARG_SKIP, - man->parse, line, *pos, "%s %s", - roff_name[tok], buf + *pos); - break; - } if (buf[*pos] != '\0' && man->last != n && tok == MAN_PD) { - mandoc_vmsg(MANDOCERR_ARG_EXCESS, - man->parse, line, *pos, "%s ... %s", - roff_name[tok], buf + *pos); + mandoc_msg(MANDOCERR_ARG_EXCESS, line, *pos, + "%s ... %s", roff_name[tok], buf + *pos); break; } la = *pos; if ( ! man_args(man, line, pos, buf, &p)) break; - if (man_macros[tok].flags & MAN_JOIN && + if (man_macro(tok)->flags & MAN_JOIN && man->last->type == ROFFT_TEXT) roff_word_append(man, p); else roff_word_alloc(man, line, la, p); + free(p); } /* @@ -374,13 +418,12 @@ in_line_eoln(MACRO_PROT_ARGS) man->last->flags |= NODE_EOS; /* - * If no arguments are specified and this is MAN_SCOPED (i.e., + * If no arguments are specified and this is MAN_ESCOPED (i.e., * next-line scoped), then set our mode to indicate that we're * waiting for terms to load into our context. */ - if (n == man->last && man_macros[tok].flags & MAN_SCOPED) { - assert( ! (man_macros[tok].flags & MAN_NSCOPED)); + if (n == man->last && man_macro(tok)->flags & MAN_ESCOPED) { man->flags |= MAN_ELINE; return; } @@ -391,18 +434,21 @@ in_line_eoln(MACRO_PROT_ARGS) /* Rewind our element scope. */ for ( ; man->last; man->last = man->last->parent) { - man_state(man, man->last); + man->last->flags |= NODE_VALID; if (man->last == n) break; } + + /* Rewind next-line scoped ancestors, if any. */ + + if (man_macro(tok)->flags & MAN_ESCOPED) + man_descope(man, line, ppos, NULL); } void man_endparse(struct roff_man *man) { - - man_unscope(man, man->first); - man->flags &= ~MAN_LITERAL; + man_unscope(man, man->meta.first); } static int @@ -417,6 +463,6 @@ man_args(struct roff_man *man, int line, int *pos, char *buf, char **v) if ('\0' == *start) return 0; - *v = mandoc_getarg(man->parse, v, line, pos); + *v = roff_getarg(man->roff, v, line, pos); return 1; } diff --git a/usr/src/cmd/mandoc/man_term.c b/usr/src/cmd/mandoc/man_term.c index b5723ccf83..4bb3f9da28 100644 --- a/usr/src/cmd/mandoc/man_term.c +++ b/usr/src/cmd/mandoc/man_term.c @@ -1,7 +1,7 @@ -/* $Id: man_term.c,v 1.211 2018/06/10 15:12:35 schwarze Exp $ */ +/* $Id: man_term.c,v 1.228 2019/01/05 21:18:26 schwarze Exp $ */ /* * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2010-2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2010-2015, 2017-2019 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 @@ -27,7 +27,6 @@ #include <string.h> #include "mandoc_aux.h" -#include "mandoc.h" #include "roff.h" #include "man.h" #include "out.h" @@ -37,8 +36,6 @@ #define MAXMARGINS 64 /* maximum number of indented scopes */ struct mtermp { - int fl; -#define MANT_LITERAL (1 << 0) int lmargin[MAXMARGINS]; /* margins (incl. vis. page) */ int lmargincur; /* index of current margin */ int lmarginsz; /* actual number of nested margins */ @@ -51,7 +48,7 @@ struct mtermp { struct roff_node *n, \ const struct roff_meta *meta -struct termact { +struct man_term_act { int (*pre)(DECL_ARGS); void (*post)(DECL_ARGS); int flags; @@ -78,8 +75,10 @@ static int pre_PP(DECL_ARGS); static int pre_RS(DECL_ARGS); static int pre_SH(DECL_ARGS); static int pre_SS(DECL_ARGS); +static int pre_SY(DECL_ARGS); static int pre_TP(DECL_ARGS); static int pre_UR(DECL_ARGS); +static int pre_abort(DECL_ARGS); static int pre_alternate(DECL_ARGS); static int pre_ign(DECL_ARGS); static int pre_in(DECL_ARGS); @@ -89,18 +88,19 @@ static void post_IP(DECL_ARGS); static void post_HP(DECL_ARGS); static void post_RS(DECL_ARGS); static void post_SH(DECL_ARGS); -static void post_SS(DECL_ARGS); +static void post_SY(DECL_ARGS); static void post_TP(DECL_ARGS); static void post_UR(DECL_ARGS); -static const struct termact __termacts[MAN_MAX - MAN_TH] = { +static const struct man_term_act man_term_acts[MAN_MAX - MAN_TH] = { { NULL, NULL, 0 }, /* TH */ { pre_SH, post_SH, 0 }, /* SH */ - { pre_SS, post_SS, 0 }, /* SS */ + { pre_SS, post_SH, 0 }, /* SS */ { pre_TP, post_TP, 0 }, /* TP */ - { pre_PP, NULL, 0 }, /* LP */ + { pre_TP, post_TP, 0 }, /* TQ */ + { pre_abort, NULL, 0 }, /* LP */ { pre_PP, NULL, 0 }, /* PP */ - { pre_PP, NULL, 0 }, /* P */ + { pre_abort, NULL, 0 }, /* P */ { pre_IP, post_IP, 0 }, /* IP */ { pre_HP, post_HP, 0 }, /* HP */ { NULL, NULL, 0 }, /* SM */ @@ -114,8 +114,6 @@ static const struct termact __termacts[MAN_MAX - MAN_TH] = { { pre_I, NULL, 0 }, /* I */ { pre_alternate, NULL, 0 }, /* IR */ { pre_alternate, NULL, 0 }, /* RI */ - { pre_literal, NULL, 0 }, /* nf */ - { pre_literal, NULL, 0 }, /* fi */ { NULL, NULL, 0 }, /* RE */ { pre_RS, post_RS, 0 }, /* RS */ { pre_DT, NULL, 0 }, /* DT */ @@ -123,6 +121,8 @@ static const struct termact __termacts[MAN_MAX - MAN_TH] = { { pre_PD, NULL, MAN_NOTEXT }, /* PD */ { pre_ign, NULL, 0 }, /* AT */ { pre_in, NULL, MAN_NOTEXT }, /* in */ + { pre_SY, post_SY, 0 }, /* SY */ + { NULL, NULL, 0 }, /* YS */ { pre_OP, NULL, 0 }, /* OP */ { pre_literal, NULL, 0 }, /* EX */ { pre_literal, NULL, 0 }, /* EE */ @@ -131,15 +131,22 @@ static const struct termact __termacts[MAN_MAX - MAN_TH] = { { pre_UR, post_UR, 0 }, /* MT */ { NULL, NULL, 0 }, /* ME */ }; -static const struct termact *termacts = __termacts - MAN_TH; +static const struct man_term_act *man_term_act(enum roff_tok); +static const struct man_term_act * +man_term_act(enum roff_tok tok) +{ + assert(tok >= MAN_TH && tok <= MAN_MAX); + return man_term_acts + (tok - MAN_TH); +} + void -terminal_man(void *arg, const struct roff_man *man) +terminal_man(void *arg, const struct roff_meta *man) { + struct mtermp mt; struct termp *p; struct roff_node *n; - struct mtermp mt; size_t save_defindent; p = (struct termp *)arg; @@ -151,7 +158,7 @@ terminal_man(void *arg, const struct roff_man *man) term_tab_set(p, "T"); term_tab_set(p, ".5i"); - memset(&mt, 0, sizeof(struct mtermp)); + memset(&mt, 0, sizeof(mt)); mt.lmargin[mt.lmargincur] = term_len(p, p->defindent); mt.offset = term_len(p, p->defindent); mt.pardist = 1; @@ -164,18 +171,17 @@ terminal_man(void *arg, const struct roff_man *man) !strcmp(n->child->child->string, "SYNOPSIS")) { if (n->child->next->child != NULL) print_man_nodelist(p, &mt, - n->child->next->child, - &man->meta); + n->child->next->child, man); term_newln(p); break; } n = n->next; } } else { - term_begin(p, print_man_head, print_man_foot, &man->meta); + term_begin(p, print_man_head, print_man_foot, man); p->flags |= TERMP_NOSPACE; if (n != NULL) - print_man_nodelist(p, &mt, n, &man->meta); + print_man_nodelist(p, &mt, n, man); term_end(p); } p->defindent = save_defindent; @@ -196,12 +202,12 @@ print_bvspace(struct termp *p, const struct roff_node *n, int pardist) term_newln(p); - if (n->body && n->body->child) + if (n->body != NULL && n->body->child != NULL) if (n->body->child->type == ROFFT_TBL) return; if (n->parent->type == ROFFT_ROOT || n->parent->tok != MAN_RS) - if (NULL == n->prev) + if (n->prev == NULL) return; for (i = 0; i < pardist; i++) @@ -210,16 +216,20 @@ print_bvspace(struct termp *p, const struct roff_node *n, int pardist) static int -pre_ign(DECL_ARGS) +pre_abort(DECL_ARGS) { + abort(); +} +static int +pre_ign(DECL_ARGS) +{ return 0; } static int pre_I(DECL_ARGS) { - term_fontrepl(p, TERMFONT_UNDER); return 1; } @@ -227,14 +237,8 @@ pre_I(DECL_ARGS) static int pre_literal(DECL_ARGS) { - term_newln(p); - if (n->tok == MAN_nf || n->tok == MAN_EX) - mt->fl |= MANT_LITERAL; - else - mt->fl &= ~MANT_LITERAL; - /* * Unlike .IP and .TP, .HP does not have a HEAD. * So in case a second call to term_flushln() is needed, @@ -247,7 +251,6 @@ pre_literal(DECL_ARGS) p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); p->flags |= TERMP_NOSPACE; } - return 0; } @@ -272,7 +275,7 @@ pre_alternate(DECL_ARGS) { enum termfont font[2]; struct roff_node *nn; - int savelit, i; + int i; switch (n->tok) { case MAN_RB: @@ -302,29 +305,21 @@ pre_alternate(DECL_ARGS) default: abort(); } - - savelit = MANT_LITERAL & mt->fl; - mt->fl &= ~MANT_LITERAL; - - for (i = 0, nn = n->child; nn; nn = nn->next, i = 1 - i) { + for (i = 0, nn = n->child; nn != NULL; nn = nn->next, i = 1 - i) { term_fontrepl(p, font[i]); - if (savelit && NULL == nn->next) - mt->fl |= MANT_LITERAL; assert(nn->type == ROFFT_TEXT); term_word(p, nn->string); if (nn->flags & NODE_EOS) - p->flags |= TERMP_SENTENCE; - if (nn->next) + p->flags |= TERMP_SENTENCE; + if (nn->next != NULL) p->flags |= TERMP_NOSPACE; } - return 0; } static int pre_B(DECL_ARGS) { - term_fontrepl(p, TERMFONT_BOLD); return 1; } @@ -332,20 +327,19 @@ pre_B(DECL_ARGS) static int pre_OP(DECL_ARGS) { - term_word(p, "["); - p->flags |= TERMP_NOSPACE; + p->flags |= TERMP_KEEP | TERMP_NOSPACE; - if (NULL != (n = n->child)) { + if ((n = n->child) != NULL) { term_fontrepl(p, TERMFONT_BOLD); term_word(p, n->string); } - if (NULL != n && NULL != n->next) { + if (n != NULL && n->next != NULL) { term_fontrepl(p, TERMFONT_UNDER); term_word(p, n->next->string); } - term_fontrepl(p, TERMFONT_NONE); + p->flags &= ~TERMP_KEEP; p->flags |= TERMP_NOSPACE; term_word(p, "]"); return 0; @@ -369,9 +363,9 @@ pre_in(DECL_ARGS) cp = n->child->string; less = 0; - if ('-' == *cp) + if (*cp == '-') less = -1; - else if ('+' == *cp) + else if (*cp == '+') less = 1; else cp--; @@ -413,13 +407,18 @@ pre_HP(DECL_ARGS) case ROFFT_BLOCK: print_bvspace(p, n, mt->pardist); return 1; + case ROFFT_HEAD: + return 0; case ROFFT_BODY: break; default: - return 0; + abort(); } - if ( ! (MANT_LITERAL & mt->fl)) { + if (n->child == NULL) + return 0; + + if ((n->child->flags & NODE_NOFILL) == 0) { p->flags |= TERMP_NOBREAK | TERMP_BRIND; p->trailspace = 2; } @@ -445,8 +444,10 @@ pre_HP(DECL_ARGS) static void post_HP(DECL_ARGS) { - switch (n->type) { + case ROFFT_BLOCK: + case ROFFT_HEAD: + break; case ROFFT_BODY: term_newln(p); @@ -466,25 +467,27 @@ post_HP(DECL_ARGS) p->tcol->rmargin = p->maxrmargin; break; default: - break; + abort(); } } static int pre_PP(DECL_ARGS) { - switch (n->type) { case ROFFT_BLOCK: mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); print_bvspace(p, n, mt->pardist); break; - default: + case ROFFT_HEAD: + return 0; + case ROFFT_BODY: p->tcol->offset = mt->offset; break; + default: + abort(); } - - return n->type != ROFFT_HEAD; + return 1; } static int @@ -492,21 +495,21 @@ pre_IP(DECL_ARGS) { struct roffsu su; const struct roff_node *nn; - int len, savelit; + int len; switch (n->type) { - case ROFFT_BODY: - p->flags |= TERMP_NOSPACE; - break; + case ROFFT_BLOCK: + print_bvspace(p, n, mt->pardist); + return 1; case ROFFT_HEAD: p->flags |= TERMP_NOBREAK; p->trailspace = 1; break; - case ROFFT_BLOCK: - print_bvspace(p, n, mt->pardist); - /* FALLTHROUGH */ + case ROFFT_BODY: + p->flags |= TERMP_NOSPACE; + break; default: - return 1; + abort(); } /* Calculate the offset from the optional second argument. */ @@ -526,33 +529,25 @@ pre_IP(DECL_ARGS) case ROFFT_HEAD: p->tcol->offset = mt->offset; p->tcol->rmargin = mt->offset + len; - - savelit = MANT_LITERAL & mt->fl; - mt->fl &= ~MANT_LITERAL; - - if (n->child) + if (n->child != NULL) print_man_node(p, mt, n->child, meta); - - if (savelit) - mt->fl |= MANT_LITERAL; - return 0; case ROFFT_BODY: p->tcol->offset = mt->offset + len; p->tcol->rmargin = p->maxrmargin; break; default: - break; + abort(); } - return 1; } static void post_IP(DECL_ARGS) { - switch (n->type) { + case ROFFT_BLOCK: + break; case ROFFT_HEAD: term_flushln(p); p->flags &= ~TERMP_NOBREAK; @@ -564,7 +559,7 @@ post_IP(DECL_ARGS) p->tcol->offset = mt->offset; break; default: - break; + abort(); } } @@ -573,9 +568,13 @@ pre_TP(DECL_ARGS) { struct roffsu su; struct roff_node *nn; - int len, savelit; + int len; switch (n->type) { + case ROFFT_BLOCK: + if (n->tok == MAN_TP) + print_bvspace(p, n, mt->pardist); + return 1; case ROFFT_HEAD: p->flags |= TERMP_NOBREAK | TERMP_BRTRSP; p->trailspace = 1; @@ -583,11 +582,8 @@ pre_TP(DECL_ARGS) case ROFFT_BODY: p->flags |= TERMP_NOSPACE; break; - case ROFFT_BLOCK: - print_bvspace(p, n, mt->pardist); - /* FALLTHROUGH */ default: - return 1; + abort(); } /* Calculate offset. */ @@ -609,21 +605,15 @@ pre_TP(DECL_ARGS) p->tcol->offset = mt->offset; p->tcol->rmargin = mt->offset + len; - savelit = MANT_LITERAL & mt->fl; - mt->fl &= ~MANT_LITERAL; - /* Don't print same-line elements. */ nn = n->child; - while (NULL != nn && 0 == (NODE_LINE & nn->flags)) + while (nn != NULL && (nn->flags & NODE_LINE) == 0) nn = nn->next; - while (NULL != nn) { + while (nn != NULL) { print_man_node(p, mt, nn, meta); nn = nn->next; } - - if (savelit) - mt->fl |= MANT_LITERAL; return 0; case ROFFT_BODY: p->tcol->offset = mt->offset + len; @@ -632,17 +622,17 @@ pre_TP(DECL_ARGS) p->flags &= ~(TERMP_NOBREAK | TERMP_BRTRSP); break; default: - break; + abort(); } - return 1; } static void post_TP(DECL_ARGS) { - switch (n->type) { + case ROFFT_BLOCK: + break; case ROFFT_HEAD: term_flushln(p); break; @@ -651,7 +641,7 @@ post_TP(DECL_ARGS) p->tcol->offset = mt->offset; break; default: - break; + abort(); } } @@ -662,7 +652,6 @@ pre_SS(DECL_ARGS) switch (n->type) { case ROFFT_BLOCK: - mt->fl &= ~MANT_LITERAL; mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); mt->offset = term_len(p, p->defindent); @@ -674,7 +663,7 @@ pre_SS(DECL_ARGS) do { n = n->prev; } while (n != NULL && n->tok >= MAN_TH && - termacts[n->tok].flags & MAN_NOTEXT); + man_term_act(n->tok)->flags & MAN_NOTEXT); if (n == NULL || n->type == ROFFT_COMMENT || (n->tok == MAN_SS && n->body->child == NULL)) break; @@ -698,26 +687,9 @@ pre_SS(DECL_ARGS) default: break; } - return 1; } -static void -post_SS(DECL_ARGS) -{ - - switch (n->type) { - case ROFFT_HEAD: - term_newln(p); - break; - case ROFFT_BODY: - term_newln(p); - break; - default: - break; - } -} - static int pre_SH(DECL_ARGS) { @@ -725,7 +697,6 @@ pre_SH(DECL_ARGS) switch (n->type) { case ROFFT_BLOCK: - mt->fl &= ~MANT_LITERAL; mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); mt->offset = term_len(p, p->defindent); @@ -737,7 +708,7 @@ pre_SH(DECL_ARGS) do { n = n->prev; } while (n != NULL && n->tok >= MAN_TH && - termacts[n->tok].flags & MAN_NOTEXT); + man_term_act(n->tok)->flags & MAN_NOTEXT); if (n == NULL || n->type == ROFFT_COMMENT || (n->tok == MAN_SH && n->body->child == NULL)) break; @@ -759,25 +730,23 @@ pre_SH(DECL_ARGS) p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); break; default: - break; + abort(); } - return 1; } static void post_SH(DECL_ARGS) { - switch (n->type) { - case ROFFT_HEAD: - term_newln(p); + case ROFFT_BLOCK: break; + case ROFFT_HEAD: case ROFFT_BODY: term_newln(p); break; default: - break; + abort(); } } @@ -792,8 +761,10 @@ pre_RS(DECL_ARGS) return 1; case ROFFT_HEAD: return 0; - default: + case ROFFT_BODY: break; + default: + abort(); } n = n->parent->head; @@ -821,42 +792,99 @@ pre_RS(DECL_ARGS) static void post_RS(DECL_ARGS) { - switch (n->type) { case ROFFT_BLOCK: - return; case ROFFT_HEAD: return; - default: - term_newln(p); + case ROFFT_BODY: break; + default: + abort(); } - + term_newln(p); mt->offset -= n->parent->head->aux; p->tcol->offset = mt->offset; - if (--mt->lmarginsz < MAXMARGINS) mt->lmargincur = mt->lmarginsz; } static int -pre_UR(DECL_ARGS) +pre_SY(DECL_ARGS) +{ + const struct roff_node *nn; + int len; + + switch (n->type) { + case ROFFT_BLOCK: + if (n->prev == NULL || n->prev->tok != MAN_SY) + print_bvspace(p, n, mt->pardist); + return 1; + case ROFFT_HEAD: + case ROFFT_BODY: + break; + default: + abort(); + } + + nn = n->parent->head->child; + len = nn == NULL ? 1 : term_strlen(p, nn->string) + 1; + + switch (n->type) { + case ROFFT_HEAD: + p->tcol->offset = mt->offset; + p->tcol->rmargin = mt->offset + len; + if (n->next->child == NULL || + (n->next->child->flags & NODE_NOFILL) == 0) + p->flags |= TERMP_NOBREAK; + term_fontrepl(p, TERMFONT_BOLD); + break; + case ROFFT_BODY: + mt->lmargin[mt->lmargincur] = len; + p->tcol->offset = mt->offset + len; + p->tcol->rmargin = p->maxrmargin; + p->flags |= TERMP_NOSPACE; + break; + default: + abort(); + } + return 1; +} + +static void +post_SY(DECL_ARGS) { + switch (n->type) { + case ROFFT_BLOCK: + break; + case ROFFT_HEAD: + term_flushln(p); + p->flags &= ~TERMP_NOBREAK; + break; + case ROFFT_BODY: + term_newln(p); + p->tcol->offset = mt->offset; + break; + default: + abort(); + } +} +static int +pre_UR(DECL_ARGS) +{ return n->type != ROFFT_HEAD; } static void post_UR(DECL_ARGS) { - if (n->type != ROFFT_BLOCK) return; term_word(p, "<"); p->flags |= TERMP_NOSPACE; - if (NULL != n->child->child) + if (n->child->child != NULL) print_man_node(p, mt, n->child->child, meta); p->flags |= TERMP_NOSPACE; @@ -866,7 +894,8 @@ post_UR(DECL_ARGS) static void print_man_node(DECL_ARGS) { - int c; + const struct man_term_act *act; + int c; switch (n->type) { case ROFFT_TEXT: @@ -884,6 +913,8 @@ print_man_node(DECL_ARGS) } else if (*n->string == ' ' && n->flags & NODE_LINE && (p->flags & TERMP_NONEWLINE) == 0) term_newln(p); + else if (n->flags & NODE_DELIMC) + p->flags |= TERMP_NOSPACE; term_word(p, n->string); goto out; @@ -910,20 +941,20 @@ print_man_node(DECL_ARGS) return; } - assert(n->tok >= MAN_TH && n->tok <= MAN_MAX); - if ( ! (MAN_NOTEXT & termacts[n->tok].flags)) + act = man_term_act(n->tok); + if ((act->flags & MAN_NOTEXT) == 0 && n->tok != MAN_SM) term_fontrepl(p, TERMFONT_NONE); c = 1; - if (termacts[n->tok].pre) - c = (*termacts[n->tok].pre)(p, mt, n, meta); + if (act->pre != NULL) + c = (*act->pre)(p, mt, n, meta); - if (c && n->child) + if (c && n->child != NULL) print_man_nodelist(p, mt, n->child, meta); - if (termacts[n->tok].post) - (*termacts[n->tok].post)(p, mt, n, meta); - if ( ! (MAN_NOTEXT & termacts[n->tok].flags)) + if (act->post != NULL) + (*act->post)(p, mt, n, meta); + if ((act->flags & MAN_NOTEXT) == 0 && n->tok != MAN_SM) term_fontrepl(p, TERMFONT_NONE); out: @@ -934,7 +965,7 @@ out: * -man doesn't have nested macros, we don't need to be * more specific than this. */ - if (mt->fl & MANT_LITERAL && + if (n->flags & NODE_NOFILL && ! (p->flags & (TERMP_NOBREAK | TERMP_NONEWLINE)) && (n->next == NULL || n->next->flags & NODE_LINE)) { p->flags |= TERMP_BRNEVER | TERMP_NOSPACE; @@ -949,15 +980,13 @@ out: p->tcol->rmargin = p->maxrmargin; } } - if (NODE_EOS & n->flags) + if (n->flags & NODE_EOS) p->flags |= TERMP_SENTENCE; } - static void print_man_nodelist(DECL_ARGS) { - while (n != NULL) { print_man_node(p, mt, n, meta); n = n->next; @@ -992,7 +1021,7 @@ print_man_foot(struct termp *p, const struct roff_meta *meta) } mandoc_asprintf(&title, "%s(%s)", meta->title, meta->msec); - } else if (meta->os) { + } else if (meta->os != NULL) { title = mandoc_strdup(meta->os); } else { title = mandoc_strdup(""); diff --git a/usr/src/cmd/mandoc/man_validate.c b/usr/src/cmd/mandoc/man_validate.c index d6c51af525..4bfaf764e6 100644 --- a/usr/src/cmd/mandoc/man_validate.c +++ b/usr/src/cmd/mandoc/man_validate.c @@ -1,4 +1,4 @@ -/* $OpenBSD$ */ +/* $Id: man_validate.c,v 1.146 2018/12/31 10:04:39 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2010, 2012-2018 Ingo Schwarze <schwarze@openbsd.org> @@ -24,6 +24,7 @@ #include <errno.h> #include <limits.h> #include <stdarg.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> @@ -40,28 +41,32 @@ typedef void (*v_check)(CHKARGS); +static void check_abort(CHKARGS); static void check_par(CHKARGS); static void check_part(CHKARGS); static void check_root(CHKARGS); static void check_text(CHKARGS); static void post_AT(CHKARGS); +static void post_EE(CHKARGS); +static void post_EX(CHKARGS); static void post_IP(CHKARGS); static void post_OP(CHKARGS); +static void post_SH(CHKARGS); static void post_TH(CHKARGS); static void post_UC(CHKARGS); static void post_UR(CHKARGS); static void post_in(CHKARGS); -static void post_vs(CHKARGS); -static const v_check __man_valids[MAN_MAX - MAN_TH] = { +static const v_check man_valids[MAN_MAX - MAN_TH] = { post_TH, /* TH */ - NULL, /* SH */ - NULL, /* SS */ + post_SH, /* SH */ + post_SH, /* SS */ NULL, /* TP */ - check_par, /* LP */ + NULL, /* TQ */ + check_abort,/* LP */ check_par, /* PP */ - check_par, /* P */ + check_abort,/* P */ post_IP, /* IP */ NULL, /* HP */ NULL, /* SM */ @@ -75,8 +80,6 @@ static const v_check __man_valids[MAN_MAX - MAN_TH] = { NULL, /* I */ NULL, /* IR */ NULL, /* RI */ - NULL, /* nf */ - NULL, /* fi */ NULL, /* RE */ check_part, /* RS */ NULL, /* DT */ @@ -84,33 +87,56 @@ static const v_check __man_valids[MAN_MAX - MAN_TH] = { NULL, /* PD */ post_AT, /* AT */ post_in, /* in */ + NULL, /* SY */ + NULL, /* YS */ post_OP, /* OP */ - NULL, /* EX */ - NULL, /* EE */ + post_EX, /* EX */ + post_EE, /* EE */ post_UR, /* UR */ NULL, /* UE */ post_UR, /* MT */ NULL, /* ME */ }; -static const v_check *man_valids = __man_valids - MAN_TH; +/* Validate the subtree rooted at man->last. */ void -man_node_validate(struct roff_man *man) +man_validate(struct roff_man *man) { struct roff_node *n; const v_check *cp; + /* + * Translate obsolete macros such that later code + * does not need to look for them. + */ + n = man->last; + switch (n->tok) { + case MAN_LP: + case MAN_P: + n->tok = MAN_PP; + break; + default: + break; + } + + /* + * Iterate over all children, recursing into each one + * in turn, depth-first. + */ + man->last = man->last->child; while (man->last != NULL) { - man_node_validate(man); + man_validate(man); if (man->last == n) man->last = man->last->child; else man->last = man->last->next; } + /* Finally validate the macro itself. */ + man->last = n; man->next = ROFF_NEXT_SIBLING; switch (n->type) { @@ -126,23 +152,15 @@ man_node_validate(struct roff_man *man) break; default: if (n->tok < ROFF_MAX) { - switch (n->tok) { - case ROFF_br: - case ROFF_sp: - post_vs(man, n); - break; - default: - roff_validate(man); - break; - } + roff_validate(man); break; } assert(n->tok >= MAN_TH && n->tok < MAN_MAX); - cp = man_valids + n->tok; + cp = man_valids + (n->tok - MAN_TH); if (*cp) (*cp)(man, n); if (man->last == n) - man_state(man, n); + n->flags |= NODE_VALID; break; } } @@ -153,14 +171,12 @@ check_root(CHKARGS) assert((man->flags & (MAN_BLINE | MAN_ELINE)) == 0); if (n->last == NULL || n->last->type == ROFFT_COMMENT) - mandoc_msg(MANDOCERR_DOC_EMPTY, man->parse, - n->line, n->pos, NULL); + mandoc_msg(MANDOCERR_DOC_EMPTY, n->line, n->pos, NULL); else man->meta.hasbody = 1; if (NULL == man->meta.title) { - mandoc_msg(MANDOCERR_TH_NOTITLE, man->parse, - n->line, n->pos, NULL); + mandoc_msg(MANDOCERR_TH_NOTITLE, n->line, n->pos, NULL); /* * If a title hasn't been set, do so now (by @@ -175,23 +191,43 @@ check_root(CHKARGS) if (man->meta.os_e && (man->meta.rcsids & (1 << man->meta.os_e)) == 0) - mandoc_msg(MANDOCERR_RCS_MISSING, man->parse, 0, 0, + mandoc_msg(MANDOCERR_RCS_MISSING, 0, 0, man->meta.os_e == MANDOC_OS_OPENBSD ? "(OpenBSD)" : "(NetBSD)"); } static void +check_abort(CHKARGS) +{ + abort(); +} + +static void check_text(CHKARGS) { char *cp, *p; - if (MAN_LITERAL & man->flags) + if (n->flags & NODE_NOFILL) return; cp = n->string; for (p = cp; NULL != (p = strchr(p, '\t')); p++) - mandoc_msg(MANDOCERR_FI_TAB, man->parse, - n->line, n->pos + (p - cp), NULL); + mandoc_msg(MANDOCERR_FI_TAB, + n->line, n->pos + (int)(p - cp), NULL); +} + +static void +post_EE(CHKARGS) +{ + if ((n->flags & NODE_NOFILL) == 0) + mandoc_msg(MANDOCERR_FI_SKIP, n->line, n->pos, "EE"); +} + +static void +post_EX(CHKARGS) +{ + if (n->flags & NODE_NOFILL) + mandoc_msg(MANDOCERR_NF_SKIP, n->line, n->pos, "EX"); } static void @@ -199,21 +235,55 @@ post_OP(CHKARGS) { if (n->child == NULL) - mandoc_msg(MANDOCERR_OP_EMPTY, man->parse, - n->line, n->pos, "OP"); + mandoc_msg(MANDOCERR_OP_EMPTY, n->line, n->pos, "OP"); else if (n->child->next != NULL && n->child->next->next != NULL) { n = n->child->next->next; - mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse, + mandoc_msg(MANDOCERR_ARG_EXCESS, n->line, n->pos, "OP ... %s", n->string); } } static void +post_SH(CHKARGS) +{ + struct roff_node *nc; + + if (n->type != ROFFT_BODY || (nc = n->child) == NULL) + return; + + if (nc->tok == MAN_PP && nc->body->child != NULL) { + while (nc->body->last != NULL) { + man->next = ROFF_NEXT_CHILD; + roff_node_relink(man, nc->body->last); + man->last = n; + } + } + + if (nc->tok == MAN_PP || nc->tok == ROFF_sp || nc->tok == ROFF_br) { + mandoc_msg(MANDOCERR_PAR_SKIP, nc->line, nc->pos, + "%s after %s", roff_name[nc->tok], roff_name[n->tok]); + roff_node_delete(man, nc); + } + + /* + * Trailing PP is empty, so it is deleted by check_par(). + * Trailing sp is significant. + */ + + if ((nc = n->last) != NULL && nc->tok == ROFF_br) { + mandoc_msg(MANDOCERR_PAR_SKIP, + nc->line, nc->pos, "%s at the end of %s", + roff_name[nc->tok], roff_name[n->tok]); + roff_node_delete(man, nc); + } +} + +static void post_UR(CHKARGS) { if (n->type == ROFFT_HEAD && n->child == NULL) - mandoc_msg(MANDOCERR_UR_NOHEAD, man->parse, - n->line, n->pos, roff_name[n->tok]); + mandoc_msg(MANDOCERR_UR_NOHEAD, n->line, n->pos, + "%s", roff_name[n->tok]); check_part(man, n); } @@ -222,8 +292,8 @@ check_part(CHKARGS) { if (n->type == ROFFT_BODY && n->child == NULL) - mandoc_msg(MANDOCERR_BLK_EMPTY, man->parse, - n->line, n->pos, roff_name[n->tok]); + mandoc_msg(MANDOCERR_BLK_EMPTY, n->line, n->pos, + "%s", roff_name[n->tok]); } static void @@ -236,15 +306,22 @@ check_par(CHKARGS) roff_node_delete(man, n); break; case ROFFT_BODY: + if (n->child != NULL && + (n->child->tok == ROFF_sp || n->child->tok == ROFF_br)) { + mandoc_msg(MANDOCERR_PAR_SKIP, + n->child->line, n->child->pos, + "%s after %s", roff_name[n->child->tok], + roff_name[n->tok]); + roff_node_delete(man, n->child); + } if (n->child == NULL) - mandoc_vmsg(MANDOCERR_PAR_SKIP, - man->parse, n->line, n->pos, + mandoc_msg(MANDOCERR_PAR_SKIP, n->line, n->pos, "%s empty", roff_name[n->tok]); break; case ROFFT_HEAD: if (n->child != NULL) - mandoc_vmsg(MANDOCERR_ARG_SKIP, - man->parse, n->line, n->pos, "%s %s%s", + mandoc_msg(MANDOCERR_ARG_SKIP, + n->line, n->pos, "%s %s%s", roff_name[n->tok], n->child->string, n->child->next != NULL ? " ..." : ""); break; @@ -264,8 +341,7 @@ post_IP(CHKARGS) break; case ROFFT_BODY: if (n->parent->head->child == NULL && n->child == NULL) - mandoc_vmsg(MANDOCERR_PAR_SKIP, - man->parse, n->line, n->pos, + mandoc_msg(MANDOCERR_PAR_SKIP, n->line, n->pos, "%s empty", roff_name[n->tok]); break; default: @@ -298,9 +374,8 @@ post_TH(CHKARGS) /* Only warn about this once... */ if (isalpha((unsigned char)*p) && ! isupper((unsigned char)*p)) { - mandoc_vmsg(MANDOCERR_TITLE_CASE, - man->parse, n->line, - n->pos + (p - n->string), + mandoc_msg(MANDOCERR_TITLE_CASE, n->line, + n->pos + (int)(p - n->string), "TH %s", n->string); break; } @@ -308,8 +383,7 @@ post_TH(CHKARGS) man->meta.title = mandoc_strdup(n->string); } else { man->meta.title = mandoc_strdup(""); - mandoc_msg(MANDOCERR_TH_NOTITLE, man->parse, - nb->line, nb->pos, "TH"); + mandoc_msg(MANDOCERR_TH_NOTITLE, nb->line, nb->pos, "TH"); } /* TITLE ->MSEC<- DATE OS VOL */ @@ -320,7 +394,7 @@ post_TH(CHKARGS) man->meta.msec = mandoc_strdup(n->string); else { man->meta.msec = mandoc_strdup(""); - mandoc_vmsg(MANDOCERR_MSEC_MISSING, man->parse, + mandoc_msg(MANDOCERR_MSEC_MISSING, nb->line, nb->pos, "TH %s", man->meta.title); } @@ -334,7 +408,7 @@ post_TH(CHKARGS) mandoc_normdate(man, n->string, n->line, n->pos); } else { man->meta.date = mandoc_strdup(""); - mandoc_msg(MANDOCERR_DATE_MISSING, man->parse, + mandoc_msg(MANDOCERR_DATE_MISSING, n ? n->line : nb->line, n ? n->pos : nb->pos, "TH"); } @@ -362,7 +436,7 @@ post_TH(CHKARGS) man->meta.vol = mandoc_strdup(p); if (n != NULL && (n = n->next) != NULL) - mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse, + mandoc_msg(MANDOCERR_ARG_EXCESS, n->line, n->pos, "TH ... %s", n->string); /* @@ -463,32 +537,3 @@ post_in(CHKARGS) free(n->child->string); n->child->string = s; } - -static void -post_vs(CHKARGS) -{ - - if (NULL != n->prev) - return; - - switch (n->parent->tok) { - case MAN_SH: - case MAN_SS: - case MAN_PP: - case MAN_LP: - case MAN_P: - mandoc_vmsg(MANDOCERR_PAR_SKIP, man->parse, n->line, n->pos, - "%s after %s", roff_name[n->tok], - roff_name[n->parent->tok]); - /* FALLTHROUGH */ - case TOKEN_NONE: - /* - * Don't warn about this because it occurs in pod2man - * and would cause considerable (unfixable) warnage. - */ - roff_node_delete(man, n); - break; - default: - break; - } -} diff --git a/usr/src/cmd/mandoc/manconf.h b/usr/src/cmd/mandoc/manconf.h index b4cd31646c..bb3761998c 100644 --- a/usr/src/cmd/mandoc/manconf.h +++ b/usr/src/cmd/mandoc/manconf.h @@ -1,6 +1,6 @@ -/* $Id: manconf.h,v 1.5 2017/07/01 09:47:30 schwarze Exp $ */ +/* $Id: manconf.h,v 1.7 2018/11/22 11:30:23 schwarze Exp $ */ /* - * Copyright (c) 2011, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2011, 2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv> * * Permission to use, copy, modify, and distribute this software for any @@ -30,12 +30,14 @@ struct manoutput { char *man; char *paper; char *style; + char *tag; size_t indent; size_t width; int fragment; int mdoc; - int synopsisonly; int noval; + int synopsisonly; + int toc; }; struct manconf { diff --git a/usr/src/cmd/mandoc/mandoc.c b/usr/src/cmd/mandoc/mandoc.c index 1279b52ed5..fb9395a585 100644 --- a/usr/src/cmd/mandoc/mandoc.c +++ b/usr/src/cmd/mandoc/mandoc.c @@ -1,4 +1,4 @@ -/* $Id: mandoc.c,v 1.104 2018/07/28 18:34:15 schwarze Exp $ */ +/* $Id: mandoc.c,v 1.114 2018/12/30 00:49:55 schwarze Exp $ */ /* * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2011-2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org> @@ -32,16 +32,70 @@ #include "mandoc.h" #include "roff.h" #include "libmandoc.h" +#include "roff_int.h" static int a2time(time_t *, const char *, const char *); static char *time2a(time_t); enum mandoc_esc +mandoc_font(const char *cp, int sz) +{ + switch (sz) { + case 0: + return ESCAPE_FONTPREV; + case 1: + switch (cp[0]) { + case 'B': + case '3': + return ESCAPE_FONTBOLD; + case 'I': + case '2': + return ESCAPE_FONTITALIC; + case 'P': + return ESCAPE_FONTPREV; + case 'R': + case '1': + return ESCAPE_FONTROMAN; + case '4': + return ESCAPE_FONTBI; + default: + return ESCAPE_ERROR; + } + case 2: + switch (cp[0]) { + case 'B': + switch (cp[1]) { + case 'I': + return ESCAPE_FONTBI; + default: + return ESCAPE_ERROR; + } + case 'C': + switch (cp[1]) { + case 'B': + return ESCAPE_FONTBOLD; + case 'I': + return ESCAPE_FONTITALIC; + case 'R': + case 'W': + return ESCAPE_FONTCW; + default: + return ESCAPE_ERROR; + } + default: + return ESCAPE_ERROR; + } + default: + return ESCAPE_ERROR; + } +} + +enum mandoc_esc mandoc_escape(const char **end, const char **start, int *sz) { const char *local_start; - int local_sz; + int local_sz, c, i; char term; enum mandoc_esc gly; @@ -56,6 +110,14 @@ mandoc_escape(const char **end, const char **start, int *sz) sz = &local_sz; /* + * Treat "\E" just like "\"; + * it only makes a difference in copy mode. + */ + + if (**end == 'E') + ++*end; + + /* * Beyond the backslash, at least one input character * is part of the escape sequence. With one exception * (see below), that character won't be returned. @@ -77,6 +139,10 @@ mandoc_escape(const char **end, const char **start, int *sz) *sz = 2; break; case '[': + if (**start == ' ') { + ++*end; + return ESCAPE_ERROR; + } gly = ESCAPE_SPECIAL; term = ']'; break; @@ -91,11 +157,26 @@ mandoc_escape(const char **end, const char **start, int *sz) /* * Escapes taking no arguments at all. */ - case 'd': - case 'u': + case '!': + case '?': + return ESCAPE_UNSUPP; + case '%': + case '&': + case ')': case ',': case '/': + case '^': + case 'a': + case 'd': + case 'r': + case 't': + case 'u': + case '{': + case '|': + case '}': return ESCAPE_IGNORE; + case 'c': + return ESCAPE_NOSPACE; case 'p': return ESCAPE_BREAK; @@ -113,32 +194,57 @@ mandoc_escape(const char **end, const char **start, int *sz) * 'X' is the trigger. These have opaque sub-strings. */ case 'F': + case 'f': case 'g': case 'k': case 'M': case 'm': case 'n': + case 'O': case 'V': case 'Y': - gly = ESCAPE_IGNORE; - /* FALLTHROUGH */ - case 'f': - if (ESCAPE_ERROR == gly) - gly = ESCAPE_FONT; + gly = (*start)[-1] == 'f' ? ESCAPE_FONT : ESCAPE_IGNORE; switch (**start) { case '(': + if ((*start)[-1] == 'O') + gly = ESCAPE_ERROR; *start = ++*end; *sz = 2; break; case '[': + if ((*start)[-1] == 'O') + gly = (*start)[1] == '5' ? + ESCAPE_UNSUPP : ESCAPE_ERROR; *start = ++*end; term = ']'; break; default: + if ((*start)[-1] == 'O') { + switch (**start) { + case '0': + gly = ESCAPE_UNSUPP; + break; + case '1': + case '2': + case '3': + case '4': + break; + default: + gly = ESCAPE_ERROR; + break; + } + } *sz = 1; break; } break; + case '*': + if (strncmp(*start, "(.T", 3) != 0) + abort(); + gly = ESCAPE_DEVICE; + *start = ++*end; + *sz = 2; + break; /* * These escapes are of the form \X'Y', where 'X' is the trigger @@ -250,18 +356,29 @@ mandoc_escape(const char **end, const char **start, int *sz) break; /* - * Anything else is assumed to be a glyph. - * In this case, pass back the character after the backslash. + * Several special characters can be encoded as + * one-byte escape sequences without using \[]. */ - default: + case ' ': + case '\'': + case '-': + case '.': + case '0': + case ':': + case '_': + case '`': + case 'e': + case '~': gly = ESCAPE_SPECIAL; + /* FALLTHROUGH */ + default: + if (gly == ESCAPE_ERROR) + gly = ESCAPE_UNDEF; *start = --*end; *sz = 1; break; } - assert(ESCAPE_ERROR != gly); - /* * Read up to the terminating character, * paying attention to nested escapes. @@ -284,6 +401,15 @@ mandoc_escape(const char **end, const char **start, int *sz) } } *sz = (*end)++ - *start; + + /* + * The file chars.c only provides one common list + * of character names, but \[-] == \- is the only + * one of the characters with one-byte names that + * allows enclosing the name in brackets. + */ + if (gly == ESCAPE_SPECIAL && *sz == 1 && **start != '-') + return ESCAPE_ERROR; } else { assert(*sz > 0); if ((size_t)*sz > strlen(*start)) @@ -295,43 +421,25 @@ mandoc_escape(const char **end, const char **start, int *sz) switch (gly) { case ESCAPE_FONT: - if (2 == *sz) { - if ('C' == **start) { - /* - * Treat constant-width font modes - * just like regular font modes. - */ - (*start)++; - (*sz)--; - } else { - if ('B' == (*start)[0] && 'I' == (*start)[1]) - gly = ESCAPE_FONTBI; + gly = mandoc_font(*start, *sz); + break; + case ESCAPE_SPECIAL: + if (**start == 'c') { + if (*sz < 6 || *sz > 7 || + strncmp(*start, "char", 4) != 0 || + (int)strspn(*start + 4, "0123456789") + 4 < *sz) break; - } - } else if (1 != *sz) - break; - - switch (**start) { - case '3': - case 'B': - gly = ESCAPE_FONTBOLD; - break; - case '2': - case 'I': - gly = ESCAPE_FONTITALIC; - break; - case 'P': - gly = ESCAPE_FONTPREV; - break; - case '1': - case 'R': - gly = ESCAPE_FONTROMAN; + c = 0; + for (i = 4; i < *sz; i++) + c = 10 * c + ((*start)[i] - '0'); + if (c < 0x21 || (c > 0x7e && c < 0xa0) || c > 0xff) + break; + *start += 4; + *sz -= 4; + gly = ESCAPE_NUMBERED; break; } - break; - case ESCAPE_SPECIAL: - if (1 == *sz && 'c' == **start) - gly = ESCAPE_NOSPACE; + /* * Unicode escapes are defined in groff as \[u0000] * to \[u10FFFF], where the contained value must be @@ -358,101 +466,6 @@ mandoc_escape(const char **end, const char **start, int *sz) return gly; } -/* - * Parse a quoted or unquoted roff-style request or macro argument. - * Return a pointer to the parsed argument, which is either the original - * pointer or advanced by one byte in case the argument is quoted. - * NUL-terminate the argument in place. - * Collapse pairs of quotes inside quoted arguments. - * Advance the argument pointer to the next argument, - * or to the NUL byte terminating the argument line. - */ -char * -mandoc_getarg(struct mparse *parse, char **cpp, int ln, int *pos) -{ - char *start, *cp; - int quoted, pairs, white; - - /* Quoting can only start with a new word. */ - start = *cpp; - quoted = 0; - if ('"' == *start) { - quoted = 1; - start++; - } - - pairs = 0; - white = 0; - for (cp = start; '\0' != *cp; cp++) { - - /* - * Move the following text left - * after quoted quotes and after "\\" and "\t". - */ - if (pairs) - cp[-pairs] = cp[0]; - - if ('\\' == cp[0]) { - /* - * In copy mode, translate double to single - * backslashes and backslash-t to literal tabs. - */ - switch (cp[1]) { - case 't': - cp[0] = '\t'; - /* FALLTHROUGH */ - case '\\': - pairs++; - cp++; - break; - case ' ': - /* Skip escaped blanks. */ - if (0 == quoted) - cp++; - break; - default: - break; - } - } else if (0 == quoted) { - if (' ' == cp[0]) { - /* Unescaped blanks end unquoted args. */ - white = 1; - break; - } - } else if ('"' == cp[0]) { - if ('"' == cp[1]) { - /* Quoted quotes collapse. */ - pairs++; - cp++; - } else { - /* Unquoted quotes end quoted args. */ - quoted = 2; - break; - } - } - } - - /* Quoted argument without a closing quote. */ - if (1 == quoted) - mandoc_msg(MANDOCERR_ARG_QUOTE, parse, ln, *pos, NULL); - - /* NUL-terminate this argument and move to the next one. */ - if (pairs) - cp[-pairs] = '\0'; - if ('\0' != *cp) { - *cp++ = '\0'; - while (' ' == *cp) - cp++; - } - *pos += (int)(cp - start) + (quoted ? 1 : 0); - *cpp = cp; - - if ('\0' == *cp && (white || ' ' == cp[-1])) - mandoc_msg(MANDOCERR_SPACE_EOL, parse, ln, *pos, NULL); - - return start; -} - static int a2time(time_t *t, const char *fmt, const char *p) { @@ -529,7 +542,7 @@ mandoc_normdate(struct roff_man *man, char *in, int ln, int pos) /* No date specified: use today's date. */ if (in == NULL || *in == '\0' || strcmp(in, "$" "Mdocdate$") == 0) { - mandoc_msg(MANDOCERR_DATE_MISSING, man->parse, ln, pos, NULL); + mandoc_msg(MANDOCERR_DATE_MISSING, ln, pos, NULL); return time2a(time(NULL)); } @@ -539,23 +552,20 @@ mandoc_normdate(struct roff_man *man, char *in, int ln, int pos) a2time(&t, "%b %d, %Y", in)) { cp = time2a(t); if (t > time(NULL) + 86400) - mandoc_msg(MANDOCERR_DATE_FUTURE, man->parse, - ln, pos, cp); + mandoc_msg(MANDOCERR_DATE_FUTURE, ln, pos, "%s", cp); else if (*in != '$' && strcmp(in, cp) != 0) - mandoc_msg(MANDOCERR_DATE_NORM, man->parse, - ln, pos, cp); + mandoc_msg(MANDOCERR_DATE_NORM, ln, pos, "%s", cp); return cp; } /* In man(7), do not warn about the legacy format. */ if (a2time(&t, "%Y-%m-%d", in) == 0) - mandoc_msg(MANDOCERR_DATE_BAD, man->parse, ln, pos, in); + mandoc_msg(MANDOCERR_DATE_BAD, ln, pos, "%s", in); else if (t > time(NULL) + 86400) - mandoc_msg(MANDOCERR_DATE_FUTURE, man->parse, ln, pos, in); - else if (man->macroset == MACROSET_MDOC) - mandoc_vmsg(MANDOCERR_DATE_LEGACY, man->parse, - ln, pos, "Dd %s", in); + mandoc_msg(MANDOCERR_DATE_FUTURE, ln, pos, "%s", in); + else if (man->meta.macroset == MACROSET_MDOC) + mandoc_msg(MANDOCERR_DATE_LEGACY, ln, pos, "Dd %s", in); /* Use any non-mdoc(7) date verbatim. */ diff --git a/usr/src/cmd/mandoc/mandoc.h b/usr/src/cmd/mandoc/mandoc.h index dbc266cc3b..a44b192e0f 100644 --- a/usr/src/cmd/mandoc/mandoc.h +++ b/usr/src/cmd/mandoc/mandoc.h @@ -1,7 +1,7 @@ -/* $Id: mandoc.h,v 1.248 2018/07/28 18:34:15 schwarze Exp $ */ +/* $Id: mandoc.h,v 1.262 2018/12/16 00:17:02 schwarze Exp $ */ /* * Copyright (c) 2010, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2010-2018 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 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 @@ -14,6 +14,8 @@ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Error handling, escape sequence, and character utilities. */ #define ASCII_NBRSP 31 /* non-breaking space */ @@ -158,6 +160,7 @@ enum mandocerr { MANDOCERR_LB_BAD, /* unknown library name: Lb ... */ MANDOCERR_RS_BAD, /* invalid content in Rs block: macro */ MANDOCERR_SM_BAD, /* invalid Boolean argument: macro arg */ + MANDOCERR_CHAR_FONT, /* argument contains two font escapes */ MANDOCERR_FT_BAD, /* unknown font, skipping request: ft font */ MANDOCERR_TR_ODD, /* odd number of characters in request: tr char */ @@ -166,6 +169,7 @@ enum mandocerr { MANDOCERR_FI_TAB, /* tab in filled text */ MANDOCERR_EOS, /* new sentence, new line */ MANDOCERR_ESC_BAD, /* invalid escape sequence: esc */ + MANDOCERR_ESC_UNDEF, /* undefined escape, printing literally: char */ MANDOCERR_STR_UNDEF, /* undefined string, using "": name */ /* related to tables */ @@ -195,6 +199,7 @@ enum mandocerr { MANDOCERR_ROFFLOOP, /* input stack limit exceeded, infinite loop? */ MANDOCERR_CHAR_BAD, /* skipping bad character: number */ MANDOCERR_MACRO, /* skipping unknown macro: macro */ + MANDOCERR_REQ_NOMAC, /* skipping request outside macro: ... */ MANDOCERR_REQ_INSEC, /* skipping insecure request: request */ MANDOCERR_IT_STRAY, /* skipping item outside list: It ... */ MANDOCERR_TA_STRAY, /* skipping column outside column list: Ta */ @@ -205,14 +210,18 @@ enum mandocerr { /* related to request and macro arguments */ MANDOCERR_NAMESC, /* escaped character not allowed in a name: name */ + MANDOCERR_ARG_UNDEF, /* using macro argument outside macro */ + MANDOCERR_ARG_NONUM, /* argument number is not numeric */ MANDOCERR_BD_FILE, /* NOT IMPLEMENTED: Bd -file */ MANDOCERR_BD_NOARG, /* skipping display without arguments: Bd */ MANDOCERR_BL_NOTYPE, /* missing list type, using -item: Bl */ MANDOCERR_CE_NONUM, /* argument is not numeric, using 1: ce ... */ + MANDOCERR_CHAR_ARG, /* argument is not a character: char ... */ MANDOCERR_NM_NONAME, /* missing manual name, using "": Nm */ MANDOCERR_OS_UNAME, /* uname(3) system call failed, using UNKNOWN */ MANDOCERR_ST_BAD, /* unknown standard specifier: St standard */ MANDOCERR_IT_NONUM, /* skipping request without numeric argument */ + MANDOCERR_SHIFT, /* excessive shift: ..., but max is ... */ MANDOCERR_SO_PATH, /* NOT IMPLEMENTED: .so with absolute path or ".." */ MANDOCERR_SO_FAIL, /* .so request failed */ MANDOCERR_ARG_SKIP, /* skipping all arguments: macro args */ @@ -223,7 +232,12 @@ enum mandocerr { MANDOCERR_TOOLARGE, /* input too large */ MANDOCERR_CHAR_UNSUPP, /* unsupported control character: number */ + MANDOCERR_ESC_UNSUPP, /* unsupported escape sequence: escape */ MANDOCERR_REQ_UNSUPP, /* unsupported roff request: request */ + MANDOCERR_WHILE_NEST, /* nested .while loops */ + MANDOCERR_WHILE_OUTOF, /* end of scope with open .while loop */ + MANDOCERR_WHILE_INTO, /* end of .while loop in inner scope */ + MANDOCERR_WHILE_FAIL, /* cannot continue this .while loop */ MANDOCERR_TBLOPT_EQN, /* eqn delim option in tbl: arg */ MANDOCERR_TBLLAYOUT_MOD, /* unsupported tbl layout modifier: m */ MANDOCERR_TBLMACRO, /* ignoring macro in table: macro */ @@ -231,206 +245,22 @@ enum mandocerr { MANDOCERR_MAX }; -struct tbl_opts { - char tab; /* cell-separator */ - char decimal; /* decimal point */ - int opts; -#define TBL_OPT_CENTRE (1 << 0) -#define TBL_OPT_EXPAND (1 << 1) -#define TBL_OPT_BOX (1 << 2) -#define TBL_OPT_DBOX (1 << 3) -#define TBL_OPT_ALLBOX (1 << 4) -#define TBL_OPT_NOKEEP (1 << 5) -#define TBL_OPT_NOSPACE (1 << 6) -#define TBL_OPT_NOWARN (1 << 7) - int cols; /* number of columns */ - int lvert; /* width of left vertical line */ - int rvert; /* width of right vertical line */ -}; - -enum tbl_cellt { - TBL_CELL_CENTRE, /* c, C */ - TBL_CELL_RIGHT, /* r, R */ - TBL_CELL_LEFT, /* l, L */ - TBL_CELL_NUMBER, /* n, N */ - TBL_CELL_SPAN, /* s, S */ - TBL_CELL_LONG, /* a, A */ - TBL_CELL_DOWN, /* ^ */ - TBL_CELL_HORIZ, /* _, - */ - TBL_CELL_DHORIZ, /* = */ - TBL_CELL_MAX -}; - -/* - * A cell in a layout row. - */ -struct tbl_cell { - struct tbl_cell *next; - 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 */ - int col; /* column number, starting from 0 */ - int flags; -#define TBL_CELL_TALIGN (1 << 0) /* t, T */ -#define TBL_CELL_BALIGN (1 << 1) /* d, D */ -#define TBL_CELL_BOLD (1 << 2) /* fB, B, b */ -#define TBL_CELL_ITALIC (1 << 3) /* fI, I, i */ -#define TBL_CELL_EQUAL (1 << 4) /* e, E */ -#define TBL_CELL_UP (1 << 5) /* u, U */ -#define TBL_CELL_WIGN (1 << 6) /* z, Z */ -#define TBL_CELL_WMAX (1 << 7) /* x, X */ - enum tbl_cellt pos; -}; - -/* - * A layout row. - */ -struct tbl_row { - struct tbl_row *next; - struct tbl_cell *first; - struct tbl_cell *last; - int vert; /* width of left vertical line */ -}; - -enum tbl_datt { - TBL_DATA_NONE, /* has no data */ - TBL_DATA_DATA, /* consists of data/string */ - TBL_DATA_HORIZ, /* horizontal line */ - TBL_DATA_DHORIZ, /* double-horizontal line */ - TBL_DATA_NHORIZ, /* squeezed horizontal line */ - TBL_DATA_NDHORIZ /* squeezed double-horizontal line */ -}; - -/* - * A cell within a row of data. The "string" field contains the actual - * string value that's in the cell. The rest is layout. - */ -struct tbl_dat { - struct tbl_cell *layout; /* layout cell */ - struct tbl_dat *next; - char *string; /* data (NULL if not TBL_DATA_DATA) */ - int spans; /* how many spans follow */ - int block; /* T{ text block T} */ - enum tbl_datt pos; -}; - -enum tbl_spant { - TBL_SPAN_DATA, /* span consists of data */ - TBL_SPAN_HORIZ, /* span is horizontal line */ - TBL_SPAN_DHORIZ /* span is double horizontal line */ -}; - -/* - * A row of data in a table. - */ -struct tbl_span { - struct tbl_opts *opts; - struct tbl_row *layout; /* layout row */ - struct tbl_dat *first; - struct tbl_dat *last; - struct tbl_span *prev; - struct tbl_span *next; - int line; /* parse line */ - enum tbl_spant pos; -}; - -enum eqn_boxt { - EQN_TEXT, /* text (number, variable, whatever) */ - EQN_SUBEXPR, /* nested `eqn' subexpression */ - EQN_LIST, /* list (braces, etc.) */ - EQN_PILE, /* vertical pile */ - EQN_MATRIX /* pile of piles */ -}; - -enum eqn_fontt { - EQNFONT_NONE = 0, - EQNFONT_ROMAN, - EQNFONT_BOLD, - EQNFONT_FAT, - EQNFONT_ITALIC, - EQNFONT__MAX -}; - -enum eqn_post { - EQNPOS_NONE = 0, - EQNPOS_SUP, - EQNPOS_SUBSUP, - EQNPOS_SUB, - EQNPOS_TO, - EQNPOS_FROM, - EQNPOS_FROMTO, - EQNPOS_OVER, - EQNPOS_SQRT, - EQNPOS__MAX -}; - -enum eqn_pilet { - EQNPILE_NONE = 0, - EQNPILE_PILE, - EQNPILE_CPILE, - EQNPILE_RPILE, - EQNPILE_LPILE, - EQNPILE_COL, - EQNPILE_CCOL, - EQNPILE_RCOL, - EQNPILE_LCOL, - EQNPILE__MAX -}; - - /* - * A "box" is a parsed mathematical expression as defined by the eqn.7 - * grammar. - */ -struct eqn_box { - int size; /* font size of expression */ -#define EQN_DEFSIZE INT_MIN - enum eqn_boxt type; /* type of node */ - struct eqn_box *first; /* first child node */ - struct eqn_box *last; /* last child node */ - struct eqn_box *next; /* node sibling */ - struct eqn_box *prev; /* node sibling */ - struct eqn_box *parent; /* node sibling */ - char *text; /* text (or NULL) */ - char *left; /* fence left-hand */ - char *right; /* fence right-hand */ - char *top; /* expression over-symbol */ - char *bottom; /* expression under-symbol */ - size_t args; /* arguments in parent */ - size_t expectargs; /* max arguments in parent */ - enum eqn_post pos; /* position of next box */ - enum eqn_fontt font; /* font of box */ - enum eqn_pilet pile; /* equation piling */ -}; - -/* - * Parse options. - */ -#define MPARSE_MDOC 1 /* assume -mdoc */ -#define MPARSE_MAN 2 /* assume -man */ -#define MPARSE_SO 4 /* honour .so requests */ -#define MPARSE_QUICK 8 /* abort the parse early */ -#define MPARSE_UTF8 16 /* accept UTF-8 input */ -#define MPARSE_LATIN1 32 /* accept ISO-LATIN-1 input */ - -enum mandoc_os { - MANDOC_OS_OTHER = 0, - MANDOC_OS_NETBSD, - MANDOC_OS_OPENBSD -}; - enum mandoc_esc { ESCAPE_ERROR = 0, /* bail! unparsable escape */ + ESCAPE_UNSUPP, /* unsupported escape; ignore it */ ESCAPE_IGNORE, /* escape to be ignored */ + ESCAPE_UNDEF, /* undefined escape; print literal character */ ESCAPE_SPECIAL, /* a regular special character */ ESCAPE_FONT, /* a generic font mode */ ESCAPE_FONTBOLD, /* bold font mode */ ESCAPE_FONTITALIC, /* italic font mode */ ESCAPE_FONTBI, /* bold italic font mode */ ESCAPE_FONTROMAN, /* roman font mode */ + ESCAPE_FONTCW, /* constant width font mode */ ESCAPE_FONTPREV, /* previous font mode */ ESCAPE_NUMBERED, /* a numbered glyph */ ESCAPE_UNICODE, /* a unicode codepoint */ + ESCAPE_DEVICE, /* print the output device name */ ESCAPE_BREAK, /* break the output line */ ESCAPE_NOSPACE, /* suppress space if the last on a line */ ESCAPE_HORIZ, /* horizontal movement */ @@ -439,14 +269,18 @@ enum mandoc_esc { ESCAPE_OVERSTRIKE /* overstrike all chars in the argument */ }; -typedef void (*mandocmsg)(enum mandocerr, enum mandoclevel, - const char *, int, int, const char *); - - -struct mparse; -struct roff_man; +enum mandoc_esc mandoc_font(const char *, int sz); enum mandoc_esc mandoc_escape(const char **, const char **, int *); +void mandoc_msg_setoutfile(FILE *); +const char *mandoc_msg_getinfilename(void); +void mandoc_msg_setinfilename(const char *); +enum mandocerr mandoc_msg_getmin(void); +void mandoc_msg_setmin(enum mandocerr); +enum mandoclevel mandoc_msg_getrc(void); +void mandoc_msg_setrc(enum mandoclevel); +void mandoc_msg(enum mandocerr, int, int, const char *, ...) + __attribute__((__format__ (__printf__, 4, 5))); void mchars_alloc(void); void mchars_free(void); int mchars_num2char(const char *, size_t); @@ -454,18 +288,3 @@ const char *mchars_uc2str(int); int mchars_num2uc(const char *, size_t); int mchars_spec2cp(const char *, size_t); const char *mchars_spec2str(const char *, size_t, size_t *); -struct mparse *mparse_alloc(int, enum mandocerr, mandocmsg, - enum mandoc_os, const char *); -void mparse_free(struct mparse *); -void mparse_keep(struct mparse *); -int mparse_open(struct mparse *, const char *); -enum mandoclevel mparse_readfd(struct mparse *, int, const char *); -enum mandoclevel mparse_readmem(struct mparse *, void *, size_t, - const char *); -void mparse_reset(struct mparse *); -void mparse_result(struct mparse *, - struct roff_man **, char **); -const char *mparse_getkeep(const struct mparse *); -const char *mparse_strerror(enum mandocerr); -const char *mparse_strlevel(enum mandoclevel); -void mparse_updaterc(struct mparse *, enum mandoclevel *); diff --git a/usr/src/cmd/mandoc/mandoc_msg.c b/usr/src/cmd/mandoc/mandoc_msg.c new file mode 100644 index 0000000000..ff4d80313c --- /dev/null +++ b/usr/src/cmd/mandoc/mandoc_msg.c @@ -0,0 +1,329 @@ +/* $Id: mandoc_msg.c,v 1.6 2019/03/06 15:55:38 schwarze Exp $ */ +/* + * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * 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 + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> + +#include "mandoc.h" + +static const enum mandocerr lowest_type[MANDOCLEVEL_MAX] = { + MANDOCERR_OK, + MANDOCERR_OK, + MANDOCERR_WARNING, + MANDOCERR_ERROR, + MANDOCERR_UNSUPP, + MANDOCERR_MAX, + MANDOCERR_MAX +}; + +static const char *const level_name[MANDOCLEVEL_MAX] = { + "SUCCESS", + "STYLE", + "WARNING", + "ERROR", + "UNSUPP", + "BADARG", + "SYSERR" +}; + +static const char *const type_message[MANDOCERR_MAX] = { + "ok", + + "base system convention", + + "Mdocdate found", + "Mdocdate missing", + "unknown architecture", + "operating system explicitly specified", + "RCS id missing", + "referenced manual not found", + + "generic style suggestion", + + "legacy man(7) date format", + "normalizing date format to", + "lower case character in document title", + "duplicate RCS id", + "possible typo in section name", + "unterminated quoted argument", + "useless macro", + "consider using OS macro", + "errnos out of order", + "duplicate errno", + "trailing delimiter", + "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", + + "generic warning", + + /* related to the prologue */ + "missing manual title, using UNTITLED", + "missing manual title, using \"\"", + "missing manual section, using \"\"", + "unknown manual section", + "missing date, using today's date", + "cannot parse date, using it verbatim", + "date in the future, using it anyway", + "missing Os macro, using \"\"", + "late prologue macro", + "prologue macros out of order", + + /* related to document structure */ + ".so is fragile, better use ln(1)", + "no document body", + "content before first section header", + "first section is not \"NAME\"", + "NAME section without Nm before Nd", + "NAME section without description", + "description not at the end of NAME", + "bad NAME section content", + "missing comma before name", + "missing description line, using \"\"", + "description line outside NAME section", + "sections out of conventional order", + "duplicate section title", + "unexpected section", + "cross reference to self", + "unusual Xr order", + "unusual Xr punctuation", + "AUTHORS section without An macro", + + /* related to macros and nesting */ + "obsolete macro", + "macro neither callable nor escaped", + "skipping paragraph macro", + "moving paragraph macro out of list", + "skipping no-space macro", + "blocks badly nested", + "nested displays are not portable", + "moving content out of list", + "first macro on line", + "line scope broken", + "skipping blank line in line scope", + + /* related to missing macro arguments */ + "skipping empty request", + "conditional request controls empty scope", + "skipping empty macro", + "empty block", + "empty argument, using 0n", + "missing display type, using -ragged", + "list type is not the first argument", + "missing -width in -tag list, using 6n", + "missing utility name, using \"\"", + "missing function name, using \"\"", + "empty head in list item", + "empty list item", + "missing argument, using next line", + "missing font type, using \\fR", + "unknown font type, using \\fR", + "nothing follows prefix", + "empty reference block", + "missing section argument", + "missing -std argument, adding it", + "missing option string, using \"\"", + "missing resource identifier, using \"\"", + "missing eqn box, using \"\"", + + /* related to bad macro arguments */ + "duplicate argument", + "skipping duplicate argument", + "skipping duplicate display type", + "skipping duplicate list type", + "skipping -width argument", + "wrong number of cells", + "unknown AT&T UNIX version", + "comma in function argument", + "parenthesis in function name", + "unknown library name", + "invalid content in Rs block", + "invalid Boolean argument", + "argument contains two font escapes", + "unknown font, skipping request", + "odd number of characters in request", + + /* related to plain text */ + "blank line in fill mode, using .sp", + "tab in filled text", + "new sentence, new line", + "invalid escape sequence", + "undefined escape, printing literally", + "undefined string, using \"\"", + + /* related to tables */ + "tbl line starts with span", + "tbl column starts with span", + "skipping vertical bar in tbl layout", + + "generic error", + + /* related to tables */ + "non-alphabetic character in tbl options", + "skipping unknown tbl option", + "missing tbl option argument", + "wrong tbl option argument size", + "empty tbl layout", + "invalid character in tbl layout", + "unmatched parenthesis in tbl layout", + "tbl without any data cells", + "ignoring data in spanned tbl cell", + "ignoring extra tbl data cells", + "data block open at end of tbl", + + /* related to document structure and macros */ + NULL, + "duplicate prologue macro", + "skipping late title macro", + "input stack limit exceeded, infinite loop?", + "skipping bad character", + "skipping unknown macro", + "ignoring request outside macro", + "skipping insecure request", + "skipping item outside list", + "skipping column outside column list", + "skipping end of block that is not open", + "fewer RS blocks open, skipping", + "inserting missing end of block", + "appending missing end of block", + + /* related to request and macro arguments */ + "escaped character not allowed in a name", + "using macro argument outside macro", + "argument number is not numeric", + "NOT IMPLEMENTED: Bd -file", + "skipping display without arguments", + "missing list type, using -item", + "argument is not numeric, using 1", + "argument is not a character", + "missing manual name, using \"\"", + "uname(3) system call failed, using UNKNOWN", + "unknown standard specifier", + "skipping request without numeric argument", + "excessive shift", + "NOT IMPLEMENTED: .so with absolute path or \"..\"", + ".so request failed", + "skipping all arguments", + "skipping excess arguments", + "divide by zero", + + "unsupported feature", + "input too large", + "unsupported control character", + "unsupported escape sequence", + "unsupported roff request", + "nested .while loops", + "end of scope with open .while loop", + "end of .while loop in inner scope", + "cannot continue this .while loop", + "eqn delim option in tbl", + "unsupported tbl layout modifier", + "ignoring macro in table", +}; + +static FILE *fileptr = NULL; +static const char *filename = NULL; +static enum mandocerr min_type = MANDOCERR_MAX; +static enum mandoclevel rc = MANDOCLEVEL_OK; + + +void +mandoc_msg_setoutfile(FILE *fp) +{ + fileptr = fp; +} + +const char * +mandoc_msg_getinfilename(void) +{ + return filename; +} + +void +mandoc_msg_setinfilename(const char *fn) +{ + filename = fn; +} + +enum mandocerr +mandoc_msg_getmin(void) +{ + return min_type; +} + +void +mandoc_msg_setmin(enum mandocerr t) +{ + min_type = t; +} + +enum mandoclevel +mandoc_msg_getrc(void) +{ + return rc; +} + +void +mandoc_msg_setrc(enum mandoclevel level) +{ + if (rc < level) + rc = level; +} + +void +mandoc_msg(enum mandocerr t, int line, int col, const char *fmt, ...) +{ + va_list ap; + enum mandoclevel level; + + if (t < min_type && t != MANDOCERR_FILE) + return; + + level = MANDOCLEVEL_UNSUPP; + while (t < lowest_type[level]) + level--; + mandoc_msg_setrc(level); + + if (fileptr == NULL) + return; + + fprintf(fileptr, "%s:", getprogname()); + if (filename != NULL) + fprintf(fileptr, " %s:", filename); + + if (line > 0) + fprintf(fileptr, "%d:%d:", line, col + 1); + + fprintf(fileptr, " %s", level_name[level]); + if (type_message[t] != NULL) + fprintf(fileptr, ": %s", type_message[t]); + + if (fmt != NULL) { + fprintf(fileptr, ": "); + va_start(ap, fmt); + vfprintf(fileptr, fmt, ap); + va_end(ap); + } + fputc('\n', fileptr); +} diff --git a/usr/src/cmd/mandoc/mandoc_parse.h b/usr/src/cmd/mandoc/mandoc_parse.h new file mode 100644 index 0000000000..61341f0d7f --- /dev/null +++ b/usr/src/cmd/mandoc/mandoc_parse.h @@ -0,0 +1,43 @@ +/* $Id: mandoc_parse.h,v 1.4 2018/12/30 00:49:55 schwarze Exp $ */ +/* + * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * 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 + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Top level parser interface. For use in the main program + * and in the main parser, but not in formatters. + */ + +/* + * Parse options. + */ +#define MPARSE_MDOC (1 << 0) /* assume -mdoc */ +#define MPARSE_MAN (1 << 1) /* assume -man */ +#define MPARSE_SO (1 << 2) /* honour .so requests */ +#define MPARSE_QUICK (1 << 3) /* abort the parse early */ +#define MPARSE_UTF8 (1 << 4) /* accept UTF-8 input */ +#define MPARSE_LATIN1 (1 << 5) /* accept ISO-LATIN-1 input */ +#define MPARSE_VALIDATE (1 << 6) /* call validation functions */ + + +struct roff_meta; +struct mparse; + +struct mparse *mparse_alloc(int, enum mandoc_os, const char *); +void mparse_copy(const struct mparse *); +void mparse_free(struct mparse *); +int mparse_open(struct mparse *, const char *); +void mparse_readfd(struct mparse *, int, const char *); +void mparse_reset(struct mparse *); +struct roff_meta *mparse_result(struct mparse *); diff --git a/usr/src/cmd/mandoc/mandocdb.c b/usr/src/cmd/mandoc/mandocdb.c index 86dbce2d9f..222350c987 100644 --- a/usr/src/cmd/mandoc/mandocdb.c +++ b/usr/src/cmd/mandoc/mandocdb.c @@ -1,7 +1,7 @@ -/* $Id: mandocdb.c,v 1.258 2018/02/23 18:25:57 schwarze Exp $ */ +/* $Id: mandocdb.c,v 1.262 2018/12/30 00:49:55 schwarze Exp $ */ /* * Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2011-2017 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2011-2018 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2016 Ed Maste <emaste@freebsd.org> * * Permission to use, copy, modify, and distribute this software for any @@ -52,6 +52,7 @@ #include "roff.h" #include "mdoc.h" #include "man.h" +#include "mandoc_parse.h" #include "manconf.h" #include "mansearch.h" #include "dba_array.h" @@ -185,7 +186,7 @@ static struct ohash names; /* table of all names */ static struct ohash strings; /* table of all strings */ static uint64_t name_mask; -static const struct mdoc_handler __mdocs[MDOC_MAX - MDOC_Dd] = { +static const struct mdoc_handler mdoc_handlers[MDOC_MAX - MDOC_Dd] = { { NULL, 0, NODE_NOPRT }, /* Dd */ { NULL, 0, NODE_NOPRT }, /* Dt */ { NULL, 0, NODE_NOPRT }, /* Os */ @@ -307,7 +308,6 @@ static const struct mdoc_handler __mdocs[MDOC_MAX - MDOC_Dd] = { { NULL, 0, 0 }, /* %U */ { NULL, 0, 0 }, /* Ta */ }; -static const struct mdoc_handler *const mdocs = __mdocs - MDOC_Dd; int @@ -347,6 +347,7 @@ mandocdb(int argc, char *argv[]) goto usage; \ } while (/*CONSTCOND*/0) + mparse_options = MPARSE_VALIDATE; path_arg = NULL; op = OP_DEFAULT; @@ -422,8 +423,7 @@ mandocdb(int argc, char *argv[]) exitcode = (int)MANDOCLEVEL_OK; mchars_alloc(); - mp = mparse_alloc(mparse_options, MANDOCERR_MAX, NULL, - MANDOC_OS_OTHER, NULL); + mp = mparse_alloc(mparse_options, MANDOC_OS_OTHER, NULL); mandoc_ohash_init(&mpages, 6, offsetof(struct mpage, inodev)); mandoc_ohash_init(&mlinks, 6, offsetof(struct mlink, file)); @@ -1116,8 +1116,7 @@ mpages_merge(struct dba *dba, struct mparse *mp) { struct mpage *mpage, *mpage_dest; struct mlink *mlink, *mlink_dest; - struct roff_man *man; - char *sodest; + struct roff_meta *meta; char *cp; int fd; @@ -1130,8 +1129,7 @@ mpages_merge(struct dba *dba, struct mparse *mp) mandoc_ohash_init(&names, 4, offsetof(struct str, key)); mandoc_ohash_init(&strings, 6, offsetof(struct str, key)); mparse_reset(mp); - man = NULL; - sodest = NULL; + meta = NULL; if ((fd = mparse_open(mp, mlink->file)) == -1) { say(mlink->file, "&open"); @@ -1146,14 +1144,14 @@ mpages_merge(struct dba *dba, struct mparse *mp) mparse_readfd(mp, fd, mlink->file); close(fd); fd = -1; - mparse_result(mp, &man, &sodest); + meta = mparse_result(mp); } - if (sodest != NULL) { + if (meta != NULL && meta->sodest != NULL) { mlink_dest = ohash_find(&mlinks, - ohash_qlookup(&mlinks, sodest)); + ohash_qlookup(&mlinks, meta->sodest)); if (mlink_dest == NULL) { - mandoc_asprintf(&cp, "%s.gz", sodest); + mandoc_asprintf(&cp, "%s.gz", meta->sodest); mlink_dest = ohash_find(&mlinks, ohash_qlookup(&mlinks, cp)); free(cp); @@ -1190,39 +1188,36 @@ mpages_merge(struct dba *dba, struct mparse *mp) mpage->mlinks = NULL; } goto nextpage; - } else if (man != NULL && man->macroset == MACROSET_MDOC) { - mdoc_validate(man); + } else if (meta != NULL && meta->macroset == MACROSET_MDOC) { mpage->form = FORM_SRC; - mpage->sec = man->meta.msec; + mpage->sec = meta->msec; mpage->sec = mandoc_strdup( mpage->sec == NULL ? "" : mpage->sec); - mpage->arch = man->meta.arch; + mpage->arch = meta->arch; mpage->arch = mandoc_strdup( mpage->arch == NULL ? "" : mpage->arch); - mpage->title = mandoc_strdup(man->meta.title); - } else if (man != NULL && man->macroset == MACROSET_MAN) { - man_validate(man); - if (*man->meta.msec != '\0' || - *man->meta.title != '\0') { + mpage->title = mandoc_strdup(meta->title); + } else if (meta != NULL && meta->macroset == MACROSET_MAN) { + if (*meta->msec != '\0' || *meta->title != '\0') { mpage->form = FORM_SRC; - mpage->sec = mandoc_strdup(man->meta.msec); + mpage->sec = mandoc_strdup(meta->msec); mpage->arch = mandoc_strdup(mlink->arch); - mpage->title = mandoc_strdup(man->meta.title); + mpage->title = mandoc_strdup(meta->title); } else - man = NULL; + meta = NULL; } assert(mpage->desc == NULL); - if (man == NULL) { + if (meta == NULL) { mpage->form = FORM_CAT; mpage->sec = mandoc_strdup(mlink->dsec); mpage->arch = mandoc_strdup(mlink->arch); mpage->title = mandoc_strdup(mlink->name); parse_cat(mpage, fd); - } else if (man->macroset == MACROSET_MDOC) - parse_mdoc(mpage, &man->meta, man->first); + } else if (meta->macroset == MACROSET_MDOC) + parse_mdoc(mpage, meta, meta->first); else - parse_man(mpage, &man->meta, man->first); + parse_man(mpage, meta, meta->first); if (mpage->desc == NULL) { mpage->desc = mandoc_strdup(mlink->name); if (warnings) @@ -1546,25 +1541,28 @@ static void parse_mdoc(struct mpage *mpage, const struct roff_meta *meta, const struct roff_node *n) { + const struct mdoc_handler *handler; for (n = n->child; n != NULL; n = n->next) { - if (n->tok == TOKEN_NONE || - n->tok < ROFF_MAX || - n->flags & mdocs[n->tok].taboo) + if (n->tok == TOKEN_NONE || n->tok < ROFF_MAX) continue; assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX); + handler = mdoc_handlers + (n->tok - MDOC_Dd); + if (n->flags & handler->taboo) + continue; + switch (n->type) { case ROFFT_ELEM: case ROFFT_BLOCK: case ROFFT_HEAD: case ROFFT_BODY: case ROFFT_TAIL: - if (mdocs[n->tok].fp != NULL && - (*mdocs[n->tok].fp)(mpage, meta, n) == 0) + if (handler->fp != NULL && + (*handler->fp)(mpage, meta, n) == 0) break; - if (mdocs[n->tok].mask) + if (handler->mask) putmdockey(mpage, n->child, - mdocs[n->tok].mask, mdocs[n->tok].taboo); + handler->mask, handler->taboo); break; default: continue; diff --git a/usr/src/cmd/mandoc/manpath.c b/usr/src/cmd/mandoc/manpath.c index 54f7a6b110..74f38a95db 100644 --- a/usr/src/cmd/mandoc/manpath.c +++ b/usr/src/cmd/mandoc/manpath.c @@ -1,6 +1,6 @@ -/* $Id: manpath.c,v 1.35 2017/07/01 09:47:30 schwarze Exp $ */ +/* $Id: manpath.c,v 1.37 2018/11/22 11:30:23 schwarze Exp $ */ /* - * Copyright (c) 2011, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2011,2014,2015,2017,2018 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv> * * Permission to use, copy, modify, and distribute this software for any @@ -232,8 +232,8 @@ int manconf_output(struct manoutput *conf, const char *cp, int fromfile) { const char *const toks[] = { - "includes", "man", "paper", "style", - "indent", "width", "fragment", "mdoc", "noval" + "includes", "man", "paper", "style", "indent", "width", + "tag", "fragment", "mdoc", "noval", "toc" }; const char *errstr; @@ -257,7 +257,7 @@ manconf_output(struct manoutput *conf, const char *cp, int fromfile) warnx("-O %s=?: Missing argument value", toks[tok]); return -1; } - if ((tok == 6 || tok == 7) && *cp != '\0') { + if (tok > 6 && *cp != '\0') { warnx("-O %s: Does not take a value: %s", toks[tok], cp); return -1; } @@ -312,14 +312,24 @@ manconf_output(struct manoutput *conf, const char *cp, int fromfile) warnx("-O width=%s is %s", cp, errstr); return -1; case 6: - conf->fragment = 1; + if (conf->tag != NULL) { + oldval = mandoc_strdup(conf->tag); + break; + } + conf->tag = mandoc_strdup(cp); return 0; case 7: - conf->mdoc = 1; + conf->fragment = 1; return 0; case 8: + conf->mdoc = 1; + return 0; + case 9: conf->noval = 1; return 0; + case 10: + conf->toc = 1; + return 0; default: if (fromfile) warnx("-O %s: Bad argument", cp); diff --git a/usr/src/cmd/mandoc/mansearch.c b/usr/src/cmd/mandoc/mansearch.c index 784c17bee7..4e968332e3 100644 --- a/usr/src/cmd/mandoc/mansearch.c +++ b/usr/src/cmd/mandoc/mansearch.c @@ -1,7 +1,7 @@ -/* $Id: mansearch.c,v 1.77 2017/08/22 17:50:11 schwarze Exp $ */ +/* $Id: mansearch.c,v 1.80 2018/12/13 11:55:46 schwarze Exp $ */ /* * Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2013-2017 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 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 @@ -36,7 +36,6 @@ #include <string.h> #include <unistd.h> -#include "mandoc.h" #include "mandoc_aux.h" #include "mandoc_ohash.h" #include "manconf.h" @@ -192,7 +191,7 @@ mansearch(const struct mansearch *search, mpage->file, R_OK) == -1) { warn("%s", mpage->file); warnx("outdated mandoc.db contains " - "bogus %s entry, run makewhatis %s", + "bogus %s entry, run makewhatis %s", page->file + 1, paths->paths[i]); free(mpage->file); free(rp); @@ -201,7 +200,6 @@ mansearch(const struct mansearch *search, mpage->names = buildnames(page); mpage->output = buildoutput(outkey, page); mpage->ipath = i; - mpage->bits = rp->bits; mpage->sec = *page->sect - '0'; if (mpage->sec < 0 || mpage->sec > 9) mpage->sec = 10; @@ -296,10 +294,8 @@ manmerge_term(struct expr *e, struct ohash *htab) break; slot = ohash_lookup_memory(htab, (char *)&res, sizeof(res.page), res.page); - if ((rp = ohash_find(htab, slot)) != NULL) { - rp->bits |= res.bits; + if ((rp = ohash_find(htab, slot)) != NULL) continue; - } rp = mandoc_malloc(sizeof(*rp)); *rp = res; ohash_insert(htab, slot, rp); @@ -412,8 +408,7 @@ manpage_compare(const void *vp1, const void *vp2) mp1 = vp1; mp2 = vp2; - if ((diff = mp2->bits - mp1->bits) || - (diff = mp1->sec - mp2->sec)) + if ((diff = mp1->sec - mp2->sec)) return diff; /* Fall back to alphabetic ordering of names. */ @@ -774,8 +769,9 @@ exprterm(const struct mansearch *search, int argc, char *argv[], int *argi) cs = 0; } else if ((val = strpbrk(argv[*argi], "=~")) == NULL) { e->bits = TYPE_Nm | TYPE_Nd; - e->match.type = DBM_SUB; - e->match.str = argv[*argi]; + e->match.type = DBM_REGEX; + val = argv[*argi]; + cs = 0; } else { if (val == argv[*argi]) e->bits = TYPE_Nm | TYPE_Nd; diff --git a/usr/src/cmd/mandoc/mansearch.h b/usr/src/cmd/mandoc/mansearch.h index cc4f364f69..355873f83e 100644 --- a/usr/src/cmd/mandoc/mansearch.h +++ b/usr/src/cmd/mandoc/mansearch.h @@ -1,4 +1,4 @@ -/* $Id: mansearch.h,v 1.28 2017/04/17 20:05:08 schwarze Exp $ */ +/* $Id: mansearch.h,v 1.29 2018/11/22 12:01:46 schwarze Exp $ */ /* * Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2013, 2014, 2016, 2017 Ingo Schwarze <schwarze@openbsd.org> @@ -93,7 +93,6 @@ struct manpage { char *names; /* a list of names with sections */ char *output; /* user-defined additional output */ size_t ipath; /* number of the manpath */ - uint64_t bits; /* name type mask */ int sec; /* section number, 10 means invalid */ enum form form; }; diff --git a/usr/src/cmd/mandoc/mdoc.c b/usr/src/cmd/mandoc/mdoc.c index 71803531dd..bb3ec58bd0 100644 --- a/usr/src/cmd/mandoc/mdoc.c +++ b/usr/src/cmd/mandoc/mdoc.c @@ -1,7 +1,7 @@ -/* $Id: mdoc.c,v 1.268 2017/08/11 16:56:21 schwarze Exp $ */ +/* $Id: mdoc.c,v 1.274 2018/12/31 07:46:07 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> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -80,13 +80,6 @@ mdoc_parseln(struct roff_man *mdoc, int ln, char *buf, int offs) } void -mdoc_macro(MACRO_PROT_ARGS) -{ - assert(tok >= MDOC_Dd && tok < MDOC_MAX); - (*mdoc_macros[tok].fp)(mdoc, tok, line, ppos, pos, buf); -} - -void mdoc_tail_alloc(struct roff_man *mdoc, int line, int pos, enum roff_tok tok) { struct roff_node *p; @@ -162,15 +155,6 @@ mdoc_elem_alloc(struct roff_man *mdoc, int line, int pos, mdoc->next = ROFF_NEXT_CHILD; } -void -mdoc_node_relink(struct roff_man *mdoc, struct roff_node *p) -{ - - roff_node_unlink(mdoc, p); - p->prev = p->next = NULL; - roff_node_append(mdoc, p); -} - /* * Parse free-form text, that is, a line that does not begin with the * control character. @@ -196,7 +180,8 @@ mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs) (n->parent != NULL && n->parent->tok == MDOC_Bl && n->parent->norm->Bl.type == LIST_column)) { mdoc->flags |= MDOC_FREECOL; - mdoc_macro(mdoc, MDOC_It, line, offs, &offs, buf); + (*mdoc_macro(MDOC_It)->fp)(mdoc, MDOC_It, + line, offs, &offs, buf); return 1; } @@ -225,7 +210,7 @@ mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs) * Strip trailing tabs in literal context only; * outside, they affect the next line. */ - if (MDOC_LITERAL & mdoc->flags) + if (mdoc->flags & ROFF_NOFILL) continue; break; case '\\': @@ -242,8 +227,7 @@ mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs) *end = '\0'; if (ws) - mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse, - line, (int)(ws-buf), NULL); + mandoc_msg(MANDOCERR_SPACE_EOL, line, (int)(ws - buf), NULL); /* * Blank lines are allowed in no-fill mode @@ -251,7 +235,7 @@ mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs) * but add a single vertical space elsewhere. */ - if (buf[offs] == '\0' && ! (mdoc->flags & MDOC_LITERAL)) { + if (buf[offs] == '\0' && (mdoc->flags & ROFF_NOFILL) == 0) { switch (mdoc->last->type) { case ROFFT_TEXT: sp = mdoc->last->string; @@ -267,8 +251,7 @@ mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs) default: break; } - mandoc_msg(MANDOCERR_FI_BLANK, mdoc->parse, - line, (int)(c - buf), NULL); + mandoc_msg(MANDOCERR_FI_BLANK, line, (int)(c - buf), NULL); roff_elem_alloc(mdoc, line, offs, ROFF_sp); mdoc->last->flags |= NODE_VALID | NODE_ENDED; mdoc->next = ROFF_NEXT_SIBLING; @@ -277,7 +260,7 @@ mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs) roff_word_alloc(mdoc, line, offs, buf+offs); - if (mdoc->flags & MDOC_LITERAL) + if (mdoc->flags & ROFF_NOFILL) return 1; /* @@ -308,8 +291,7 @@ mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs) if (*c == ' ') c++; if (isupper((unsigned char)(*c))) - mandoc_msg(MANDOCERR_EOS, mdoc->parse, - line, (int)(c - buf), NULL); + mandoc_msg(MANDOCERR_EOS, line, (int)(c - buf), NULL); } return 1; @@ -337,8 +319,7 @@ mdoc_pmacro(struct roff_man *mdoc, int ln, char *buf, int offs) if (sz == 2 || sz == 3) tok = roffhash_find(mdoc->mdocmac, buf + sv, sz); if (tok == TOKEN_NONE) { - mandoc_msg(MANDOCERR_MACRO, mdoc->parse, - ln, sv, buf + sv - 1); + mandoc_msg(MANDOCERR_MACRO, ln, sv, "%s", buf + sv - 1); return 1; } @@ -368,8 +349,7 @@ mdoc_pmacro(struct roff_man *mdoc, int ln, char *buf, int offs) */ if ('\0' == buf[offs] && ' ' == buf[offs - 1]) - mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse, - ln, offs - 1, NULL); + mandoc_msg(MANDOCERR_SPACE_EOL, ln, offs - 1, NULL); /* * If an initial macro or a list invocation, divert directly @@ -378,7 +358,7 @@ mdoc_pmacro(struct roff_man *mdoc, int ln, char *buf, int offs) n = mdoc->last; if (n == NULL || tok == MDOC_It || tok == MDOC_El) { - mdoc_macro(mdoc, tok, ln, sv, &offs, buf); + (*mdoc_macro(tok)->fp)(mdoc, tok, ln, sv, &offs, buf); return 1; } @@ -394,13 +374,13 @@ mdoc_pmacro(struct roff_man *mdoc, int ln, char *buf, int offs) (n->parent != NULL && n->parent->tok == MDOC_Bl && n->parent->norm->Bl.type == LIST_column)) { mdoc->flags |= MDOC_FREECOL; - mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf); + (*mdoc_macro(MDOC_It)->fp)(mdoc, MDOC_It, ln, sv, &sv, buf); return 1; } /* Normal processing of a macro. */ - mdoc_macro(mdoc, tok, ln, sv, &offs, buf); + (*mdoc_macro(tok)->fp)(mdoc, tok, ln, sv, &offs, buf); /* In quick mode (for mandocdb), abort after the NAME section. */ @@ -448,12 +428,3 @@ mdoc_isdelim(const char *p) return DELIM_NONE; } - -void -mdoc_validate(struct roff_man *mdoc) -{ - - mdoc->last = mdoc->first; - mdoc_node_validate(mdoc); - mdoc_state_reset(mdoc); -} diff --git a/usr/src/cmd/mandoc/mdoc.h b/usr/src/cmd/mandoc/mdoc.h index 1628e0c80c..2f32fa4962 100644 --- a/usr/src/cmd/mandoc/mdoc.h +++ b/usr/src/cmd/mandoc/mdoc.h @@ -1,4 +1,4 @@ -/* $Id: mdoc.h,v 1.145 2017/04/24 23:06:18 schwarze Exp $ */ +/* $Id: mdoc.h,v 1.146 2018/12/30 00:49:55 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org> @@ -16,6 +16,9 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +struct roff_node; +struct roff_man; + enum mdocargt { MDOC_Split, /* -split */ MDOC_Nosplit, /* -nospli */ diff --git a/usr/src/cmd/mandoc/mdoc_argv.c b/usr/src/cmd/mandoc/mdoc_argv.c index db4c63f0d6..f4ce4a8730 100644 --- a/usr/src/cmd/mandoc/mdoc_argv.c +++ b/usr/src/cmd/mandoc/mdoc_argv.c @@ -1,7 +1,7 @@ -/* $Id: mdoc_argv.c,v 1.115 2017/05/30 16:22:03 schwarze Exp $ */ +/* $Id: mdoc_argv.c,v 1.119 2018/12/21 17:15:19 schwarze Exp $ */ /* * Copyright (c) 2008, 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 @@ -144,7 +144,7 @@ static const enum mdocargt args_Bl[] = { MDOC_ARG_MAX }; -static const struct mdocarg __mdocargs[MDOC_MAX - MDOC_Dd] = { +static const struct mdocarg mdocargs[MDOC_MAX - MDOC_Dd] = { { ARGSFL_NONE, NULL }, /* Dd */ { ARGSFL_NONE, NULL }, /* Dt */ { ARGSFL_NONE, NULL }, /* Os */ @@ -266,7 +266,6 @@ static const struct mdocarg __mdocargs[MDOC_MAX - MDOC_Dd] = { { ARGSFL_NONE, NULL }, /* %U */ { ARGSFL_NONE, NULL }, /* Ta */ }; -static const struct mdocarg *const mdocargs = __mdocargs - MDOC_Dd; /* @@ -290,7 +289,7 @@ mdoc_argv(struct roff_man *mdoc, int line, enum roff_tok tok, /* Which flags does this macro support? */ assert(tok >= MDOC_Dd && tok < MDOC_MAX); - argtable = mdocargs[tok].argvs; + argtable = mdocargs[tok - MDOC_Dd].argvs; if (argtable == NULL) return; @@ -368,7 +367,7 @@ mdoc_argv(struct roff_man *mdoc, int line, enum roff_tok tok, /* Prepare for parsing the next flag. */ *pos = ipos; - argtable = mdocargs[tok].argvs; + argtable = mdocargs[tok - MDOC_Dd].argvs; } } @@ -417,12 +416,9 @@ mdoc_args(struct roff_man *mdoc, int line, int *pos, char *buf, enum roff_tok tok, char **v) { struct roff_node *n; - char *v_local; enum argsflag fl; - if (v == NULL) - v = &v_local; - fl = tok == TOKEN_NONE ? ARGSFL_NONE : mdocargs[tok].flags; + fl = tok == TOKEN_NONE ? ARGSFL_NONE : mdocargs[tok - MDOC_Dd].flags; /* * We know that we're in an `It', so it's reasonable to expect @@ -449,18 +445,20 @@ args(struct roff_man *mdoc, int line, int *pos, char *buf, enum argsflag fl, char **v) { char *p; + char *v_local; int pairs; if (buf[*pos] == '\0') { if (mdoc->flags & MDOC_PHRASELIT && ! (mdoc->flags & MDOC_PHRASE)) { - mandoc_msg(MANDOCERR_ARG_QUOTE, - mdoc->parse, line, *pos, NULL); + mandoc_msg(MANDOCERR_ARG_QUOTE, line, *pos, NULL); mdoc->flags &= ~MDOC_PHRASELIT; } return ARGS_EOLN; } + if (v == NULL) + v = &v_local; *v = buf + *pos; if (fl == ARGSFL_DELIM && args_checkpunct(buf, *pos)) @@ -506,7 +504,7 @@ args(struct roff_man *mdoc, int line, int *pos, p = strchr(*v, '\0'); if (p[-1] == ' ') mandoc_msg(MANDOCERR_SPACE_EOL, - mdoc->parse, line, *pos, NULL); + line, *pos, NULL); *pos += (int)(p - *v); } @@ -527,13 +525,12 @@ args(struct roff_man *mdoc, int line, int *pos, * Whitespace is NOT involved in literal termination. */ - if (mdoc->flags & MDOC_PHRASELIT || buf[*pos] == '\"') { - if ( ! (mdoc->flags & MDOC_PHRASELIT)) + if (mdoc->flags & MDOC_PHRASELIT || + (mdoc->flags & MDOC_PHRASE && buf[*pos] == '\"')) { + if ((mdoc->flags & MDOC_PHRASELIT) == 0) { *v = &buf[++(*pos)]; - - if (mdoc->flags & MDOC_PHRASE) mdoc->flags |= MDOC_PHRASELIT; - + } pairs = 0; for ( ; buf[*pos]; (*pos)++) { /* Move following text left after quoted quotes. */ @@ -554,7 +551,7 @@ args(struct roff_man *mdoc, int line, int *pos, if (buf[*pos] == '\0') { if ( ! (mdoc->flags & MDOC_PHRASE)) mandoc_msg(MANDOCERR_ARG_QUOTE, - mdoc->parse, line, *pos, NULL); + line, *pos, NULL); return ARGS_WORD; } @@ -568,14 +565,15 @@ args(struct roff_man *mdoc, int line, int *pos, (*pos)++; if ('\0' == buf[*pos]) - mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse, - line, *pos, NULL); + mandoc_msg(MANDOCERR_SPACE_EOL, line, *pos, NULL); return ARGS_WORD; } p = &buf[*pos]; - *v = mandoc_getarg(mdoc->parse, &p, line, pos); + *v = roff_getarg(mdoc->roff, &p, line, pos); + if (v == &v_local) + free(*v); /* * After parsing the last word in this phrase, @@ -586,7 +584,7 @@ args(struct roff_man *mdoc, int line, int *pos, mdoc->flags &= ~MDOC_PHRASEQL; mdoc->flags |= MDOC_PHRASEQF; } - return ARGS_WORD; + return ARGS_ALLOC; } /* @@ -657,7 +655,9 @@ argv_multi(struct roff_man *mdoc, int line, v->value = mandoc_reallocarray(v->value, v->sz + MULTI_STEP, sizeof(char *)); - v->value[(int)v->sz] = mandoc_strdup(p); + if (ac != ARGS_ALLOC) + p = mandoc_strdup(p); + v->value[(int)v->sz] = p; } } @@ -672,7 +672,10 @@ argv_single(struct roff_man *mdoc, int line, if (ac == ARGS_EOLN) return; + if (ac != ARGS_ALLOC) + p = mandoc_strdup(p); + v->sz = 1; v->value = mandoc_malloc(sizeof(char *)); - v->value[0] = mandoc_strdup(p); + v->value[0] = p; } diff --git a/usr/src/cmd/mandoc/mdoc_html.c b/usr/src/cmd/mandoc/mdoc_html.c index f50de8a77a..87bf42a72b 100644 --- a/usr/src/cmd/mandoc/mdoc_html.c +++ b/usr/src/cmd/mandoc/mdoc_html.c @@ -1,7 +1,7 @@ -/* $Id: mdoc_html.c,v 1.310 2018/07/27 17:49:31 schwarze Exp $ */ +/* $Id: mdoc_html.c,v 1.328 2019/03/01 10:57:18 schwarze Exp $ */ /* * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2014,2015,2016,2017,2018 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2014-2019 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 @@ -42,7 +42,7 @@ #define MIN(a,b) ((/*CONSTCOND*/(a)<(b))?(a):(b)) #endif -struct htmlmdoc { +struct mdoc_html_act { int (*pre)(MDOC_ARGS); void (*post)(MDOC_ARGS); }; @@ -62,6 +62,7 @@ static int mdoc_root_pre(const struct roff_meta *, static void mdoc__x_post(MDOC_ARGS); static int mdoc__x_pre(MDOC_ARGS); +static int mdoc_abort_pre(MDOC_ARGS); static int mdoc_ad_pre(MDOC_ARGS); static int mdoc_an_pre(MDOC_ARGS); static int mdoc_ap_pre(MDOC_ARGS); @@ -119,7 +120,7 @@ static int mdoc_vt_pre(MDOC_ARGS); static int mdoc_xr_pre(MDOC_ARGS); static int mdoc_xx_pre(MDOC_ARGS); -static const struct htmlmdoc __mdocs[MDOC_MAX - MDOC_Dd] = { +static const struct mdoc_html_act mdoc_html_acts[MDOC_MAX - MDOC_Dd] = { {NULL, NULL}, /* Dd */ {NULL, NULL}, /* Dt */ {NULL, NULL}, /* Os */ @@ -154,7 +155,7 @@ static const struct htmlmdoc __mdocs[MDOC_MAX - MDOC_Dd] = { {mdoc_nd_pre, NULL}, /* Nd */ {mdoc_nm_pre, NULL}, /* Nm */ {mdoc_quote_pre, mdoc_quote_post}, /* Op */ - {mdoc_ft_pre, NULL}, /* Ot */ + {mdoc_abort_pre, NULL}, /* Ot */ {mdoc_pa_pre, NULL}, /* Pa */ {mdoc_ex_pre, NULL}, /* Rv */ {mdoc_st_pre, NULL}, /* St */ @@ -227,7 +228,7 @@ static const struct htmlmdoc __mdocs[MDOC_MAX - MDOC_Dd] = { {mdoc_em_pre, NULL}, /* Fr */ {NULL, NULL}, /* Ud */ {mdoc_lb_pre, NULL}, /* Lb */ - {mdoc_pp_pre, NULL}, /* Lp */ + {mdoc_abort_pre, NULL}, /* Lp */ {mdoc_lk_pre, NULL}, /* Lk */ {mdoc_mt_pre, NULL}, /* Mt */ {mdoc_quote_pre, mdoc_quote_post}, /* Brq */ @@ -241,7 +242,6 @@ static const struct htmlmdoc __mdocs[MDOC_MAX - MDOC_Dd] = { {mdoc__x_pre, mdoc__x_post}, /* %U */ {NULL, NULL}, /* Ta */ }; -static const struct htmlmdoc *const mdocs = __mdocs - MDOC_Dd; /* @@ -268,22 +268,21 @@ synopsis_pre(struct html *h, const struct roff_node *n) case MDOC_Fo: case MDOC_In: case MDOC_Vt: - print_paragraph(h); break; case MDOC_Ft: - if (MDOC_Fn != n->tok && MDOC_Fo != n->tok) { - print_paragraph(h); + if (n->tok != MDOC_Fn && n->tok != MDOC_Fo) break; - } /* FALLTHROUGH */ default: print_otag(h, TAG_BR, ""); - break; + return; } + html_close_paragraph(h); + print_otag(h, TAG_P, "c", "Pp"); } void -html_mdoc(void *arg, const struct roff_man *mdoc) +html_mdoc(void *arg, const struct roff_meta *mdoc) { struct html *h; struct roff_node *n; @@ -295,19 +294,19 @@ html_mdoc(void *arg, const struct roff_man *mdoc) if ((h->oflags & HTML_FRAGMENT) == 0) { print_gen_decls(h); print_otag(h, TAG_HTML, ""); - if (n->type == ROFFT_COMMENT) + if (n != NULL && n->type == ROFFT_COMMENT) print_gen_comment(h, n); t = print_otag(h, TAG_HEAD, ""); - print_mdoc_head(&mdoc->meta, h); + print_mdoc_head(mdoc, h); print_tagq(h, t); print_otag(h, TAG_BODY, ""); } - mdoc_root_pre(&mdoc->meta, h); + mdoc_root_pre(mdoc, h); t = print_otag(h, TAG_DIV, "c", "manual-text"); - print_mdoc_nodelist(&mdoc->meta, n, h); + print_mdoc_nodelist(mdoc, n, h); print_tagq(h, t); - mdoc_root_post(&mdoc->meta, h); + mdoc_root_post(mdoc, h); print_tagq(h, NULL); } @@ -346,18 +345,21 @@ print_mdoc_nodelist(MDOC_ARGS) static void print_mdoc_node(MDOC_ARGS) { - int child; struct tag *t; + int child; if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT) return; + html_fillmode(h, n->flags & NODE_NOFILL ? ROFF_nf : ROFF_fi); + child = 1; - t = h->tag; n->flags &= ~NODE_ENDED; - switch (n->type) { case ROFFT_TEXT: + t = h->tag; + t->refcnt++; + /* No tables in this mode... */ assert(NULL == h->tblt); @@ -366,15 +368,18 @@ print_mdoc_node(MDOC_ARGS) * (i.e., within a <PRE>) don't print the newline. */ if (*n->string == ' ' && n->flags & NODE_LINE && - (h->flags & (HTML_LITERAL | HTML_NONEWLINE)) == 0) + (h->flags & HTML_NONEWLINE) == 0 && + (n->flags & NODE_NOFILL) == 0) print_otag(h, TAG_BR, ""); if (NODE_DELIMC & n->flags) h->flags |= HTML_NOSPACE; print_text(h, n->string); if (NODE_DELIMO & n->flags) h->flags |= HTML_NOSPACE; - return; + break; case ROFFT_EQN: + t = h->tag; + t->refcnt++; print_eqn(h, n->eqn); break; case ROFFT_TBL: @@ -391,20 +396,22 @@ print_mdoc_node(MDOC_ARGS) * the "meta" table state. This will be reopened on the * next table element. */ - if (h->tblt != NULL) { + if (h->tblt != NULL) print_tblclose(h); - t = h->tag; - } assert(h->tblt == NULL); + t = h->tag; + t->refcnt++; if (n->tok < ROFF_MAX) { roff_html_pre(h, n); - child = 0; - break; + t->refcnt--; + print_stagq(h, t); + return; } assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX); - if (mdocs[n->tok].pre != NULL && + if (mdoc_html_acts[n->tok - MDOC_Dd].pre != NULL && (n->end == ENDBODY_NOT || n->child != NULL)) - child = (*mdocs[n->tok].pre)(meta, n, h); + child = (*mdoc_html_acts[n->tok - MDOC_Dd].pre)(meta, + n, h); break; } @@ -413,24 +420,31 @@ print_mdoc_node(MDOC_ARGS) h->flags |= HTML_PREKEEP; } - if (child && n->child) + if (child && n->child != NULL) print_mdoc_nodelist(meta, n->child, h); + t->refcnt--; print_stagq(h, t); switch (n->type) { + case ROFFT_TEXT: case ROFFT_EQN: break; default: - if (n->tok < ROFF_MAX || - mdocs[n->tok].post == NULL || + if (mdoc_html_acts[n->tok - MDOC_Dd].post == NULL || n->flags & NODE_ENDED) break; - (*mdocs[n->tok].post)(meta, n, h); + (*mdoc_html_acts[n->tok - MDOC_Dd].post)(meta, n, h); if (n->end != ENDBODY_NOT) n->body->flags |= NODE_ENDED; break; } + + if (n->flags & NODE_NOFILL && + (n->next == NULL || n->next->flags & NODE_LINE)) { + h->col++; + print_endline(h); + } } static void @@ -507,12 +521,65 @@ cond_id(const struct roff_node *n) static int mdoc_sh_pre(MDOC_ARGS) { - char *id; + struct roff_node *sn, *subn; + struct tag *t, *tsec, *tsub; + char *id; + int sc; switch (n->type) { + case ROFFT_BLOCK: + html_close_paragraph(h); + if ((h->oflags & HTML_TOC) == 0 || + h->flags & HTML_TOCDONE || + n->sec <= SEC_SYNOPSIS) { + print_otag(h, TAG_SECTION, "c", "Sh"); + break; + } + h->flags |= HTML_TOCDONE; + sc = 0; + for (sn = n->next; sn != NULL; sn = sn->next) + if (sn->sec == SEC_CUSTOM) + if (++sc == 2) + break; + if (sc < 2) + break; + t = print_otag(h, TAG_H1, "c", "Sh"); + print_text(h, "TABLE OF CONTENTS"); + print_tagq(h, t); + t = print_otag(h, TAG_UL, "c", "Bl-compact"); + for (sn = n; sn != NULL; sn = sn->next) { + tsec = print_otag(h, TAG_LI, ""); + id = html_make_id(sn->head, 0); + tsub = print_otag(h, TAG_A, "hR", id); + free(id); + print_mdoc_nodelist(meta, sn->head->child, h); + print_tagq(h, tsub); + tsub = NULL; + for (subn = sn->body->child; subn != NULL; + subn = subn->next) { + if (subn->tok != MDOC_Ss) + continue; + id = html_make_id(subn->head, 0); + if (id == NULL) + continue; + if (tsub == NULL) + print_otag(h, TAG_UL, + "c", "Bl-compact"); + tsub = print_otag(h, TAG_LI, ""); + print_otag(h, TAG_A, "hR", id); + free(id); + print_mdoc_nodelist(meta, + subn->head->child, h); + print_tagq(h, tsub); + } + print_tagq(h, tsec); + } + print_tagq(h, t); + print_otag(h, TAG_SECTION, "c", "Sh"); + break; case ROFFT_HEAD: id = html_make_id(n, 1); - print_otag(h, TAG_H1, "cTi", "Sh", id); + print_otag(h, TAG_H1, "ci", "Sh", id); if (id != NULL) print_otag(h, TAG_A, "chR", "permalink", id); break; @@ -531,11 +598,21 @@ mdoc_ss_pre(MDOC_ARGS) { char *id; - if (n->type != ROFFT_HEAD) + switch (n->type) { + case ROFFT_BLOCK: + html_close_paragraph(h); + print_otag(h, TAG_SECTION, "c", "Ss"); return 1; + case ROFFT_HEAD: + break; + case ROFFT_BODY: + return 1; + default: + abort(); + } id = html_make_id(n, 1); - print_otag(h, TAG_H2, "cTi", "Ss", id); + print_otag(h, TAG_H2, "ci", "Ss", id); if (id != NULL) print_otag(h, TAG_A, "chR", "permalink", id); return 1; @@ -548,7 +625,7 @@ mdoc_fl_pre(MDOC_ARGS) if ((id = cond_id(n)) != NULL) print_otag(h, TAG_A, "chR", "permalink", id); - print_otag(h, TAG_CODE, "cTi", "Fl", id); + print_otag(h, TAG_CODE, "ci", "Fl", id); print_text(h, "\\-"); if (!(n->child == NULL && @@ -567,19 +644,27 @@ mdoc_cm_pre(MDOC_ARGS) if ((id = cond_id(n)) != NULL) print_otag(h, TAG_A, "chR", "permalink", id); - print_otag(h, TAG_CODE, "cTi", "Cm", id); + print_otag(h, TAG_CODE, "ci", "Cm", id); return 1; } static int mdoc_nd_pre(MDOC_ARGS) { - if (n->type != ROFFT_BODY) + switch (n->type) { + case ROFFT_BLOCK: + html_close_paragraph(h); return 1; - + case ROFFT_HEAD: + return 0; + case ROFFT_BODY: + break; + default: + abort(); + } print_text(h, "\\(em"); /* Cannot use TAG_SPAN because it may contain blocks. */ - print_otag(h, TAG_DIV, "cT", "Nd"); + print_otag(h, TAG_DIV, "c", "Nd"); return 1; } @@ -587,18 +672,21 @@ static int mdoc_nm_pre(MDOC_ARGS) { switch (n->type) { + case ROFFT_BLOCK: + break; case ROFFT_HEAD: print_otag(h, TAG_TD, ""); /* FALLTHROUGH */ case ROFFT_ELEM: - print_otag(h, TAG_CODE, "cT", "Nm"); + print_otag(h, TAG_CODE, "c", "Nm"); return 1; case ROFFT_BODY: print_otag(h, TAG_TD, ""); return 1; default: - break; + abort(); } + html_close_paragraph(h); synopsis_pre(h, n); print_otag(h, TAG_TABLE, "c", "Nm"); print_otag(h, TAG_TR, ""); @@ -611,12 +699,12 @@ mdoc_xr_pre(MDOC_ARGS) if (NULL == n->child) return 0; - if (h->base_man) - print_otag(h, TAG_A, "cThM", "Xr", + if (h->base_man1) + print_otag(h, TAG_A, "chM", "Xr", n->child->string, n->child->next == NULL ? NULL : n->child->next->string); else - print_otag(h, TAG_A, "cT", "Xr"); + print_otag(h, TAG_A, "c", "Xr"); n = n->child; print_text(h, n->string); @@ -645,7 +733,7 @@ mdoc_ns_pre(MDOC_ARGS) static int mdoc_ar_pre(MDOC_ARGS) { - print_otag(h, TAG_VAR, "cT", "Ar"); + print_otag(h, TAG_VAR, "c", "Ar"); return 1; } @@ -660,7 +748,6 @@ static int mdoc_it_pre(MDOC_ARGS) { const struct roff_node *bl; - struct tag *t; enum mdoc_list type; bl = n->parent; @@ -702,17 +789,6 @@ mdoc_it_pre(MDOC_ARGS) case LIST_tag: switch (n->type) { case ROFFT_HEAD: - if (h->style != NULL && !bl->norm->Bl.comp && - (n->parent->prev == NULL || - n->parent->prev->body == NULL || - n->parent->prev->body->child != NULL)) { - t = print_otag(h, TAG_DT, ""); - print_text(h, "\\ "); - print_tagq(h, t); - t = print_otag(h, TAG_DD, ""); - print_text(h, "\\ "); - print_tagq(h, t); - } print_otag(h, TAG_DT, ""); break; case ROFFT_BODY: @@ -746,17 +822,20 @@ mdoc_it_pre(MDOC_ARGS) static int mdoc_bl_pre(MDOC_ARGS) { - char cattr[28]; + char cattr[32]; struct mdoc_bl *bl; enum htmltag elemtype; switch (n->type) { - case ROFFT_BODY: - return 1; + case ROFFT_BLOCK: + html_close_paragraph(h); + break; case ROFFT_HEAD: return 0; + case ROFFT_BODY: + return 1; default: - break; + abort(); } bl = &n->norm->Bl; @@ -826,28 +905,34 @@ mdoc_ex_pre(MDOC_ARGS) static int mdoc_st_pre(MDOC_ARGS) { - print_otag(h, TAG_SPAN, "cT", "St"); + print_otag(h, TAG_SPAN, "c", "St"); return 1; } static int mdoc_em_pre(MDOC_ARGS) { - print_otag(h, TAG_I, "cT", "Em"); + print_otag(h, TAG_I, "c", "Em"); return 1; } static int mdoc_d1_pre(MDOC_ARGS) { - if (n->type != ROFFT_BLOCK) + switch (n->type) { + case ROFFT_BLOCK: + html_close_paragraph(h); + break; + case ROFFT_HEAD: + return 0; + case ROFFT_BODY: return 1; - + default: + abort(); + } print_otag(h, TAG_DIV, "c", "Bd Bd-indent"); - if (n->tok == MDOC_Dl) print_otag(h, TAG_CODE, "c", "Li"); - return 1; } @@ -857,7 +942,7 @@ mdoc_sx_pre(MDOC_ARGS) char *id; id = html_make_id(n, 0); - print_otag(h, TAG_A, "cThR", "Sx", id); + print_otag(h, TAG_A, "chR", "Sx", id); free(id); return 1; } @@ -865,86 +950,51 @@ mdoc_sx_pre(MDOC_ARGS) static int mdoc_bd_pre(MDOC_ARGS) { - int comp, sv; + char buf[16]; struct roff_node *nn; + int comp; - if (n->type == ROFFT_HEAD) - return 0; - - if (n->type == ROFFT_BLOCK) { - comp = n->norm->Bd.comp; - for (nn = n; nn && ! comp; nn = nn->parent) { - if (nn->type != ROFFT_BLOCK) - continue; - if (MDOC_Ss == nn->tok || MDOC_Sh == nn->tok) - comp = 1; - if (nn->prev) - break; - } - if ( ! comp) - print_paragraph(h); + switch (n->type) { + case ROFFT_BLOCK: + html_close_paragraph(h); return 1; + case ROFFT_HEAD: + return 0; + case ROFFT_BODY: + break; + default: + abort(); } - /* Handle the -offset argument. */ - - if (n->norm->Bd.offs == NULL || - ! strcmp(n->norm->Bd.offs, "left")) - print_otag(h, TAG_DIV, "c", "Bd"); - else - print_otag(h, TAG_DIV, "c", "Bd Bd-indent"); - - if (n->norm->Bd.type != DISP_unfilled && - n->norm->Bd.type != DISP_literal) - return 1; - - print_otag(h, TAG_PRE, "c", "Li"); + /* Handle preceding whitespace. */ - /* This can be recursive: save & set our literal state. */ - - sv = h->flags & HTML_LITERAL; - h->flags |= HTML_LITERAL; - - for (nn = n->child; nn; nn = nn->next) { - print_mdoc_node(meta, nn, h); - /* - * If the printed node flushes its own line, then we - * needn't do it here as well. This is hacky, but the - * notion of selective eoln whitespace is pretty dumb - * anyway, so don't sweat it. - */ - switch (nn->tok) { - case ROFF_br: - case ROFF_sp: - case MDOC_Sm: - case MDOC_Bl: - case MDOC_D1: - case MDOC_Dl: - case MDOC_Lp: - case MDOC_Pp: + comp = n->norm->Bd.comp; + for (nn = n; nn != NULL && comp == 0; nn = nn->parent) { + if (nn->type != ROFFT_BLOCK) continue; - default: + if (nn->tok == MDOC_Sh || nn->tok == MDOC_Ss) + comp = 1; + if (nn->prev != NULL) break; - } - if (h->flags & HTML_NONEWLINE || - (nn->next && ! (nn->next->flags & NODE_LINE))) - continue; - else if (nn->next) - print_text(h, "\n"); - - h->flags |= HTML_NOSPACE; } + (void)strlcpy(buf, "Bd", sizeof(buf)); + if (comp == 0) + (void)strlcat(buf, " Pp", sizeof(buf)); - if (0 == sv) - h->flags &= ~HTML_LITERAL; + /* Handle the -offset argument. */ - return 0; + if (n->norm->Bd.offs != NULL && + strcmp(n->norm->Bd.offs, "left") != 0) + (void)strlcat(buf, " Bd-indent", sizeof(buf)); + + print_otag(h, TAG_DIV, "c", buf); + return 1; } static int mdoc_pa_pre(MDOC_ARGS) { - print_otag(h, TAG_SPAN, "cT", "Pa"); + print_otag(h, TAG_SPAN, "c", "Pa"); return 1; } @@ -975,7 +1025,7 @@ mdoc_an_pre(MDOC_ARGS) if (n->sec == SEC_AUTHORS && ! (h->flags & HTML_NOSPLIT)) h->flags |= HTML_SPLIT; - print_otag(h, TAG_SPAN, "cT", "An"); + print_otag(h, TAG_SPAN, "c", "An"); return 1; } @@ -983,7 +1033,7 @@ static int mdoc_cd_pre(MDOC_ARGS) { synopsis_pre(h, n); - print_otag(h, TAG_CODE, "cT", "Cd"); + print_otag(h, TAG_CODE, "c", "Cd"); return 1; } @@ -994,7 +1044,7 @@ mdoc_dv_pre(MDOC_ARGS) if ((id = cond_id(n)) != NULL) print_otag(h, TAG_A, "chR", "permalink", id); - print_otag(h, TAG_CODE, "cTi", "Dv", id); + print_otag(h, TAG_CODE, "ci", "Dv", id); return 1; } @@ -1005,7 +1055,7 @@ mdoc_ev_pre(MDOC_ARGS) if ((id = cond_id(n)) != NULL) print_otag(h, TAG_A, "chR", "permalink", id); - print_otag(h, TAG_CODE, "cTi", "Ev", id); + print_otag(h, TAG_CODE, "ci", "Ev", id); return 1; } @@ -1022,7 +1072,7 @@ mdoc_er_pre(MDOC_ARGS) if (id != NULL) print_otag(h, TAG_A, "chR", "permalink", id); - print_otag(h, TAG_CODE, "cTi", "Er", id); + print_otag(h, TAG_CODE, "ci", "Er", id); return 1; } @@ -1033,12 +1083,12 @@ mdoc_fa_pre(MDOC_ARGS) struct tag *t; if (n->parent->tok != MDOC_Fo) { - print_otag(h, TAG_VAR, "cT", "Fa"); + print_otag(h, TAG_VAR, "c", "Fa"); return 1; } for (nn = n->child; nn; nn = nn->next) { - t = print_otag(h, TAG_VAR, "cT", "Fa"); + t = print_otag(h, TAG_VAR, "c", "Fa"); print_text(h, nn->string); print_tagq(h, t); if (nn->next) { @@ -1069,11 +1119,11 @@ mdoc_fd_pre(MDOC_ARGS) assert(n->type == ROFFT_TEXT); if (strcmp(n->string, "#include")) { - print_otag(h, TAG_CODE, "cT", "Fd"); + print_otag(h, TAG_CODE, "c", "Fd"); return 1; } - print_otag(h, TAG_CODE, "cT", "In"); + print_otag(h, TAG_CODE, "c", "In"); print_text(h, n->string); if (NULL != (n = n->next)) { @@ -1087,10 +1137,10 @@ mdoc_fd_pre(MDOC_ARGS) cp = strchr(buf, '\0') - 1; if (cp >= buf && (*cp == '>' || *cp == '"')) *cp = '\0'; - t = print_otag(h, TAG_A, "cThI", "In", buf); + t = print_otag(h, TAG_A, "chI", "In", buf); free(buf); } else - t = print_otag(h, TAG_A, "cT", "In"); + t = print_otag(h, TAG_A, "c", "In"); print_text(h, n->string); print_tagq(h, t); @@ -1117,7 +1167,7 @@ mdoc_vt_pre(MDOC_ARGS) } else if (n->type == ROFFT_HEAD) return 0; - print_otag(h, TAG_VAR, "cT", "Vt"); + print_otag(h, TAG_VAR, "c", "Vt"); return 1; } @@ -1125,7 +1175,7 @@ static int mdoc_ft_pre(MDOC_ARGS) { synopsis_pre(h, n); - print_otag(h, TAG_VAR, "cT", "Ft"); + print_otag(h, TAG_VAR, "c", "Ft"); return 1; } @@ -1146,7 +1196,7 @@ mdoc_fn_pre(MDOC_ARGS) ep = strchr(sp, ' '); if (NULL != ep) { - t = print_otag(h, TAG_VAR, "cT", "Ft"); + t = print_otag(h, TAG_VAR, "c", "Ft"); while (ep) { sz = MIN((int)(ep - sp), BUFSIZ - 1); @@ -1159,7 +1209,7 @@ mdoc_fn_pre(MDOC_ARGS) print_tagq(h, t); } - t = print_otag(h, TAG_CODE, "cT", "Fn"); + t = print_otag(h, TAG_CODE, "c", "Fn"); if (sp) print_text(h, sp); @@ -1172,10 +1222,10 @@ mdoc_fn_pre(MDOC_ARGS) for (n = n->child->next; n; n = n->next) { if (NODE_SYNPRETTY & n->flags) - t = print_otag(h, TAG_VAR, "cTs", "Fa", + t = print_otag(h, TAG_VAR, "cs", "Fa", "white-space", "nowrap"); else - t = print_otag(h, TAG_VAR, "cT", "Fa"); + t = print_otag(h, TAG_VAR, "c", "Fa"); print_text(h, n->string); print_tagq(h, t); if (n->next) { @@ -1222,8 +1272,10 @@ mdoc_skip_pre(MDOC_ARGS) static int mdoc_pp_pre(MDOC_ARGS) { - - print_paragraph(h); + if ((n->flags & NODE_NOFILL) == 0) { + html_close_paragraph(h); + print_otag(h, TAG_P, "c", "Pp"); + } return 0; } @@ -1246,7 +1298,7 @@ mdoc_lk_pre(MDOC_ARGS) descr = link->next; if (descr == punct) descr = link; /* no text */ - t = print_otag(h, TAG_A, "cTh", "Lk", link->string); + t = print_otag(h, TAG_A, "ch", "Lk", link->string); do { if (descr->flags & (NODE_DELIMC | NODE_DELIMO)) h->flags |= HTML_NOSPACE; @@ -1274,7 +1326,7 @@ mdoc_mt_pre(MDOC_ARGS) assert(n->type == ROFFT_TEXT); mandoc_asprintf(&cp, "mailto:%s", n->string); - t = print_otag(h, TAG_A, "cTh", "Mt", cp); + t = print_otag(h, TAG_A, "ch", "Mt", cp); print_text(h, n->string); print_tagq(h, t); free(cp); @@ -1302,7 +1354,7 @@ mdoc_fo_pre(MDOC_ARGS) return 0; assert(n->child->string); - t = print_otag(h, TAG_CODE, "cT", "Fn"); + t = print_otag(h, TAG_CODE, "c", "Fn"); print_text(h, n->child->string); print_tagq(h, t); return 0; @@ -1326,7 +1378,7 @@ mdoc_in_pre(MDOC_ARGS) struct tag *t; synopsis_pre(h, n); - print_otag(h, TAG_CODE, "cT", "In"); + print_otag(h, TAG_CODE, "c", "In"); /* * The first argument of the `In' gets special treatment as @@ -1345,9 +1397,9 @@ mdoc_in_pre(MDOC_ARGS) assert(n->type == ROFFT_TEXT); if (h->base_includes) - t = print_otag(h, TAG_A, "cThI", "In", n->string); + t = print_otag(h, TAG_A, "chI", "In", n->string); else - t = print_otag(h, TAG_A, "cT", "In"); + t = print_otag(h, TAG_A, "c", "In"); print_text(h, n->string); print_tagq(h, t); @@ -1372,14 +1424,14 @@ mdoc_ic_pre(MDOC_ARGS) if ((id = cond_id(n)) != NULL) print_otag(h, TAG_A, "chR", "permalink", id); - print_otag(h, TAG_CODE, "cTi", "Ic", id); + print_otag(h, TAG_CODE, "ci", "Ic", id); return 1; } static int mdoc_va_pre(MDOC_ARGS) { - print_otag(h, TAG_VAR, "cT", "Va"); + print_otag(h, TAG_VAR, "c", "Va"); return 1; } @@ -1398,10 +1450,17 @@ mdoc_bf_pre(MDOC_ARGS) { const char *cattr; - if (n->type == ROFFT_HEAD) - return 0; - else if (n->type != ROFFT_BODY) + switch (n->type) { + case ROFFT_BLOCK: + html_close_paragraph(h); return 1; + case ROFFT_HEAD: + return 0; + case ROFFT_BODY: + break; + default: + abort(); + } if (FONT_Em == n->norm->Bf.font) cattr = "Bf Em"; @@ -1424,7 +1483,7 @@ mdoc_ms_pre(MDOC_ARGS) if ((id = cond_id(n)) != NULL) print_otag(h, TAG_A, "chR", "permalink", id); - print_otag(h, TAG_SPAN, "cTi", "Ms", id); + print_otag(h, TAG_SPAN, "ci", "Ms", id); return 1; } @@ -1447,13 +1506,21 @@ mdoc_pf_post(MDOC_ARGS) static int mdoc_rs_pre(MDOC_ARGS) { - if (n->type != ROFFT_BLOCK) - return 1; - - if (n->prev && SEC_SEE_ALSO == n->sec) - print_paragraph(h); - - print_otag(h, TAG_CITE, "cT", "Rs"); + switch (n->type) { + case ROFFT_BLOCK: + if (n->sec == SEC_SEE_ALSO) + html_close_paragraph(h); + break; + case ROFFT_HEAD: + return 0; + case ROFFT_BODY: + if (n->sec == SEC_SEE_ALSO) + print_otag(h, TAG_P, "c", "Pp"); + print_otag(h, TAG_CITE, "c", "Rs"); + break; + default: + abort(); + } return 1; } @@ -1482,7 +1549,7 @@ mdoc_li_pre(MDOC_ARGS) static int mdoc_sy_pre(MDOC_ARGS) { - print_otag(h, TAG_B, "cT", "Sy"); + print_otag(h, TAG_B, "c", "Sy"); return 1; } @@ -1492,7 +1559,7 @@ mdoc_lb_pre(MDOC_ARGS) if (SEC_LIBRARY == n->sec && NODE_LINE & n->flags && n->prev) print_otag(h, TAG_BR, ""); - print_otag(h, TAG_SPAN, "cT", "Lb"); + print_otag(h, TAG_SPAN, "c", "Lb"); return 1; } @@ -1630,9 +1697,15 @@ mdoc_quote_pre(MDOC_ARGS) case MDOC_Oo: case MDOC_Op: print_text(h, "\\(lB"); - h->flags |= HTML_NOSPACE; - /* Cannot use TAG_SPAN because it may contain blocks. */ - print_otag(h, TAG_IDIV, "c", "Op"); + /* + * Give up on semantic markup for now. + * We cannot use TAG_SPAN because .Oo may contain blocks. + * We cannot use TAG_IDIV because we might be in a + * phrasing context (like .Dl or .Pp); we cannot + * close out a .Pp at this point either because + * that would break the line. + */ + /* XXX print_otag(h, TAG_???, "c", "Op"); */ break; case MDOC_En: if (NULL == n->norm->Es || @@ -1760,3 +1833,9 @@ mdoc_eo_post(MDOC_ARGS) else if ( ! tail) h->flags &= ~HTML_NOSPACE; } + +static int +mdoc_abort_pre(MDOC_ARGS) +{ + abort(); +} diff --git a/usr/src/cmd/mandoc/mdoc_macro.c b/usr/src/cmd/mandoc/mdoc_macro.c index b463d03e22..3422945814 100644 --- a/usr/src/cmd/mandoc/mdoc_macro.c +++ b/usr/src/cmd/mandoc/mdoc_macro.c @@ -1,7 +1,7 @@ -/* $Id: mdoc_macro.c,v 1.224 2017/05/30 16:22:03 schwarze Exp $ */ +/* $Id: mdoc_macro.c,v 1.232 2019/01/07 07:26:29 schwarze Exp $ */ /* * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2010, 2012-2017 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2010, 2012-2019 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 @@ -49,7 +49,7 @@ static void dword(struct roff_man *, int, int, const char *, static int find_pending(struct roff_man *, enum roff_tok, int, int, struct roff_node *); static int lookup(struct roff_man *, int, int, int, const char *); -static int macro_or_word(MACRO_PROT_ARGS, int); +static int macro_or_word(MACRO_PROT_ARGS, char *, int); static void break_intermediate(struct roff_node *, struct roff_node *); static int parse_rest(struct roff_man *, enum roff_tok, @@ -60,7 +60,7 @@ static void rew_last(struct roff_man *, const struct roff_node *); static void rew_pending(struct roff_man *, const struct roff_node *); -const struct mdoc_macro __mdoc_macros[MDOC_MAX - MDOC_Dd] = { +static const struct mdoc_macro mdoc_macros[MDOC_MAX - MDOC_Dd] = { { in_line_eoln, MDOC_PROLOGUE }, /* Dd */ { in_line_eoln, MDOC_PROLOGUE }, /* Dt */ { in_line_eoln, MDOC_PROLOGUE }, /* Os */ @@ -201,9 +201,15 @@ const struct mdoc_macro __mdoc_macros[MDOC_MAX - MDOC_Dd] = { { in_line_eoln, 0 }, /* %U */ { phrase_ta, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ta */ }; -const struct mdoc_macro *const mdoc_macros = __mdoc_macros - MDOC_Dd; +const struct mdoc_macro * +mdoc_macro(enum roff_tok tok) +{ + assert(tok >= MDOC_Dd && tok < MDOC_MAX); + return mdoc_macros + (tok - MDOC_Dd); +} + /* * This is called at the end of parsing. It must traverse up the tree, * closing out open [implicit] scopes. Obviously, open explicit scopes @@ -221,14 +227,13 @@ mdoc_endparse(struct roff_man *mdoc) for ( ; n; n = n->parent) if (n->type == ROFFT_BLOCK && - mdoc_macros[n->tok].flags & MDOC_EXPLICIT) - mandoc_msg(MANDOCERR_BLK_NOEND, mdoc->parse, - n->line, n->pos, roff_name[n->tok]); + mdoc_macro(n->tok)->flags & MDOC_EXPLICIT) + mandoc_msg(MANDOCERR_BLK_NOEND, + n->line, n->pos, "%s", roff_name[n->tok]); /* Rewind to the first. */ - rew_last(mdoc, mdoc->first); - mdoc_state_reset(mdoc); + rew_last(mdoc, mdoc->meta.first); } /* @@ -244,13 +249,12 @@ lookup(struct roff_man *mdoc, int from, int line, int ppos, const char *p) mdoc->flags &= ~MDOC_PHRASEQF; return TOKEN_NONE; } - if (from == TOKEN_NONE || mdoc_macros[from].flags & MDOC_PARSED) { + if (from == TOKEN_NONE || mdoc_macro(from)->flags & MDOC_PARSED) { res = roffhash_find(mdoc->mdocmac, p, 0); if (res != TOKEN_NONE) { - if (mdoc_macros[res].flags & MDOC_CALLABLE) + if (mdoc_macro(res)->flags & MDOC_CALLABLE) return res; - mandoc_msg(MANDOCERR_MACRO_CALL, - mdoc->parse, line, ppos, p); + mandoc_msg(MANDOCERR_MACRO_CALL, line, ppos, "%s", p); } } return TOKEN_NONE; @@ -291,6 +295,8 @@ rew_pending(struct roff_man *mdoc, const struct roff_node *n) case ROFFT_HEAD: roff_body_alloc(mdoc, n->line, n->pos, n->tok); + if (n->tok == MDOC_Ss) + mdoc->flags &= ~ROFF_NONOFILL; break; case ROFFT_BLOCK: break; @@ -409,16 +415,15 @@ find_pending(struct roff_man *mdoc, enum roff_tok tok, int line, int ppos, if (n->flags & NODE_ENDED) continue; if (n->type == ROFFT_BLOCK && - mdoc_macros[n->tok].flags & MDOC_EXPLICIT) { + mdoc_macro(n->tok)->flags & MDOC_EXPLICIT) { irc = 1; break_intermediate(mdoc->last, target); if (target->type == ROFFT_HEAD) target->flags |= NODE_ENDED; else if ( ! (target->flags & NODE_ENDED)) { - mandoc_vmsg(MANDOCERR_BLK_NEST, - mdoc->parse, line, ppos, - "%s breaks %s", roff_name[tok], - roff_name[n->tok]); + mandoc_msg(MANDOCERR_BLK_NEST, + line, ppos, "%s breaks %s", + roff_name[tok], roff_name[n->tok]); mdoc_endbody_alloc(mdoc, line, ppos, tok, target); } @@ -470,14 +475,15 @@ append_delims(struct roff_man *mdoc, int line, int *pos, char *buf) { char *p; int la; + enum margserr ac; if (buf[*pos] == '\0') return; for (;;) { la = *pos; - if (mdoc_args(mdoc, line, pos, buf, TOKEN_NONE, &p) == - ARGS_EOLN) + ac = mdoc_args(mdoc, line, pos, buf, TOKEN_NONE, &p); + if (ac == ARGS_EOLN) break; dword(mdoc, line, la, p, DELIM_MAX, 1); @@ -495,6 +501,8 @@ append_delims(struct roff_man *mdoc, int line, int *pos, char *buf) if (mandoc_eos(p, strlen(p))) mdoc->last->flags |= NODE_EOS; + if (ac == ARGS_ALLOC) + free(p); } } @@ -504,27 +512,23 @@ append_delims(struct roff_man *mdoc, int line, int *pos, char *buf) * Otherwise, allocate it and return 0. */ static int -macro_or_word(MACRO_PROT_ARGS, int parsed) +macro_or_word(MACRO_PROT_ARGS, char *p, int parsed) { - char *p; int ntok; - p = buf + ppos; - ntok = TOKEN_NONE; - if (*p == '"') - p++; - else if (parsed && ! (mdoc->flags & MDOC_PHRASELIT)) - ntok = lookup(mdoc, tok, line, ppos, p); + ntok = buf[ppos] == '"' || parsed == 0 || + mdoc->flags & MDOC_PHRASELIT ? TOKEN_NONE : + lookup(mdoc, tok, line, ppos, p); if (ntok == TOKEN_NONE) { dword(mdoc, line, ppos, p, DELIM_MAX, tok == TOKEN_NONE || - mdoc_macros[tok].flags & MDOC_JOIN); + mdoc_macro(tok)->flags & MDOC_JOIN); return 0; } else { if (tok != TOKEN_NONE && - mdoc_macros[tok].fp == in_line_eoln) + mdoc_macro(tok)->fp == in_line_eoln) rew_elem(mdoc, tok); - mdoc_macro(mdoc, ntok, line, ppos, pos, buf); + (*mdoc_macro(ntok)->fp)(mdoc, ntok, line, ppos, pos, buf); if (tok == TOKEN_NONE) append_delims(mdoc, line, pos, buf); return 1; @@ -629,7 +633,7 @@ blk_exp_close(MACRO_PROT_ARGS) * the scope - of the current block ends. */ - mandoc_vmsg(MANDOCERR_BLK_NEST, mdoc->parse, + mandoc_msg(MANDOCERR_BLK_NEST, line, ppos, "%s breaks %s", roff_name[atok], roff_name[later->tok]); @@ -672,8 +676,8 @@ blk_exp_close(MACRO_PROT_ARGS) } if (body == NULL) { - mandoc_msg(MANDOCERR_BLK_NOTOPEN, mdoc->parse, - line, ppos, roff_name[tok]); + mandoc_msg(MANDOCERR_BLK_NOTOPEN, line, ppos, + "%s", roff_name[tok]); if (maxargs && endbody == NULL) { /* * Stray .Ec without previous .Eo: @@ -688,14 +692,25 @@ blk_exp_close(MACRO_PROT_ARGS) mdoc_tail_alloc(mdoc, line, ppos, atok); } - if ( ! (mdoc_macros[tok].flags & MDOC_PARSED)) { + if ((mdoc_macro(tok)->flags & MDOC_PARSED) == 0) { if (buf[*pos] != '\0') - mandoc_vmsg(MANDOCERR_ARG_SKIP, - mdoc->parse, line, ppos, - "%s %s", roff_name[tok], - buf + *pos); + mandoc_msg(MANDOCERR_ARG_SKIP, line, ppos, + "%s %s", roff_name[tok], buf + *pos); if (endbody == NULL && n != NULL) rew_pending(mdoc, n); + + /* + * Restore the fill mode that was set before the display. + * This needs to be done here rather than during validation + * such that subsequent nodes get the right flags. + */ + + if (tok == MDOC_Ed && body != NULL) { + if (body->flags & NODE_NOFILL) + mdoc->flags |= ROFF_NOFILL; + else + mdoc->flags &= ~ROFF_NOFILL; + } return; } @@ -717,14 +732,18 @@ blk_exp_close(MACRO_PROT_ARGS) if (ntok == TOKEN_NONE) { dword(mdoc, line, lastarg, p, DELIM_MAX, - MDOC_JOIN & mdoc_macros[tok].flags); + mdoc_macro(tok)->flags & MDOC_JOIN); + if (ac == ARGS_ALLOC) + free(p); continue; } + if (ac == ARGS_ALLOC) + free(p); if (n != NULL) rew_last(mdoc, n); mdoc->flags &= ~MDOC_NEWLINE; - mdoc_macro(mdoc, ntok, line, lastarg, pos, buf); + (*mdoc_macro(ntok)->fp)(mdoc, ntok, line, lastarg, pos, buf); break; } @@ -828,12 +847,14 @@ in_line(MACRO_PROT_ARGS) } else if ( ! nc && ! cnt) { mdoc_argv_free(arg); mandoc_msg(MANDOCERR_MACRO_EMPTY, - mdoc->parse, line, ppos, - roff_name[tok]); + line, ppos, "%s", roff_name[tok]); } - mdoc_macro(mdoc, ntok, line, la, pos, buf); + (*mdoc_macro(ntok)->fp)(mdoc, ntok, + line, la, pos, buf); if (nl) append_delims(mdoc, line, pos, buf); + if (ac == ARGS_ALLOC) + free(p); return; } @@ -875,7 +896,10 @@ in_line(MACRO_PROT_ARGS) } dword(mdoc, line, la, p, d, - mdoc_macros[tok].flags & MDOC_JOIN); + mdoc_macro(tok)->flags & MDOC_JOIN); + + if (ac == ARGS_ALLOC) + free(p); /* * If the first argument is a closing delimiter, @@ -914,8 +938,8 @@ in_line(MACRO_PROT_ARGS) rew_last(mdoc, mdoc->last); } else { mdoc_argv_free(arg); - mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, - line, ppos, roff_name[tok]); + mandoc_msg(MANDOCERR_MACRO_EMPTY, + line, ppos, "%s", roff_name[tok]); } } if (nl) @@ -927,24 +951,25 @@ in_line(MACRO_PROT_ARGS) static void blk_full(MACRO_PROT_ARGS) { - int la, nl, parsed; struct mdoc_arg *arg; struct roff_node *blk; /* Our own or a broken block. */ struct roff_node *head; /* Our own head. */ struct roff_node *body; /* Our own body. */ struct roff_node *n; - enum margserr ac, lac; char *p; + size_t iarg; + int done, la, nl, parsed; + enum margserr ac, lac; nl = MDOC_NEWLINE & mdoc->flags; if (buf[*pos] == '\0' && (tok == MDOC_Sh || tok == MDOC_Ss)) { - mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, - line, ppos, roff_name[tok]); + mandoc_msg(MANDOCERR_MACRO_EMPTY, + line, ppos, "%s", roff_name[tok]); return; } - if ( ! (mdoc_macros[tok].flags & MDOC_EXPLICIT)) { + if ((mdoc_macro(tok)->flags & MDOC_EXPLICIT) == 0) { /* Here, tok is one of Sh Ss Nm Nd It. */ @@ -960,21 +985,20 @@ blk_full(MACRO_PROT_ARGS) if (tok == MDOC_It && n->tok == MDOC_Bl) { if (blk != NULL) { - mandoc_vmsg(MANDOCERR_BLK_BROKEN, - mdoc->parse, line, ppos, - "It breaks %s", + mandoc_msg(MANDOCERR_BLK_BROKEN, + line, ppos, "It breaks %s", roff_name[blk->tok]); rew_pending(mdoc, blk); } break; } - if (mdoc_macros[n->tok].flags & MDOC_EXPLICIT) { + if (mdoc_macro(n->tok)->flags & MDOC_EXPLICIT) { switch (tok) { case MDOC_Sh: case MDOC_Ss: - mandoc_vmsg(MANDOCERR_BLK_BROKEN, - mdoc->parse, line, ppos, + mandoc_msg(MANDOCERR_BLK_BROKEN, + line, ppos, "%s breaks %s", roff_name[tok], roff_name[n->tok]); rew_pending(mdoc, n); @@ -1000,8 +1024,7 @@ blk_full(MACRO_PROT_ARGS) /* Item breaking an explicit block. */ if (blk != NULL) { - mandoc_vmsg(MANDOCERR_BLK_BROKEN, - mdoc->parse, line, ppos, + mandoc_msg(MANDOCERR_BLK_BROKEN, line, ppos, "It breaks %s", roff_name[blk->tok]); rew_pending(mdoc, blk); blk = NULL; @@ -1015,7 +1038,7 @@ blk_full(MACRO_PROT_ARGS) /* Skip items outside lists. */ if (tok == MDOC_It && (n == NULL || n->tok != MDOC_Bl)) { - mandoc_vmsg(MANDOCERR_IT_STRAY, mdoc->parse, + mandoc_msg(MANDOCERR_IT_STRAY, line, ppos, "It %s", buf + *pos); roff_elem_alloc(mdoc, line, ppos, ROFF_br); rew_elem(mdoc, ROFF_br); @@ -1032,6 +1055,16 @@ blk_full(MACRO_PROT_ARGS) * regular child nodes. */ + switch (tok) { + case MDOC_Sh: + mdoc->flags &= ~ROFF_NOFILL; + break; + case MDOC_Ss: + mdoc->flags |= ROFF_NONOFILL; + break; + default: + break; + } mdoc_argv(mdoc, line, tok, &arg, pos, buf); blk = mdoc_block_alloc(mdoc, line, ppos, tok, arg); head = body = NULL; @@ -1093,14 +1126,17 @@ blk_full(MACRO_PROT_ARGS) } if (tok == MDOC_Bd || tok == MDOC_Bk) { - mandoc_vmsg(MANDOCERR_ARG_EXCESS, - mdoc->parse, line, la, "%s ... %s", - roff_name[tok], buf + la); + mandoc_msg(MANDOCERR_ARG_EXCESS, line, la, + "%s ... %s", roff_name[tok], buf + la); + if (ac == ARGS_ALLOC) + free(p); break; } if (tok == MDOC_Rs) { - mandoc_vmsg(MANDOCERR_ARG_SKIP, mdoc->parse, + mandoc_msg(MANDOCERR_ARG_SKIP, line, la, "Rs %s", buf + la); + if (ac == ARGS_ALLOC) + free(p); break; } if (ac == ARGS_PUNCT) @@ -1115,6 +1151,8 @@ blk_full(MACRO_PROT_ARGS) ac != ARGS_PHRASE && mdoc_isdelim(p) == DELIM_OPEN) { dword(mdoc, line, la, p, DELIM_OPEN, 0); + if (ac == ARGS_ALLOC) + free(p); continue; } @@ -1146,7 +1184,10 @@ blk_full(MACRO_PROT_ARGS) continue; } - if (macro_or_word(mdoc, tok, line, la, pos, buf, parsed)) + done = macro_or_word(mdoc, tok, line, la, pos, buf, p, parsed); + if (ac == ARGS_ALLOC) + free(p); + if (done) break; } @@ -1165,6 +1206,33 @@ blk_full(MACRO_PROT_ARGS) rew_last(mdoc, head); body = roff_body_alloc(mdoc, line, ppos, tok); + if (tok == MDOC_Ss) + mdoc->flags &= ~ROFF_NONOFILL; + + /* + * Set up fill mode for display blocks. + * This needs to be done here up front rather than during + * validation such that child nodes get the right flags. + */ + + if (tok == MDOC_Bd && arg != NULL) { + for (iarg = 0; iarg < arg->argc; iarg++) { + switch (arg->argv[iarg].arg) { + case MDOC_Unfilled: + case MDOC_Literal: + mdoc->flags |= ROFF_NOFILL; + break; + case MDOC_Filled: + case MDOC_Ragged: + case MDOC_Centred: + mdoc->flags &= ~ROFF_NOFILL; + break; + default: + continue; + } + break; + } + } out: if (mdoc->flags & MDOC_FREECOL) { rew_last(mdoc, body); @@ -1176,7 +1244,7 @@ out: static void blk_part_imp(MACRO_PROT_ARGS) { - int la, nl; + int done, la, nl; enum margserr ac; char *p; struct roff_node *blk; /* saved block context */ @@ -1211,13 +1279,18 @@ blk_part_imp(MACRO_PROT_ARGS) if (body == NULL && mdoc_isdelim(p) == DELIM_OPEN) { dword(mdoc, line, la, p, DELIM_OPEN, 0); + if (ac == ARGS_ALLOC) + free(p); continue; } if (body == NULL) body = roff_body_alloc(mdoc, line, ppos, tok); - if (macro_or_word(mdoc, tok, line, la, pos, buf, 1)) + done = macro_or_word(mdoc, tok, line, la, pos, buf, p, 1); + if (ac == ARGS_ALLOC) + free(p); + if (done) break; } if (body == NULL) @@ -1236,13 +1309,13 @@ blk_part_imp(MACRO_PROT_ARGS) for (n = body->child; n && n->next; n = n->next) /* Do nothing. */ ; if (n && n->tok == MDOC_Ns) - mdoc_node_relink(mdoc, n); + roff_node_relink(mdoc, n); } static void blk_part_exp(MACRO_PROT_ARGS) { - int la, nl; + int done, la, nl; enum margserr ac; struct roff_node *head; /* keep track of head */ char *p; @@ -1267,6 +1340,8 @@ blk_part_exp(MACRO_PROT_ARGS) if (head == NULL && mdoc_isdelim(p) == DELIM_OPEN) { dword(mdoc, line, la, p, DELIM_OPEN, 0); + if (ac == ARGS_ALLOC) + free(p); continue; } @@ -1276,11 +1351,17 @@ blk_part_exp(MACRO_PROT_ARGS) dword(mdoc, line, la, p, DELIM_MAX, 0); rew_last(mdoc, head); roff_body_alloc(mdoc, line, ppos, tok); - if (tok == MDOC_Eo) + if (tok == MDOC_Eo) { + if (ac == ARGS_ALLOC) + free(p); continue; + } } - if (macro_or_word(mdoc, tok, line, la, pos, buf, 1)) + done = macro_or_word(mdoc, tok, line, la, pos, buf, p, 1); + if (ac == ARGS_ALLOC) + free(p); + if (done) break; } @@ -1338,10 +1419,12 @@ in_line_argn(MACRO_PROT_ARGS) la = *pos; ac = mdoc_args(mdoc, line, pos, buf, tok, &p); - if (ac == ARGS_WORD && state == -1 && - ! (mdoc_macros[tok].flags & MDOC_IGNDELIM) && + if ((ac == ARGS_WORD || ac == ARGS_ALLOC) && state == -1 && + (mdoc_macro(tok)->flags & MDOC_IGNDELIM) == 0 && mdoc_isdelim(p) == DELIM_OPEN) { dword(mdoc, line, la, p, DELIM_OPEN, 0); + if (ac == ARGS_ALLOC) + free(p); continue; } @@ -1353,8 +1436,8 @@ in_line_argn(MACRO_PROT_ARGS) if (ac == ARGS_PUNCT || ac == ARGS_EOLN) { if (abs(state) < 2 && tok == MDOC_Pf) - mandoc_vmsg(MANDOCERR_PF_SKIP, - mdoc->parse, line, ppos, "Pf %s", + mandoc_msg(MANDOCERR_PF_SKIP, + line, ppos, "Pf %s", p == NULL ? "at eol" : p); break; } @@ -1372,11 +1455,14 @@ in_line_argn(MACRO_PROT_ARGS) rew_elem(mdoc, tok); state = -2; } - mdoc_macro(mdoc, ntok, line, la, pos, buf); + (*mdoc_macro(ntok)->fp)(mdoc, ntok, + line, la, pos, buf); + if (ac == ARGS_ALLOC) + free(p); break; } - if (mdoc_macros[tok].flags & MDOC_IGNDELIM || + if (mdoc_macro(tok)->flags & MDOC_IGNDELIM || mdoc_isdelim(p) == DELIM_NONE) { if (state == -1) { mdoc_elem_alloc(mdoc, line, ppos, tok, arg); @@ -1389,12 +1475,15 @@ in_line_argn(MACRO_PROT_ARGS) } dword(mdoc, line, la, p, DELIM_MAX, - mdoc_macros[tok].flags & MDOC_JOIN); + mdoc_macro(tok)->flags & MDOC_JOIN); + if (ac == ARGS_ALLOC) + free(p); + p = mdoc->last->string; } if (state == -1) { - mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, - line, ppos, roff_name[tok]); + mandoc_msg(MANDOCERR_MACRO_EMPTY, + line, ppos, "%s", roff_name[tok]); return; } @@ -1423,8 +1512,8 @@ in_line_eoln(MACRO_PROT_ARGS) if (buf[*pos] == '\0' && (tok == MDOC_Fd || *roff_name[tok] == '%')) { - mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, - line, ppos, roff_name[tok]); + mandoc_msg(MANDOCERR_MACRO_EMPTY, + line, ppos, "%s", roff_name[tok]); return; } @@ -1444,13 +1533,19 @@ static int parse_rest(struct roff_man *mdoc, enum roff_tok tok, int line, int *pos, char *buf) { - int la; + char *p; + int done, la; + enum margserr ac; for (;;) { la = *pos; - if (mdoc_args(mdoc, line, pos, buf, tok, NULL) == ARGS_EOLN) + ac = mdoc_args(mdoc, line, pos, buf, tok, &p); + if (ac == ARGS_EOLN) return 0; - if (macro_or_word(mdoc, tok, line, la, pos, buf, 1)) + done = macro_or_word(mdoc, tok, line, la, pos, buf, p, 1); + if (ac == ARGS_ALLOC) + free(p); + if (done) return 1; } } @@ -1492,8 +1587,7 @@ phrase_ta(MACRO_PROT_ARGS) } if (n == NULL || n->norm->Bl.type != LIST_column) { - mandoc_msg(MANDOCERR_TA_STRAY, mdoc->parse, - line, ppos, "Ta"); + mandoc_msg(MANDOCERR_TA_STRAY, line, ppos, "Ta"); return; } diff --git a/usr/src/cmd/mandoc/mdoc_man.c b/usr/src/cmd/mandoc/mdoc_man.c index bcf9207f79..2e8f02ae56 100644 --- a/usr/src/cmd/mandoc/mdoc_man.c +++ b/usr/src/cmd/mandoc/mdoc_man.c @@ -1,6 +1,6 @@ -/* $Id: mdoc_man.c,v 1.126 2018/04/11 17:11:13 schwarze Exp $ */ +/* $Id: mdoc_man.c,v 1.132 2019/01/04 03:17:36 schwarze Exp $ */ /* - * Copyright (c) 2011-2018 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2011-2019 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 @@ -36,7 +36,7 @@ typedef int (*int_fp)(DECL_ARGS); typedef void (*void_fp)(DECL_ARGS); -struct manact { +struct mdoc_man_act { int_fp cond; /* DON'T run actions */ int_fp pre; /* pre-node action */ void_fp post; /* post-node action */ @@ -75,6 +75,7 @@ static void post_pf(DECL_ARGS); static void post_sect(DECL_ARGS); static void post_vt(DECL_ARGS); static int pre__t(DECL_ARGS); +static int pre_abort(DECL_ARGS); static int pre_an(DECL_ARGS); static int pre_ap(DECL_ARGS); static int pre_aq(DECL_ARGS); @@ -103,6 +104,7 @@ static int pre_lk(DECL_ARGS); static int pre_li(DECL_ARGS); static int pre_nm(DECL_ARGS); static int pre_no(DECL_ARGS); +static void pre_noarg(DECL_ARGS); static int pre_ns(DECL_ARGS); static void pre_onearg(DECL_ARGS); static int pre_pp(DECL_ARGS); @@ -124,12 +126,14 @@ static void print_width(const struct mdoc_bl *, static void print_count(int *); static void print_node(DECL_ARGS); -static const void_fp roff_manacts[ROFF_MAX] = { +static const void_fp roff_man_acts[ROFF_MAX] = { pre_br, /* br */ pre_onearg, /* ce */ + pre_noarg, /* fi */ pre_ft, /* ft */ pre_onearg, /* ll */ pre_onearg, /* mc */ + pre_noarg, /* nf */ pre_onearg, /* po */ pre_onearg, /* rj */ pre_sp, /* sp */ @@ -137,7 +141,7 @@ static const void_fp roff_manacts[ROFF_MAX] = { pre_onearg, /* ti */ }; -static const struct manact __manacts[MDOC_MAX - MDOC_Dd] = { +static const struct mdoc_man_act mdoc_man_acts[MDOC_MAX - MDOC_Dd] = { { NULL, NULL, NULL, NULL, NULL }, /* Dd */ { NULL, NULL, NULL, NULL, NULL }, /* Dt */ { NULL, NULL, NULL, NULL, NULL }, /* Os */ @@ -172,7 +176,7 @@ static const struct manact __manacts[MDOC_MAX - MDOC_Dd] = { { cond_head, pre_enc, NULL, "\\- ", NULL }, /* Nd */ { NULL, pre_nm, post_nm, NULL, NULL }, /* Nm */ { cond_body, pre_enc, post_enc, "[", "]" }, /* Op */ - { NULL, pre_Ft, post_font, NULL, NULL }, /* Ot */ + { NULL, pre_abort, NULL, NULL, NULL }, /* Ot */ { NULL, pre_em, post_font, NULL, NULL }, /* Pa */ { NULL, pre_ex, NULL, NULL, NULL }, /* Rv */ { NULL, NULL, NULL, NULL, NULL }, /* St */ @@ -245,7 +249,7 @@ static const struct manact __manacts[MDOC_MAX - MDOC_Dd] = { { NULL, pre_em, post_font, NULL, NULL }, /* Fr */ { NULL, NULL, NULL, NULL, NULL }, /* Ud */ { NULL, NULL, post_lb, NULL, NULL }, /* Lb */ - { NULL, pre_pp, NULL, NULL, NULL }, /* Lp */ + { NULL, pre_abort, NULL, NULL, NULL }, /* Lp */ { NULL, pre_lk, NULL, NULL, NULL }, /* Lk */ { NULL, pre_em, post_font, NULL, NULL }, /* Mt */ { cond_body, pre_enc, post_enc, "{", "}" }, /* Brq */ @@ -259,7 +263,7 @@ static const struct manact __manacts[MDOC_MAX - MDOC_Dd] = { { NULL, NULL, post_percent, NULL, NULL }, /* %U */ { NULL, NULL, NULL, NULL, NULL }, /* Ta */ }; -static const struct manact *const manacts = __manacts - MDOC_Dd; +static const struct mdoc_man_act *mdoc_man_act(enum roff_tok); static int outflags; #define MMAN_spc (1 << 0) /* blank character before next word */ @@ -290,6 +294,13 @@ static struct { } fontqueue; +static const struct mdoc_man_act * +mdoc_man_act(enum roff_tok tok) +{ + assert(tok >= MDOC_Dd && tok <= MDOC_MAX); + return mdoc_man_acts + (tok - MDOC_Dd); +} + static int man_strlen(const char *cp) { @@ -317,6 +328,7 @@ man_strlen(const char *cp) case ESCAPE_UNICODE: case ESCAPE_NUMBERED: case ESCAPE_SPECIAL: + case ESCAPE_UNDEF: case ESCAPE_OVERSTRIKE: if (skip) skip = 0; @@ -593,20 +605,7 @@ print_count(int *count) } void -man_man(void *arg, const struct roff_man *man) -{ - - /* - * Dump the keep buffer. - * We're guaranteed by now that this exists (is non-NULL). - * Flush stdout afterward, just in case. - */ - fputs(mparse_getkeep(man_mparse(man)), stdout); - fflush(stdout); -} - -void -man_mdoc(void *arg, const struct roff_man *mdoc) +man_mdoc(void *arg, const struct roff_meta *mdoc) { struct roff_node *n; @@ -619,9 +618,8 @@ man_mdoc(void *arg, const struct roff_man *mdoc) } printf(".TH \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"\n", - mdoc->meta.title, - (mdoc->meta.msec == NULL ? "" : mdoc->meta.msec), - mdoc->meta.date, mdoc->meta.os, mdoc->meta.vol); + mdoc->title, (mdoc->msec == NULL ? "" : mdoc->msec), + mdoc->date, mdoc->os, mdoc->vol); /* Disable hyphenation and if nroff, disable justification. */ printf(".nh\n.if n .ad l"); @@ -633,16 +631,16 @@ man_mdoc(void *arg, const struct roff_man *mdoc) *fontqueue.tail = 'R'; } for (; n != NULL; n = n->next) - print_node(&mdoc->meta, n); + print_node(mdoc, n); putchar('\n'); } static void print_node(DECL_ARGS) { - const struct manact *act; - struct roff_node *sub; - int cond, do_sub; + const struct mdoc_man_act *act; + struct roff_node *sub; + int cond, do_sub; if (n->flags & NODE_NOPRT) return; @@ -680,15 +678,14 @@ print_node(DECL_ARGS) else if (outflags & MMAN_Sm) outflags |= MMAN_spc; } else if (n->tok < ROFF_MAX) { - (*roff_manacts[n->tok])(meta, n); + (*roff_man_acts[n->tok])(meta, n); return; } else { - assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX); /* * Conditionally run the pre-node action handler for a * node. */ - act = manacts + n->tok; + act = mdoc_man_act(n->tok); cond = act->cond == NULL || (*act->cond)(meta, n); if (cond && act->pre != NULL && (n->end == ENDBODY_NOT || n->child != NULL)) @@ -732,11 +729,17 @@ cond_body(DECL_ARGS) } static int +pre_abort(DECL_ARGS) +{ + abort(); +} + +static int pre_enc(DECL_ARGS) { const char *prefix; - prefix = manacts[n->tok].prefix; + prefix = mdoc_man_act(n->tok)->prefix; if (NULL == prefix) return 1; print_word(prefix); @@ -749,7 +752,7 @@ post_enc(DECL_ARGS) { const char *suffix; - suffix = manacts[n->tok].suffix; + suffix = mdoc_man_act(n->tok)->suffix; if (NULL == suffix) return; outflags &= ~(MMAN_spc | MMAN_nl); @@ -774,7 +777,7 @@ static void post_percent(DECL_ARGS) { - if (pre_em == manacts[n->tok].pre) + if (mdoc_man_act(n->tok)->pre == pre_em) font_pop(); if (n->next) { print_word(","); @@ -820,7 +823,7 @@ pre_sect(DECL_ARGS) if (n->type == ROFFT_HEAD) { outflags |= MMAN_sp; - print_block(manacts[n->tok].prefix, 0); + print_block(mdoc_man_act(n->tok)->prefix, 0); print_word(""); putchar('\"'); outflags &= ~MMAN_spc; @@ -936,7 +939,6 @@ post_aq(DECL_ARGS) static int pre_bd(DECL_ARGS) { - outflags &= ~(MMAN_PP | MMAN_sp | MMAN_br); if (DISP_unfilled == n->norm->Bd.type || @@ -951,12 +953,27 @@ pre_bd(DECL_ARGS) static void post_bd(DECL_ARGS) { + enum roff_tok bef, now; /* Close out this display. */ print_line(".RE", MMAN_nl); - if (DISP_unfilled == n->norm->Bd.type || - DISP_literal == n->norm->Bd.type) - print_line(".fi", MMAN_nl); + bef = n->flags & NODE_NOFILL ? ROFF_nf : ROFF_fi; + if (n->last == NULL) + now = n->norm->Bd.type == DISP_unfilled || + n->norm->Bd.type == DISP_literal ? ROFF_nf : ROFF_fi; + else if (n->last->tok == ROFF_nf) + now = ROFF_nf; + else if (n->last->tok == ROFF_fi) + now = ROFF_fi; + else + now = n->last->flags & NODE_NOFILL ? ROFF_nf : ROFF_fi; + if (bef != now) { + outflags |= MMAN_nl; + print_word("."); + outflags &= ~MMAN_spc; + print_word(roff_name[bef]); + outflags |= MMAN_nl; + } /* Maybe we are inside an enclosing list? */ if (NULL != n->parent->next) @@ -1607,7 +1624,6 @@ pre_onearg(DECL_ARGS) static int pre_li(DECL_ARGS) { - font_push('R'); return 1; } @@ -1640,7 +1656,6 @@ pre_nm(DECL_ARGS) static void post_nm(DECL_ARGS) { - switch (n->type) { case ROFFT_BLOCK: outflags &= ~MMAN_Bk; @@ -1658,15 +1673,23 @@ post_nm(DECL_ARGS) static int pre_no(DECL_ARGS) { - outflags |= MMAN_spc_force; return 1; } +static void +pre_noarg(DECL_ARGS) +{ + outflags |= MMAN_nl; + print_word("."); + outflags &= ~MMAN_spc; + print_word(roff_name[n->tok]); + outflags |= MMAN_nl; +} + static int pre_ns(DECL_ARGS) { - outflags &= ~MMAN_spc; return 0; } diff --git a/usr/src/cmd/mandoc/mdoc_markdown.c b/usr/src/cmd/mandoc/mdoc_markdown.c index e73440a4e5..b73811b76b 100644 --- a/usr/src/cmd/mandoc/mdoc_markdown.c +++ b/usr/src/cmd/mandoc/mdoc_markdown.c @@ -1,6 +1,6 @@ -/* $Id: mdoc_markdown.c,v 1.24 2018/04/11 17:11:13 schwarze Exp $ */ +/* $Id: mdoc_markdown.c,v 1.30 2018/12/30 00:49:55 schwarze Exp $ */ /* - * 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 @@ -19,6 +19,7 @@ #include <assert.h> #include <ctype.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> #include "mandoc_aux.h" @@ -48,6 +49,7 @@ static void md_uri(const char *); static int md_cond_head(struct roff_node *); static int md_cond_body(struct roff_node *); +static int md_pre_abort(struct roff_node *); static int md_pre_raw(struct roff_node *); static int md_pre_word(struct roff_node *); static int md_pre_skip(struct roff_node *); @@ -103,7 +105,7 @@ static void md_post_Pf(struct roff_node *); static void md_post_Vt(struct roff_node *); static void md_post__T(struct roff_node *); -static const struct md_act __md_acts[MDOC_MAX - MDOC_Dd] = { +static const struct md_act md_acts[MDOC_MAX - MDOC_Dd] = { { NULL, NULL, NULL, NULL, NULL }, /* Dd */ { NULL, NULL, NULL, NULL, NULL }, /* Dt */ { NULL, NULL, NULL, NULL, NULL }, /* Os */ @@ -138,7 +140,7 @@ static const struct md_act __md_acts[MDOC_MAX - MDOC_Dd] = { { md_cond_head, md_pre_Nd, NULL, NULL, NULL }, /* Nd */ { NULL, md_pre_Nm, md_post_Nm, "**", "**" }, /* Nm */ { md_cond_body, md_pre_word, md_post_word, "[", "]" }, /* Op */ - { NULL, md_pre_Fd, md_post_raw, "*", "*" }, /* Ot */ + { NULL, md_pre_abort, NULL, NULL, NULL }, /* Ot */ { NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Pa */ { NULL, NULL, NULL, NULL, NULL }, /* Rv */ { NULL, NULL, NULL, NULL, NULL }, /* St */ @@ -211,7 +213,7 @@ static const struct md_act __md_acts[MDOC_MAX - MDOC_Dd] = { { NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Fr */ { NULL, NULL, NULL, NULL, NULL }, /* Ud */ { NULL, NULL, md_post_Lb, NULL, NULL }, /* Lb */ - { NULL, md_pre_Pp, NULL, NULL, NULL }, /* Lp */ + { NULL, md_pre_abort, NULL, NULL, NULL }, /* Lp */ { NULL, md_pre_Lk, NULL, NULL, NULL }, /* Lk */ { NULL, md_pre_Mt, NULL, NULL, NULL }, /* Mt */ { md_cond_body, md_pre_word, md_post_word, "{", "}" }, /* Brq */ @@ -225,7 +227,7 @@ static const struct md_act __md_acts[MDOC_MAX - MDOC_Dd] = { { NULL, md_pre_Lk, md_post_pc, NULL, NULL }, /* %U */ { NULL, NULL, NULL, NULL, NULL }, /* Ta */ }; -static const struct md_act *const md_acts = __md_acts - MDOC_Dd; +static const struct md_act *md_act(enum roff_tok); static int outflags; #define MD_spc (1 << 0) /* Blank character before next word. */ @@ -250,22 +252,30 @@ static int escflags; /* Escape in generated markdown code: */ static int code_blocks, quote_blocks, list_blocks; static int outcount; + +static const struct md_act * +md_act(enum roff_tok tok) +{ + assert(tok >= MDOC_Dd && tok <= MDOC_MAX); + return md_acts + (tok - MDOC_Dd); +} + void -markdown_mdoc(void *arg, const struct roff_man *mdoc) +markdown_mdoc(void *arg, const struct roff_meta *mdoc) { outflags = MD_Sm; - md_word(mdoc->meta.title); - if (mdoc->meta.msec != NULL) { + md_word(mdoc->title); + if (mdoc->msec != NULL) { outflags &= ~MD_spc; md_word("("); - md_word(mdoc->meta.msec); + md_word(mdoc->msec); md_word(")"); } md_word("-"); - md_word(mdoc->meta.vol); - if (mdoc->meta.arch != NULL) { + md_word(mdoc->vol); + if (mdoc->arch != NULL) { md_word("("); - md_word(mdoc->meta.arch); + md_word(mdoc->arch); md_word(")"); } outflags |= MD_sp; @@ -273,9 +283,9 @@ markdown_mdoc(void *arg, const struct roff_man *mdoc) md_nodelist(mdoc->first->child); outflags |= MD_sp; - md_word(mdoc->meta.os); + md_word(mdoc->os); md_word("-"); - md_word(mdoc->meta.date); + md_word(mdoc->date); putchar('\n'); } @@ -330,8 +340,7 @@ md_node(struct roff_node *n) break; } } else { - assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX); - act = md_acts + n->tok; + act = md_act(n->tok); cond = act->cond == NULL || (*act->cond)(n); if (cond && act->pre != NULL && (n->end == ENDBODY_NOT || n->child != NULL)) @@ -580,6 +589,12 @@ md_word(const char *s) case ESCAPE_SPECIAL: uc = mchars_spec2cp(seq, sz); break; + case ESCAPE_UNDEF: + uc = *seq; + break; + case ESCAPE_DEVICE: + md_rawword("markdown"); + continue; case ESCAPE_FONTBOLD: nextfont = "**"; break; @@ -590,6 +605,7 @@ md_word(const char *s) nextfont = "***"; break; case ESCAPE_FONT: + case ESCAPE_FONTCW: case ESCAPE_FONTROMAN: nextfont = ""; break; @@ -712,11 +728,17 @@ md_cond_body(struct roff_node *n) } static int +md_pre_abort(struct roff_node *n) +{ + abort(); +} + +static int md_pre_raw(struct roff_node *n) { const char *prefix; - if ((prefix = md_acts[n->tok].prefix) != NULL) { + if ((prefix = md_act(n->tok)->prefix) != NULL) { md_rawword(prefix); outflags &= ~MD_spc; if (*prefix == '`') @@ -730,7 +752,7 @@ md_post_raw(struct roff_node *n) { const char *suffix; - if ((suffix = md_acts[n->tok].suffix) != NULL) { + if ((suffix = md_act(n->tok)->suffix) != NULL) { outflags &= ~(MD_spc | MD_nl); md_rawword(suffix); if (*suffix == '`') @@ -743,7 +765,7 @@ md_pre_word(struct roff_node *n) { const char *prefix; - if ((prefix = md_acts[n->tok].prefix) != NULL) { + if ((prefix = md_act(n->tok)->prefix) != NULL) { md_word(prefix); outflags &= ~MD_spc; } @@ -755,7 +777,7 @@ md_post_word(struct roff_node *n) { const char *suffix; - if ((suffix = md_acts[n->tok].suffix) != NULL) { + if ((suffix = md_act(n->tok)->suffix) != NULL) { outflags &= ~(MD_spc | MD_nl); md_word(suffix); } @@ -1268,7 +1290,7 @@ md_post_It(struct roff_node *n) while ((n = n->prev) != NULL && n->type != ROFFT_HEAD) i++; - /* + /* * If a width was specified for this column, * subtract what printed, and * add the same spacing as in mdoc_term.c. diff --git a/usr/src/cmd/mandoc/mdoc_state.c b/usr/src/cmd/mandoc/mdoc_state.c index 2d8563f5bf..f9a585e736 100644 --- a/usr/src/cmd/mandoc/mdoc_state.c +++ b/usr/src/cmd/mandoc/mdoc_state.c @@ -1,4 +1,4 @@ -/* $Id: mdoc_state.c,v 1.9 2017/11/29 20:05:33 schwarze Exp $ */ +/* $Id: mdoc_state.c,v 1.15 2019/01/01 07:42:04 schwarze Exp $ */ /* * Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org> * @@ -17,6 +17,7 @@ #include <sys/types.h> #include <assert.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> @@ -24,19 +25,18 @@ #include "roff.h" #include "mdoc.h" #include "libmandoc.h" +#include "roff_int.h" #include "libmdoc.h" #define STATE_ARGS struct roff_man *mdoc, struct roff_node *n typedef void (*state_handler)(STATE_ARGS); -static void state_bd(STATE_ARGS); static void state_bl(STATE_ARGS); -static void state_dl(STATE_ARGS); static void state_sh(STATE_ARGS); static void state_sm(STATE_ARGS); -static const state_handler __state_handlers[MDOC_MAX - MDOC_Dd] = { +static const state_handler state_handlers[MDOC_MAX - MDOC_Dd] = { NULL, /* Dd */ NULL, /* Dt */ NULL, /* Os */ @@ -44,8 +44,8 @@ static const state_handler __state_handlers[MDOC_MAX - MDOC_Dd] = { NULL, /* Ss */ NULL, /* Pp */ NULL, /* D1 */ - state_dl, /* Dl */ - state_bd, /* Bd */ + NULL, /* Dl */ + NULL, /* Bd */ NULL, /* Ed */ state_bl, /* Bl */ NULL, /* El */ @@ -158,7 +158,6 @@ static const state_handler __state_handlers[MDOC_MAX - MDOC_Dd] = { NULL, /* %U */ NULL, /* Ta */ }; -static const state_handler *const state_handlers = __state_handlers - MDOC_Dd; void @@ -170,41 +169,14 @@ mdoc_state(struct roff_man *mdoc, struct roff_node *n) return; assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX); - if ( ! (mdoc_macros[n->tok].flags & MDOC_PROLOGUE)) + if ((mdoc_macro(n->tok)->flags & MDOC_PROLOGUE) == 0) mdoc->flags |= MDOC_PBODY; - handler = state_handlers[n->tok]; + handler = state_handlers[n->tok - MDOC_Dd]; if (*handler) (*handler)(mdoc, n); } -void -mdoc_state_reset(struct roff_man *mdoc) -{ - - roff_setreg(mdoc->roff, "nS", 0, '='); - mdoc->flags = 0; -} - -static void -state_bd(STATE_ARGS) -{ - enum mdocargt arg; - - if (n->type != ROFFT_HEAD && - (n->type != ROFFT_BODY || n->end != ENDBODY_NOT)) - return; - - if (n->parent->args == NULL) - return; - - arg = n->parent->args->argv[0].arg; - if (arg != MDOC_Literal && arg != MDOC_Unfilled) - return; - - state_dl(mdoc, n); -} - static void state_bl(STATE_ARGS) { @@ -230,22 +202,6 @@ state_bl(STATE_ARGS) } static void -state_dl(STATE_ARGS) -{ - - switch (n->type) { - case ROFFT_HEAD: - mdoc->flags |= MDOC_LITERAL; - break; - case ROFFT_BODY: - mdoc->flags &= ~MDOC_LITERAL; - break; - default: - break; - } -} - -static void state_sh(STATE_ARGS) { struct roff_node *nch; diff --git a/usr/src/cmd/mandoc/mdoc_term.c b/usr/src/cmd/mandoc/mdoc_term.c index cf3e7ef3dd..c2f265c4e7 100644 --- a/usr/src/cmd/mandoc/mdoc_term.c +++ b/usr/src/cmd/mandoc/mdoc_term.c @@ -1,7 +1,7 @@ -/* $Id: mdoc_term.c,v 1.367 2018/04/11 17:11:13 schwarze Exp $ */ +/* $Id: mdoc_term.c,v 1.373 2019/06/03 19:50:33 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2010, 2012-2018 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2010, 2012-2019 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de> * * Permission to use, copy, modify, and distribute this software for any @@ -29,7 +29,6 @@ #include <string.h> #include "mandoc_aux.h" -#include "mandoc.h" #include "roff.h" #include "mdoc.h" #include "out.h" @@ -47,7 +46,7 @@ struct termpair { const struct roff_meta *meta, \ struct roff_node *n -struct termact { +struct mdoc_term_act { int (*pre)(DECL_ARGS); void (*post)(DECL_ARGS); }; @@ -84,6 +83,7 @@ static void termp_xx_post(DECL_ARGS); static int termp__a_pre(DECL_ARGS); static int termp__t_pre(DECL_ARGS); +static int termp_abort_pre(DECL_ARGS); static int termp_an_pre(DECL_ARGS); static int termp_ap_pre(DECL_ARGS); static int termp_bd_pre(DECL_ARGS); @@ -124,7 +124,7 @@ static int termp_vt_pre(DECL_ARGS); static int termp_xr_pre(DECL_ARGS); static int termp_xx_pre(DECL_ARGS); -static const struct termact __termacts[MDOC_MAX - MDOC_Dd] = { +static const struct mdoc_term_act mdoc_term_acts[MDOC_MAX - MDOC_Dd] = { { NULL, NULL }, /* Dd */ { NULL, NULL }, /* Dt */ { NULL, NULL }, /* Os */ @@ -159,7 +159,7 @@ static const struct termact __termacts[MDOC_MAX - MDOC_Dd] = { { termp_nd_pre, NULL }, /* Nd */ { termp_nm_pre, termp_nm_post }, /* Nm */ { termp_quote_pre, termp_quote_post }, /* Op */ - { termp_ft_pre, NULL }, /* Ot */ + { termp_abort_pre, NULL }, /* Ot */ { termp_under_pre, NULL }, /* Pa */ { termp_ex_pre, NULL }, /* Rv */ { NULL, NULL }, /* St */ @@ -232,7 +232,7 @@ static const struct termact __termacts[MDOC_MAX - MDOC_Dd] = { { termp_under_pre, NULL }, /* Fr */ { NULL, NULL }, /* Ud */ { NULL, termp_lb_post }, /* Lb */ - { termp_pp_pre, NULL }, /* Lp */ + { termp_abort_pre, NULL }, /* Lp */ { termp_lk_pre, NULL }, /* Lk */ { termp_under_pre, NULL }, /* Mt */ { termp_quote_pre, termp_quote_post }, /* Brq */ @@ -246,13 +246,12 @@ static const struct termact __termacts[MDOC_MAX - MDOC_Dd] = { { NULL, termp____post }, /* %U */ { NULL, NULL }, /* Ta */ }; -static const struct termact *const termacts = __termacts - MDOC_Dd; static int fn_prio; void -terminal_mdoc(void *arg, const struct roff_man *mdoc) +terminal_mdoc(void *arg, const struct roff_meta *mdoc) { struct roff_node *n; struct termp *p; @@ -270,8 +269,7 @@ terminal_mdoc(void *arg, const struct roff_man *mdoc) if (n->tok == MDOC_Sh && n->sec == SEC_SYNOPSIS) { if (n->child->next->child != NULL) print_mdoc_nodelist(p, NULL, - &mdoc->meta, - n->child->next->child); + mdoc, n->child->next->child); term_newln(p); break; } @@ -281,8 +279,7 @@ terminal_mdoc(void *arg, const struct roff_man *mdoc) save_defindent = p->defindent; if (p->defindent == 0) p->defindent = 5; - term_begin(p, print_mdoc_head, print_mdoc_foot, - &mdoc->meta); + term_begin(p, print_mdoc_head, print_mdoc_foot, mdoc); while (n != NULL && (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT)) @@ -290,7 +287,7 @@ terminal_mdoc(void *arg, const struct roff_man *mdoc) if (n != NULL) { if (n->tok != MDOC_Sh) term_vspace(p); - print_mdoc_nodelist(p, NULL, &mdoc->meta, n); + print_mdoc_nodelist(p, NULL, mdoc, n); } term_end(p); p->defindent = save_defindent; @@ -310,9 +307,23 @@ print_mdoc_nodelist(DECL_ARGS) static void print_mdoc_node(DECL_ARGS) { - int chld; + const struct mdoc_term_act *act; struct termpair npair; size_t offset, rmargin; + int chld; + + /* + * In no-fill mode, break the output line at the beginning + * of new input lines except after \c, and nowhere else. + */ + + if (n->flags & NODE_NOFILL) { + if (n->flags & NODE_LINE && + (p->flags & TERMP_NONEWLINE) == 0) + term_newln(p); + p->flags |= TERMP_BRNEVER; + } else + p->flags &= ~TERMP_BRNEVER; if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT) return; @@ -341,11 +352,25 @@ print_mdoc_node(DECL_ARGS) * produce output. Note that some pre-handlers do so. */ + act = NULL; switch (n->type) { case ROFFT_TEXT: - if (*n->string == ' ' && n->flags & NODE_LINE && - (p->flags & TERMP_NONEWLINE) == 0) - term_newln(p); + if (n->flags & NODE_LINE) { + switch (*n->string) { + case '\0': + if (p->flags & TERMP_NONEWLINE) + term_newln(p); + else + term_vspace(p); + return; + case ' ': + if ((p->flags & TERMP_NONEWLINE) == 0) + term_newln(p); + break; + default: + break; + } + } if (NODE_DELIMC & n->flags) p->flags |= TERMP_NOSPACE; term_word(p, n->string); @@ -370,10 +395,10 @@ print_mdoc_node(DECL_ARGS) return; } assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX); - if (termacts[n->tok].pre != NULL && + act = mdoc_term_acts + (n->tok - MDOC_Dd); + if (act->pre != NULL && (n->end == ENDBODY_NOT || n->child != NULL)) - chld = (*termacts[n->tok].pre) - (p, &npair, meta, n); + chld = (*act->pre)(p, &npair, meta, n); break; } @@ -391,9 +416,9 @@ print_mdoc_node(DECL_ARGS) case ROFFT_EQN: break; default: - if (termacts[n->tok].post == NULL || n->flags & NODE_ENDED) + if (act->post == NULL || n->flags & NODE_ENDED) break; - (void)(*termacts[n->tok].post)(p, &npair, meta, n); + (void)(*act->post)(p, &npair, meta, n); /* * Explicit end tokens not only call the post @@ -1420,8 +1445,6 @@ termp_fa_pre(DECL_ARGS) static int termp_bd_pre(DECL_ARGS) { - size_t lm, len; - struct roff_node *nn; int offset; if (n->type == ROFFT_BLOCK) { @@ -1447,66 +1470,19 @@ termp_bd_pre(DECL_ARGS) p->tcol->offset += offset; } - /* - * If -ragged or -filled are specified, the block does nothing - * but change the indentation. If -unfilled or -literal are - * specified, text is printed exactly as entered in the display: - * for macro lines, a newline is appended to the line. Blank - * lines are allowed. - */ - - if (n->norm->Bd.type != DISP_literal && - n->norm->Bd.type != DISP_unfilled && - n->norm->Bd.type != DISP_centered) - return 1; - - if (n->norm->Bd.type == DISP_literal) { + switch (n->norm->Bd.type) { + case DISP_literal: term_tab_set(p, NULL); term_tab_set(p, "T"); term_tab_set(p, "8n"); + break; + case DISP_centered: + p->flags |= TERMP_CENTER; + break; + default: + break; } - - lm = p->tcol->offset; - p->flags |= TERMP_BRNEVER; - for (nn = n->child; nn != NULL; nn = nn->next) { - if (n->norm->Bd.type == DISP_centered) { - if (nn->type == ROFFT_TEXT) { - len = term_strlen(p, nn->string); - p->tcol->offset = len >= p->tcol->rmargin ? - 0 : lm + len >= p->tcol->rmargin ? - p->tcol->rmargin - len : - (lm + p->tcol->rmargin - len) / 2; - } else - p->tcol->offset = lm; - } - print_mdoc_node(p, pair, meta, nn); - /* - * If the printed node flushes its own line, then we - * needn't do it here as well. This is hacky, but the - * notion of selective eoln whitespace is pretty dumb - * anyway, so don't sweat it. - */ - if (nn->tok < ROFF_MAX) - continue; - switch (nn->tok) { - case MDOC_Sm: - case MDOC_Bl: - case MDOC_D1: - case MDOC_Dl: - case MDOC_Lp: - case MDOC_Pp: - continue; - default: - break; - } - if (p->flags & TERMP_NONEWLINE || - (nn->next && ! (nn->next->flags & NODE_LINE))) - continue; - term_flushln(p); - p->flags |= TERMP_NOSPACE; - } - p->flags &= ~TERMP_BRNEVER; - return 0; + return 1; } static void @@ -1514,12 +1490,14 @@ termp_bd_post(DECL_ARGS) { if (n->type != ROFFT_BODY) return; - if (DISP_literal == n->norm->Bd.type || - DISP_unfilled == n->norm->Bd.type) + if (n->norm->Bd.type == DISP_unfilled || + n->norm->Bd.type == DISP_literal) p->flags |= TERMP_BRNEVER; p->flags |= TERMP_NOSPACE; term_newln(p); p->flags &= ~TERMP_BRNEVER; + if (n->norm->Bd.type == DISP_centered) + p->flags &= ~TERMP_CENTER; } static int @@ -2098,3 +2076,9 @@ termp_tag_pre(DECL_ARGS) tag_put(n->child->string, 1, p->line); return 1; } + +static int +termp_abort_pre(DECL_ARGS) +{ + abort(); +} diff --git a/usr/src/cmd/mandoc/mdoc_validate.c b/usr/src/cmd/mandoc/mdoc_validate.c index 32067baf0a..4ef95e28b8 100644 --- a/usr/src/cmd/mandoc/mdoc_validate.c +++ b/usr/src/cmd/mandoc/mdoc_validate.c @@ -1,7 +1,7 @@ -/* $Id: mdoc_validate.c,v 1.360 2018/08/01 16:00:58 schwarze Exp $ */ +/* $Id: mdoc_validate.c,v 1.371 2019/03/04 13:01:57 schwarze Exp $ */ /* * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2010-2018 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2010-2019 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org> * Copyright 2019 Joyent, Inc. * @@ -64,6 +64,7 @@ static int child_an(const struct roff_node *); static size_t macro2len(enum roff_tok); static void rewrite_macro2len(struct roff_man *, char **); static int similar(const char *, const char *); +static void post_abort(POST_ARGS); static void post_an(POST_ARGS); static void post_an_norm(POST_ARGS); @@ -117,7 +118,7 @@ static void post_useless(POST_ARGS); static void post_xr(POST_ARGS); static void post_xx(POST_ARGS); -static const v_post __mdoc_valids[MDOC_MAX - MDOC_Dd] = { +static const v_post mdoc_valids[MDOC_MAX - MDOC_Dd] = { post_dd, /* Dd */ post_dt, /* Dt */ post_os, /* Os */ @@ -152,7 +153,7 @@ static const v_post __mdoc_valids[MDOC_MAX - MDOC_Dd] = { post_nd, /* Nd */ post_nm, /* Nm */ post_delim_nb, /* Op */ - post_obsolete, /* Ot */ + post_abort, /* Ot */ post_defaults, /* Pa */ post_rv, /* Rv */ post_st, /* St */ @@ -225,7 +226,7 @@ static const v_post __mdoc_valids[MDOC_MAX - MDOC_Dd] = { post_obsolete, /* Fr */ post_eoln, /* Ud */ post_lb, /* Lb */ - post_par, /* Lp */ + post_abort, /* Lp */ post_delim_nb, /* Lk */ post_defaults, /* Mt */ post_delim_nb, /* Brq */ @@ -239,7 +240,6 @@ static const v_post __mdoc_valids[MDOC_MAX - MDOC_Dd] = { NULL, /* %U */ NULL, /* Ta */ }; -static const v_post *const mdoc_valids = __mdoc_valids - MDOC_Dd; #define RSORD_MAX 14 /* Number of `Rs' blocks. */ @@ -287,22 +287,48 @@ static const char * const secnames[SEC__MAX] = { }; +/* Validate the subtree rooted at mdoc->last. */ void -mdoc_node_validate(struct roff_man *mdoc) +mdoc_validate(struct roff_man *mdoc) { struct roff_node *n, *np; const v_post *p; + /* + * Translate obsolete macros to modern macros first + * such that later code does not need to look + * for the obsolete versions. + */ + n = mdoc->last; + switch (n->tok) { + case MDOC_Lp: + n->tok = MDOC_Pp; + break; + case MDOC_Ot: + post_obsolete(mdoc); + n->tok = MDOC_Ft; + break; + default: + break; + } + + /* + * Iterate over all children, recursing into each one + * in turn, depth-first. + */ + mdoc->last = mdoc->last->child; while (mdoc->last != NULL) { - mdoc_node_validate(mdoc); + mdoc_validate(mdoc); if (mdoc->last == n) mdoc->last = mdoc->last->child; else mdoc->last = mdoc->last->next; } + /* Finally validate the macro itself. */ + mdoc->last = n; mdoc->next = ROFF_NEXT_SIBLING; switch (n->type) { @@ -311,9 +337,7 @@ mdoc_node_validate(struct roff_man *mdoc) if (n->sec != SEC_SYNOPSIS || (np->tok != MDOC_Cd && np->tok != MDOC_Fd)) check_text(mdoc, n->line, n->pos, n->string); - if (np->tok != MDOC_Ql && np->tok != MDOC_Dl && - (np->tok != MDOC_Bd || - (mdoc->flags & MDOC_LITERAL) == 0) && + if ((n->flags & NODE_NOFILL) == 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); @@ -345,20 +369,12 @@ mdoc_node_validate(struct roff_man *mdoc) /* Call the macro's postprocessor. */ if (n->tok < ROFF_MAX) { - switch(n->tok) { - case ROFF_br: - case ROFF_sp: - post_par(mdoc); - break; - default: - roff_validate(mdoc); - break; - } + roff_validate(mdoc); break; } assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX); - p = mdoc_valids + n->tok; + p = mdoc_valids + (n->tok - MDOC_Dd); if (*p) (*p)(mdoc); if (mdoc->last == n) @@ -394,12 +410,11 @@ check_text(struct roff_man *mdoc, int ln, int pos, char *p) { char *cp; - if (MDOC_LITERAL & mdoc->flags) + if (mdoc->last->flags & NODE_NOFILL) return; for (cp = p; NULL != (p = strchr(p, '\t')); p++) - mandoc_msg(MANDOCERR_FI_TAB, mdoc->parse, - ln, pos + (int)(p - cp), NULL); + mandoc_msg(MANDOCERR_FI_TAB, ln, pos + (int)(p - cp), NULL); } static void @@ -446,7 +461,7 @@ check_text_em(struct roff_man *mdoc, int ln, int pos, char *p) nn != NULL && nn->type == ROFFT_TEXT && isalpha((unsigned char)*nn->string))) { - mandoc_msg(MANDOCERR_DASHDASH, mdoc->parse, + mandoc_msg(MANDOCERR_DASHDASH, ln, pos + (int)(cp - p) - 1, NULL); break; } @@ -462,17 +477,13 @@ check_toptext(struct roff_man *mdoc, int ln, int pos, const char *p) return; if ((cp = strstr(p, "OpenBSD")) != NULL) - mandoc_msg(MANDOCERR_BX, mdoc->parse, - ln, pos + (cp - p), "Ox"); + mandoc_msg(MANDOCERR_BX, ln, pos + (int)(cp - p), "Ox"); if ((cp = strstr(p, "NetBSD")) != NULL) - mandoc_msg(MANDOCERR_BX, mdoc->parse, - ln, pos + (cp - p), "Nx"); + mandoc_msg(MANDOCERR_BX, ln, pos + (int)(cp - p), "Nx"); if ((cp = strstr(p, "FreeBSD")) != NULL) - mandoc_msg(MANDOCERR_BX, mdoc->parse, - ln, pos + (cp - p), "Fx"); + mandoc_msg(MANDOCERR_BX, ln, pos + (int)(cp - p), "Fx"); if ((cp = strstr(p, "DragonFly")) != NULL) - mandoc_msg(MANDOCERR_BX, mdoc->parse, - ln, pos + (cp - p), "Dx"); + mandoc_msg(MANDOCERR_BX, ln, pos + (int)(cp - p), "Dx"); cp = p; while ((cp = strstr(cp + 1, "()")) != NULL) { @@ -481,14 +492,19 @@ check_toptext(struct roff_man *mdoc, int ln, int pos, const char *p) break; if ((cpr < p || *cpr == ' ') && cpr + 1 < cp) { cpr++; - mandoc_vmsg(MANDOCERR_FUNC, mdoc->parse, - ln, pos + (cpr - p), + mandoc_msg(MANDOCERR_FUNC, ln, pos + (int)(cpr - p), "%.*s()", (int)(cp - cpr), cpr); } } } static void +post_abort(POST_ARGS) +{ + abort(); +} + +static void post_delim(POST_ARGS) { const struct roff_node *nch; @@ -510,9 +526,8 @@ post_delim(POST_ARGS) tok == MDOC_Ss || tok == MDOC_Fo)) return; - mandoc_vmsg(MANDOCERR_DELIM, mdoc->parse, - nch->line, nch->pos + (lc - nch->string), - "%s%s %s", roff_name[tok], + mandoc_msg(MANDOCERR_DELIM, nch->line, + nch->pos + (int)(lc - nch->string), "%s%s %s", roff_name[tok], nch == mdoc->last->child ? "" : " ...", nch->string); } @@ -604,9 +619,8 @@ post_delim_nb(POST_ARGS) } } - mandoc_vmsg(MANDOCERR_DELIM_NB, mdoc->parse, - nch->line, nch->pos + (lc - nch->string), - "%s%s %s", roff_name[tok], + mandoc_msg(MANDOCERR_DELIM_NB, nch->line, + nch->pos + (int)(lc - nch->string), "%s%s %s", roff_name[tok], nch == mdoc->last->child ? "" : " ...", nch->string); } @@ -672,39 +686,34 @@ post_bl_norm(POST_ARGS) case MDOC_Compact: if (n->norm->Bl.comp) mandoc_msg(MANDOCERR_ARG_REP, - mdoc->parse, argv->line, - argv->pos, "Bl -compact"); + argv->line, argv->pos, "Bl -compact"); n->norm->Bl.comp = 1; break; case MDOC_Width: wa = argv; if (0 == argv->sz) { mandoc_msg(MANDOCERR_ARG_EMPTY, - mdoc->parse, argv->line, - argv->pos, "Bl -width"); + argv->line, argv->pos, "Bl -width"); n->norm->Bl.width = "0n"; break; } if (NULL != n->norm->Bl.width) - mandoc_vmsg(MANDOCERR_ARG_REP, - mdoc->parse, argv->line, - argv->pos, "Bl -width %s", - argv->value[0]); + mandoc_msg(MANDOCERR_ARG_REP, + argv->line, argv->pos, + "Bl -width %s", argv->value[0]); rewrite_macro2len(mdoc, argv->value); n->norm->Bl.width = argv->value[0]; break; case MDOC_Offset: if (0 == argv->sz) { mandoc_msg(MANDOCERR_ARG_EMPTY, - mdoc->parse, argv->line, - argv->pos, "Bl -offset"); + argv->line, argv->pos, "Bl -offset"); break; } if (NULL != n->norm->Bl.offs) - mandoc_vmsg(MANDOCERR_ARG_REP, - mdoc->parse, argv->line, - argv->pos, "Bl -offset %s", - argv->value[0]); + mandoc_msg(MANDOCERR_ARG_REP, + argv->line, argv->pos, + "Bl -offset %s", argv->value[0]); rewrite_macro2len(mdoc, argv->value); n->norm->Bl.offs = argv->value[0]; break; @@ -718,8 +727,7 @@ post_bl_norm(POST_ARGS) /* Check: multiple list types. */ if (LIST__NONE != n->norm->Bl.type) { - mandoc_vmsg(MANDOCERR_BL_REP, - mdoc->parse, n->line, n->pos, + mandoc_msg(MANDOCERR_BL_REP, n->line, n->pos, "Bl -%s", mdoc_argnames[argv->arg]); continue; } @@ -729,8 +737,8 @@ post_bl_norm(POST_ARGS) if (n->norm->Bl.width || n->norm->Bl.offs || n->norm->Bl.comp) - mandoc_vmsg(MANDOCERR_BL_LATETYPE, - mdoc->parse, n->line, n->pos, "Bl -%s", + mandoc_msg(MANDOCERR_BL_LATETYPE, + n->line, n->pos, "Bl -%s", mdoc_argnames[n->args->argv[0].arg]); n->norm->Bl.type = lt; @@ -743,8 +751,7 @@ post_bl_norm(POST_ARGS) /* Allow lists to default to LIST_item. */ if (LIST__NONE == n->norm->Bl.type) { - mandoc_msg(MANDOCERR_BL_NOTYPE, mdoc->parse, - n->line, n->pos, "Bl"); + mandoc_msg(MANDOCERR_BL_NOTYPE, n->line, n->pos, "Bl"); n->norm->Bl.type = LIST_item; mdoclt = MDOC_Item; } @@ -759,7 +766,7 @@ post_bl_norm(POST_ARGS) switch (n->norm->Bl.type) { case LIST_tag: if (n->norm->Bl.width == NULL) - mandoc_msg(MANDOCERR_BL_NOWIDTH, mdoc->parse, + mandoc_msg(MANDOCERR_BL_NOWIDTH, n->line, n->pos, "Bl -tag"); break; case LIST_column: @@ -768,9 +775,8 @@ post_bl_norm(POST_ARGS) case LIST_inset: case LIST_item: if (n->norm->Bl.width != NULL) - mandoc_vmsg(MANDOCERR_BL_SKIPW, mdoc->parse, - wa->line, wa->pos, "Bl -%s", - mdoc_argnames[mdoclt]); + mandoc_msg(MANDOCERR_BL_SKIPW, wa->line, wa->pos, + "Bl -%s", mdoc_argnames[mdoclt]); n->norm->Bl.width = NULL; break; case LIST_bullet: @@ -818,29 +824,25 @@ post_bd(POST_ARGS) dt = DISP_literal; break; case MDOC_File: - mandoc_msg(MANDOCERR_BD_FILE, mdoc->parse, - n->line, n->pos, NULL); + mandoc_msg(MANDOCERR_BD_FILE, n->line, n->pos, NULL); break; case MDOC_Offset: if (0 == argv->sz) { mandoc_msg(MANDOCERR_ARG_EMPTY, - mdoc->parse, argv->line, - argv->pos, "Bd -offset"); + argv->line, argv->pos, "Bd -offset"); break; } if (NULL != n->norm->Bd.offs) - mandoc_vmsg(MANDOCERR_ARG_REP, - mdoc->parse, argv->line, - argv->pos, "Bd -offset %s", - argv->value[0]); + mandoc_msg(MANDOCERR_ARG_REP, + argv->line, argv->pos, + "Bd -offset %s", argv->value[0]); rewrite_macro2len(mdoc, argv->value); n->norm->Bd.offs = argv->value[0]; break; case MDOC_Compact: if (n->norm->Bd.comp) mandoc_msg(MANDOCERR_ARG_REP, - mdoc->parse, argv->line, - argv->pos, "Bd -compact"); + argv->line, argv->pos, "Bd -compact"); n->norm->Bd.comp = 1; break; default: @@ -852,14 +854,12 @@ post_bd(POST_ARGS) if (DISP__NONE == n->norm->Bd.type) n->norm->Bd.type = dt; else - mandoc_vmsg(MANDOCERR_BD_REP, - mdoc->parse, n->line, n->pos, + mandoc_msg(MANDOCERR_BD_REP, n->line, n->pos, "Bd -%s", mdoc_argnames[argv->arg]); } if (DISP__NONE == n->norm->Bd.type) { - mandoc_msg(MANDOCERR_BD_NOTYPE, mdoc->parse, - n->line, n->pos, "Bd"); + mandoc_msg(MANDOCERR_BD_NOTYPE, n->line, n->pos, "Bd"); n->norm->Bd.type = DISP_ragged; } } @@ -881,8 +881,7 @@ post_an_norm(POST_ARGS) for (i = 1; i < n->args->argc; i++) { argv = n->args->argv + i; - mandoc_vmsg(MANDOCERR_AN_REP, - mdoc->parse, argv->line, argv->pos, + mandoc_msg(MANDOCERR_AN_REP, argv->line, argv->pos, "An -%s", mdoc_argnames[argv->arg]); } @@ -903,7 +902,7 @@ post_eoln(POST_ARGS) post_useless(mdoc); n = mdoc->last; if (n->child != NULL) - mandoc_vmsg(MANDOCERR_ARG_SKIP, mdoc->parse, n->line, + mandoc_msg(MANDOCERR_ARG_SKIP, n->line, n->pos, "%s %s", roff_name[n->tok], n->child->string); while (n->child != NULL) @@ -925,7 +924,7 @@ build_list(struct roff_man *mdoc, int tok) for (ic = 1;; ic++) { roff_elem_alloc(mdoc, n->line, n->pos, tok); mdoc->last->flags |= NODE_NOSRC; - mdoc_node_relink(mdoc, n); + roff_node_relink(mdoc, n); n = mdoc->last = mdoc->last->parent; mdoc->next = ROFF_NEXT_SIBLING; if (n->next == NULL) @@ -966,8 +965,7 @@ post_ex(POST_ARGS) mdoc->next = ROFF_NEXT_SIBLING; ic = 1; } else { - mandoc_msg(MANDOCERR_EX_NONAME, mdoc->parse, - n->line, n->pos, "Ex"); + mandoc_msg(MANDOCERR_EX_NONAME, n->line, n->pos, "Ex"); ic = 0; } @@ -1000,7 +998,7 @@ post_lb(POST_ARGS) return; } - mandoc_vmsg(MANDOCERR_LB_BAD, mdoc->parse, n->child->line, + mandoc_msg(MANDOCERR_LB_BAD, n->child->line, n->child->pos, "Lb %s", n->child->string); roff_word_alloc(mdoc, n->line, n->pos, "library"); @@ -1064,8 +1062,8 @@ post_std(POST_ARGS) if (n->args->argv[0].arg == MDOC_Std) return; - mandoc_msg(MANDOCERR_ARG_STD, mdoc->parse, - n->line, n->pos, roff_name[n->tok]); + mandoc_msg(MANDOCERR_ARG_STD, n->line, n->pos, + "%s", roff_name[n->tok]); } static void @@ -1079,7 +1077,7 @@ post_st(POST_ARGS) assert(nch->type == ROFFT_TEXT); if ((p = mdoc_a2st(nch->string)) == NULL) { - mandoc_vmsg(MANDOCERR_ST_BAD, mdoc->parse, + mandoc_msg(MANDOCERR_ST_BAD, nch->line, nch->pos, "St %s", nch->string); roff_node_delete(mdoc, n); return; @@ -1099,8 +1097,8 @@ post_obsolete(POST_ARGS) n = mdoc->last; if (n->type == ROFFT_ELEM || n->type == ROFFT_BLOCK) - mandoc_msg(MANDOCERR_MACRO_OBS, mdoc->parse, - n->line, n->pos, roff_name[n->tok]); + mandoc_msg(MANDOCERR_MACRO_OBS, n->line, n->pos, + "%s", roff_name[n->tok]); } static void @@ -1109,8 +1107,8 @@ post_useless(POST_ARGS) struct roff_node *n; n = mdoc->last; - mandoc_msg(MANDOCERR_MACRO_USELESS, mdoc->parse, - n->line, n->pos, roff_name[n->tok]); + mandoc_msg(MANDOCERR_MACRO_USELESS, n->line, n->pos, + "%s", roff_name[n->tok]); } /* @@ -1139,14 +1137,14 @@ post_bf(POST_ARGS) nch = np->child; if (np->parent->args == NULL) { if (nch == NULL) { - mandoc_msg(MANDOCERR_BF_NOFONT, mdoc->parse, + mandoc_msg(MANDOCERR_BF_NOFONT, np->line, np->pos, "Bf"); return; } nch = nch->next; } if (nch != NULL) - mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, + mandoc_msg(MANDOCERR_ARG_EXCESS, nch->line, nch->pos, "Bf ... %s", nch->string); /* Extract argument into data. */ @@ -1177,9 +1175,8 @@ post_bf(POST_ARGS) else if ( ! strcmp(np->child->string, "Sy")) np->norm->Bf.font = FONT_Sy; else - mandoc_vmsg(MANDOCERR_BF_BADFONT, mdoc->parse, - np->child->line, np->child->pos, - "Bf %s", np->child->string); + mandoc_msg(MANDOCERR_BF_BADFONT, np->child->line, + np->child->pos, "Bf %s", np->child->string); } static void @@ -1193,8 +1190,8 @@ post_fname(POST_ARGS) pos = strcspn(n->string, "()"); cp = n->string + pos; if ( ! (cp[0] == '\0' || (cp[0] == '(' && cp[1] == '*'))) - mandoc_msg(MANDOCERR_FN_PAREN, mdoc->parse, - n->line, n->pos + pos, n->string); + mandoc_msg(MANDOCERR_FN_PAREN, n->line, n->pos + pos, + "%s", n->string); } static void @@ -1216,12 +1213,11 @@ post_fo(POST_ARGS) return; if (n->child == NULL) { - mandoc_msg(MANDOCERR_FO_NOHEAD, mdoc->parse, - n->line, n->pos, "Fo"); + mandoc_msg(MANDOCERR_FO_NOHEAD, n->line, n->pos, "Fo"); return; } if (n->child != n->last) { - mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, + mandoc_msg(MANDOCERR_ARG_EXCESS, n->child->next->line, n->child->next->pos, "Fo ... %s", n->child->next->string); while (n->child != n->last) @@ -1245,9 +1241,8 @@ post_fa(POST_ARGS) break; if (*cp != ',') continue; - mandoc_msg(MANDOCERR_FA_COMMA, mdoc->parse, - n->line, n->pos + (cp - n->string), - n->string); + mandoc_msg(MANDOCERR_FA_COMMA, n->line, + n->pos + (int)(cp - n->string), "%s", n->string); break; } } @@ -1265,18 +1260,15 @@ post_nm(POST_ARGS) n->child->type == ROFFT_TEXT && mdoc->meta.msec != NULL) mandoc_xr_add(mdoc->meta.msec, n->child->string, -1, -1); - if (n->last != NULL && - (n->last->tok == MDOC_Pp || - n->last->tok == MDOC_Lp)) - mdoc_node_relink(mdoc, n->last); + if (n->last != NULL && n->last->tok == MDOC_Pp) + roff_node_relink(mdoc, n->last); if (mdoc->meta.name == NULL) deroff(&mdoc->meta.name, n); if (mdoc->meta.name == NULL || (mdoc->lastsec == SEC_NAME && n->child == NULL)) - mandoc_msg(MANDOCERR_NM_NONAME, mdoc->parse, - n->line, n->pos, "Nm"); + mandoc_msg(MANDOCERR_NM_NONAME, n->line, n->pos, "Nm"); switch (n->type) { case ROFFT_ELEM: @@ -1310,12 +1302,10 @@ post_nd(POST_ARGS) return; if (n->sec != SEC_NAME) - mandoc_msg(MANDOCERR_ND_LATE, mdoc->parse, - n->line, n->pos, "Nd"); + mandoc_msg(MANDOCERR_ND_LATE, n->line, n->pos, "Nd"); if (n->child == NULL) - mandoc_msg(MANDOCERR_ND_EMPTY, mdoc->parse, - n->line, n->pos, "Nd"); + mandoc_msg(MANDOCERR_ND_EMPTY, n->line, n->pos, "Nd"); else post_delim(mdoc); @@ -1335,8 +1325,8 @@ post_display(POST_ARGS) n->body->parent->args == NULL) roff_node_delete(mdoc, n); } else if (n->child == NULL) - mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse, - n->line, n->pos, roff_name[n->tok]); + mandoc_msg(MANDOCERR_BLK_EMPTY, n->line, n->pos, + "%s", roff_name[n->tok]); else if (n->tok == MDOC_D1) post_hyph(mdoc); break; @@ -1344,10 +1334,10 @@ post_display(POST_ARGS) if (n->tok == MDOC_Bd) { if (n->args == NULL) { mandoc_msg(MANDOCERR_BD_NOARG, - mdoc->parse, n->line, n->pos, "Bd"); + n->line, n->pos, "Bd"); mdoc->next = ROFF_NEXT_SIBLING; while (n->body->child != NULL) - mdoc_node_relink(mdoc, + roff_node_relink(mdoc, n->body->child); roff_node_delete(mdoc, n); break; @@ -1357,9 +1347,8 @@ post_display(POST_ARGS) } for (np = n->parent; np != NULL; np = np->parent) { if (np->type == ROFFT_BLOCK && np->tok == MDOC_Bd) { - mandoc_vmsg(MANDOCERR_BD_NEST, - mdoc->parse, n->line, n->pos, - "%s in Bd", roff_name[n->tok]); + mandoc_msg(MANDOCERR_BD_NEST, n->line, + n->pos, "%s in Bd", roff_name[n->tok]); break; } } @@ -1423,7 +1412,7 @@ post_at(POST_ARGS) att = NULL; if (nch != NULL && ((att = mdoc_a2att(nch->string)) == NULL)) - mandoc_vmsg(MANDOCERR_AT_BAD, mdoc->parse, + mandoc_msg(MANDOCERR_AT_BAD, nch->line, nch->pos, "At %s", nch->string); mdoc->next = ROFF_NEXT_CHILD; @@ -1447,12 +1436,12 @@ post_an(POST_ARGS) nch = np->child; if (np->norm->An.auth == AUTH__NONE) { if (nch == NULL) - mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, + mandoc_msg(MANDOCERR_MACRO_EMPTY, np->line, np->pos, "An"); else post_delim_nb(mdoc); } else if (nch != NULL) - mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, + mandoc_msg(MANDOCERR_ARG_EXCESS, nch->line, nch->pos, "An ... %s", nch->string); } @@ -1548,9 +1537,8 @@ post_it(POST_ARGS) case LIST_inset: case LIST_diag: if (nit->head->child == NULL) - mandoc_vmsg(MANDOCERR_IT_NOHEAD, - mdoc->parse, nit->line, nit->pos, - "Bl -%s It", + mandoc_msg(MANDOCERR_IT_NOHEAD, + nit->line, nit->pos, "Bl -%s It", mdoc_argnames[nbl->args->argv[0].arg]); break; case LIST_bullet: @@ -1558,14 +1546,13 @@ post_it(POST_ARGS) case LIST_enum: case LIST_hyphen: if (nit->body == NULL || nit->body->child == NULL) - mandoc_vmsg(MANDOCERR_IT_NOBODY, - mdoc->parse, nit->line, nit->pos, - "Bl -%s It", + mandoc_msg(MANDOCERR_IT_NOBODY, + nit->line, nit->pos, "Bl -%s It", mdoc_argnames[nbl->args->argv[0].arg]); /* FALLTHROUGH */ case LIST_item: if ((nch = nit->head->child) != NULL) - mandoc_vmsg(MANDOCERR_ARG_SKIP, mdoc->parse, + mandoc_msg(MANDOCERR_ARG_SKIP, nit->line, nit->pos, "It %s", nch->string == NULL ? roff_name[nch->tok] : nch->string); @@ -1577,7 +1564,7 @@ post_it(POST_ARGS) if (nit->head->next->child == NULL && nit->head->next->next == NULL) { - mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, + mandoc_msg(MANDOCERR_MACRO_EMPTY, nit->line, nit->pos, "It"); roff_node_delete(mdoc, nit); break; @@ -1588,16 +1575,15 @@ post_it(POST_ARGS) if (nch->type != ROFFT_BODY) continue; if (i++ && nch->flags & NODE_LINE) - mandoc_msg(MANDOCERR_TA_LINE, mdoc->parse, + mandoc_msg(MANDOCERR_TA_LINE, nch->line, nch->pos, "Ta"); } if (i < cols || i > cols + 1) - mandoc_vmsg(MANDOCERR_BL_COL, - mdoc->parse, nit->line, nit->pos, + mandoc_msg(MANDOCERR_BL_COL, nit->line, nit->pos, "%d columns, %d cells", cols, i); else if (nit->head->next->child != NULL && - nit->head->next->child->line > nit->line) - mandoc_msg(MANDOCERR_IT_NOARG, mdoc->parse, + nit->head->next->child->flags & NODE_LINE) + mandoc_msg(MANDOCERR_IT_NOARG, nit->line, nit->pos, "Bl -column It"); break; default: @@ -1620,7 +1606,6 @@ post_bl_block(POST_ARGS) while (nc != NULL) { switch (nc->tok) { case MDOC_Pp: - case MDOC_Lp: case ROFF_br: break; default: @@ -1628,14 +1613,13 @@ post_bl_block(POST_ARGS) continue; } if (ni->next == NULL) { - mandoc_msg(MANDOCERR_PAR_MOVE, - mdoc->parse, nc->line, nc->pos, - roff_name[nc->tok]); - mdoc_node_relink(mdoc, nc); + mandoc_msg(MANDOCERR_PAR_MOVE, nc->line, + nc->pos, "%s", roff_name[nc->tok]); + roff_node_relink(mdoc, nc); } else if (n->norm->Bl.comp == 0 && n->norm->Bl.type != LIST_column) { - mandoc_vmsg(MANDOCERR_PAR_SKIP, - mdoc->parse, nc->line, nc->pos, + mandoc_msg(MANDOCERR_PAR_SKIP, + nc->line, nc->pos, "%s before It", roff_name[nc->tok]); roff_node_delete(mdoc, nc); } else @@ -1681,7 +1665,7 @@ post_bl_head(POST_ARGS) if (nh->norm->Bl.type != LIST_column) { if ((nch = nh->child) == NULL) return; - mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, + mandoc_msg(MANDOCERR_ARG_EXCESS, nch->line, nch->pos, "Bl ... %s", nch->string); while (nch != NULL) { roff_node_delete(mdoc, nch); @@ -1758,7 +1742,7 @@ post_bl(POST_ARGS) nchild = nbody->child; if (nchild == NULL) { - mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse, + mandoc_msg(MANDOCERR_BLK_EMPTY, nbody->line, nbody->pos, "Bl"); return; } @@ -1791,7 +1775,7 @@ post_bl(POST_ARGS) roff_body_alloc(mdoc, nchild->line, nchild->pos, MDOC_It); while (nchild->tok != MDOC_It) { - mdoc_node_relink(mdoc, nchild); + roff_node_relink(mdoc, nchild); if ((nchild = nnext) == NULL) break; nnext = nchild->next; @@ -1801,8 +1785,8 @@ post_bl(POST_ARGS) continue; } - mandoc_msg(MANDOCERR_BL_MOVE, mdoc->parse, - nchild->line, nchild->pos, roff_name[nchild->tok]); + mandoc_msg(MANDOCERR_BL_MOVE, nchild->line, nchild->pos, + "%s", roff_name[nchild->tok]); /* * Move the node out of the Bl block. @@ -1857,13 +1841,13 @@ post_bl(POST_ARGS) if (prev_Er != NULL) { order = strcmp(prev_Er, nnext->string); if (order > 0) - mandoc_vmsg(MANDOCERR_ER_ORDER, - mdoc->parse, nnext->line, nnext->pos, + mandoc_msg(MANDOCERR_ER_ORDER, + nnext->line, nnext->pos, "Er %s %s (NetBSD)", prev_Er, nnext->string); else if (order == 0) - mandoc_vmsg(MANDOCERR_ER_REP, - mdoc->parse, nnext->line, nnext->pos, + mandoc_msg(MANDOCERR_ER_REP, + nnext->line, nnext->pos, "Er %s (NetBSD)", prev_Er); } prev_Er = nnext->string; @@ -1878,8 +1862,7 @@ post_bk(POST_ARGS) n = mdoc->last; if (n->type == ROFFT_BLOCK && n->body->child == NULL) { - mandoc_msg(MANDOCERR_BLK_EMPTY, - mdoc->parse, n->line, n->pos, "Bk"); + mandoc_msg(MANDOCERR_BLK_EMPTY, n->line, n->pos, "Bk"); roff_node_delete(mdoc, n); } } @@ -1907,39 +1890,16 @@ post_sm(POST_ARGS) return; } - mandoc_vmsg(MANDOCERR_SM_BAD, - mdoc->parse, nch->line, nch->pos, + mandoc_msg(MANDOCERR_SM_BAD, nch->line, nch->pos, "%s %s", roff_name[mdoc->last->tok], nch->string); - mdoc_node_relink(mdoc, nch); + roff_node_relink(mdoc, nch); return; } static void post_root(POST_ARGS) { - const char *openbsd_arch[] = { - "alpha", "amd64", "arm64", "armv7", "hppa", "i386", - "landisk", "loongson", "luna88k", "macppc", "mips64", - "octeon", "sgi", "socppc", "sparc64", NULL - }; - const char *netbsd_arch[] = { - "acorn26", "acorn32", "algor", "alpha", "amiga", - "arc", "atari", - "bebox", "cats", "cesfic", "cobalt", "dreamcast", - "emips", "evbarm", "evbmips", "evbppc", "evbsh3", "evbsh5", - "hp300", "hpcarm", "hpcmips", "hpcsh", "hppa", - "i386", "ibmnws", "luna68k", - "mac68k", "macppc", "mipsco", "mmeye", "mvme68k", "mvmeppc", - "netwinder", "news68k", "newsmips", "next68k", - "pc532", "playstation2", "pmax", "pmppc", "prep", - "sandpoint", "sbmips", "sgimips", "shark", - "sparc", "sparc64", "sun2", "sun3", - "vax", "walnut", "x68k", "x86", "x86_64", "xen", NULL - }; - const char **arches[] = { NULL, netbsd_arch, openbsd_arch }; - struct roff_node *n; - const char **arch; /* Add missing prologue data. */ @@ -1948,8 +1908,7 @@ post_root(POST_ARGS) mandoc_normdate(mdoc, NULL, 0, 0); if (mdoc->meta.title == NULL) { - mandoc_msg(MANDOCERR_DT_NOTITLE, - mdoc->parse, 0, 0, "EOF"); + mandoc_msg(MANDOCERR_DT_NOTITLE, 0, 0, "EOF"); mdoc->meta.title = mandoc_strdup("UNTITLED"); } @@ -1957,49 +1916,43 @@ post_root(POST_ARGS) mdoc->meta.vol = mandoc_strdup("LOCAL"); if (mdoc->meta.os == NULL) { - mandoc_msg(MANDOCERR_OS_MISSING, - mdoc->parse, 0, 0, NULL); + mandoc_msg(MANDOCERR_OS_MISSING, 0, 0, NULL); mdoc->meta.os = mandoc_strdup(""); } else if (mdoc->meta.os_e && (mdoc->meta.rcsids & (1 << mdoc->meta.os_e)) == 0) - mandoc_msg(MANDOCERR_RCS_MISSING, mdoc->parse, 0, 0, + mandoc_msg(MANDOCERR_RCS_MISSING, 0, 0, mdoc->meta.os_e == MANDOC_OS_OPENBSD ? "(OpenBSD)" : "(NetBSD)"); if (mdoc->meta.arch != NULL && - (arch = arches[mdoc->meta.os_e]) != NULL) { - while (*arch != NULL && strcmp(*arch, mdoc->meta.arch)) - arch++; - if (*arch == NULL) { - n = mdoc->first->child; - 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, - mdoc->parse, n->line, n->pos, - "Dt ... %s %s", mdoc->meta.arch, - mdoc->meta.os_e == MANDOC_OS_OPENBSD ? - "(OpenBSD)" : "(NetBSD)"); - } + arch_valid(mdoc->meta.arch, mdoc->meta.os_e) == 0) { + n = mdoc->meta.first->child; + 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_msg(MANDOCERR_ARCH_BAD, n->line, n->pos, + "Dt ... %s %s", mdoc->meta.arch, + mdoc->meta.os_e == MANDOC_OS_OPENBSD ? + "(OpenBSD)" : "(NetBSD)"); } /* Check that we begin with a proper `Sh'. */ - n = mdoc->first->child; + n = mdoc->meta.first->child; while (n != NULL && (n->type == ROFFT_COMMENT || (n->tok >= MDOC_Dd && - mdoc_macros[n->tok].flags & MDOC_PROLOGUE))) + mdoc_macro(n->tok)->flags & MDOC_PROLOGUE))) n = n->next; if (n == NULL) - mandoc_msg(MANDOCERR_DOC_EMPTY, mdoc->parse, 0, 0, NULL); + mandoc_msg(MANDOCERR_DOC_EMPTY, 0, 0, NULL); else if (n->tok != MDOC_Sh) - mandoc_msg(MANDOCERR_SEC_BEFORE, mdoc->parse, - n->line, n->pos, roff_name[n->tok]); + mandoc_msg(MANDOCERR_SEC_BEFORE, n->line, n->pos, + "%s", roff_name[n->tok]); } static void @@ -2014,8 +1967,7 @@ post_rs(POST_ARGS) return; if (np->child == NULL) { - mandoc_msg(MANDOCERR_RS_EMPTY, mdoc->parse, - np->line, np->pos, "Rs"); + mandoc_msg(MANDOCERR_RS_EMPTY, np->line, np->pos, "Rs"); return; } @@ -2033,8 +1985,8 @@ post_rs(POST_ARGS) break; if (i == RSORD_MAX) { - mandoc_msg(MANDOCERR_RS_BAD, mdoc->parse, - nch->line, nch->pos, roff_name[nch->tok]); + mandoc_msg(MANDOCERR_RS_BAD, nch->line, nch->pos, + "%s", roff_name[nch->tok]); i = -1; } else if (nch->tok == MDOC__J || nch->tok == MDOC__B) np->norm->Rs.quote_T++; @@ -2123,8 +2075,7 @@ post_ns(POST_ARGS) n = mdoc->last; if (n->flags & NODE_LINE || (n->next != NULL && n->next->flags & NODE_DELIMC)) - mandoc_msg(MANDOCERR_NS_SKIP, mdoc->parse, - n->line, n->pos, NULL); + mandoc_msg(MANDOCERR_NS_SKIP, n->line, n->pos, NULL); } static void @@ -2176,8 +2127,8 @@ post_sh_name(POST_ARGS) switch (n->tok) { case MDOC_Nm: if (hasnm && n->child != NULL) - mandoc_vmsg(MANDOCERR_NAMESEC_PUNCT, - mdoc->parse, n->line, n->pos, + mandoc_msg(MANDOCERR_NAMESEC_PUNCT, + n->line, n->pos, "Nm %s", n->child->string); hasnm = 1; continue; @@ -2185,7 +2136,7 @@ post_sh_name(POST_ARGS) hasnd = 1; if (n->next != NULL) mandoc_msg(MANDOCERR_NAMESEC_ND, - mdoc->parse, n->line, n->pos, NULL); + n->line, n->pos, NULL); break; case TOKEN_NONE: if (n->type == ROFFT_TEXT && @@ -2196,18 +2147,18 @@ post_sh_name(POST_ARGS) } /* FALLTHROUGH */ default: - mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse, - n->line, n->pos, roff_name[n->tok]); + mandoc_msg(MANDOCERR_NAMESEC_BAD, + n->line, n->pos, "%s", roff_name[n->tok]); continue; } break; } if ( ! hasnm) - mandoc_msg(MANDOCERR_NAMESEC_NONM, mdoc->parse, + mandoc_msg(MANDOCERR_NAMESEC_NONM, mdoc->last->line, mdoc->last->pos, NULL); if ( ! hasnd) - mandoc_msg(MANDOCERR_NAMESEC_NOND, mdoc->parse, + mandoc_msg(MANDOCERR_NAMESEC_NOND, mdoc->last->line, mdoc->last->pos, NULL); } @@ -2233,21 +2184,18 @@ post_sh_see_also(POST_ARGS) sec = n->child->next->string; if (lastsec != NULL) { if (lastpunct[0] != ',' || lastpunct[1] != '\0') - mandoc_vmsg(MANDOCERR_XR_PUNCT, - mdoc->parse, n->line, n->pos, - "%s before %s(%s)", lastpunct, - name, sec); + mandoc_msg(MANDOCERR_XR_PUNCT, n->line, + n->pos, "%s before %s(%s)", + lastpunct, name, sec); cmp = strcmp(lastsec, sec); if (cmp > 0) - mandoc_vmsg(MANDOCERR_XR_ORDER, - mdoc->parse, n->line, n->pos, - "%s(%s) after %s(%s)", name, - sec, lastname, lastsec); + mandoc_msg(MANDOCERR_XR_ORDER, n->line, + n->pos, "%s(%s) after %s(%s)", + name, sec, lastname, lastsec); else if (cmp == 0 && strcasecmp(lastname, name) > 0) - mandoc_vmsg(MANDOCERR_XR_ORDER, - mdoc->parse, n->line, n->pos, - "%s after %s", name, lastname); + mandoc_msg(MANDOCERR_XR_ORDER, n->line, + n->pos, "%s after %s", name, lastname); } lastname = name; lastsec = sec; @@ -2268,8 +2216,8 @@ post_sh_see_also(POST_ARGS) return; lastpunct = n->string; if (n->next == NULL || n->next->tok == MDOC_Rs) - mandoc_vmsg(MANDOCERR_XR_PUNCT, mdoc->parse, - n->line, n->pos, "%s after %s(%s)", + mandoc_msg(MANDOCERR_XR_PUNCT, n->line, + n->pos, "%s after %s(%s)", lastpunct, lastname, lastsec); n = n->next; } @@ -2290,7 +2238,7 @@ post_sh_authors(POST_ARGS) { if ( ! child_an(mdoc->last)) - mandoc_msg(MANDOCERR_AN_MISSING, mdoc->parse, + mandoc_msg(MANDOCERR_AN_MISSING, mdoc->last->line, mdoc->last->pos, NULL); } @@ -2356,7 +2304,7 @@ post_sh_head(POST_ARGS) /* The NAME should be first. */ if (sec != SEC_NAME && mdoc->lastnamed == SEC_NONE) - mandoc_vmsg(MANDOCERR_NAMESEC_FIRST, mdoc->parse, + mandoc_msg(MANDOCERR_NAMESEC_FIRST, mdoc->last->line, mdoc->last->pos, "Sh %s", sec != SEC_CUSTOM ? secnames[sec] : (nch = mdoc->last->child) == NULL ? "" : @@ -2393,9 +2341,8 @@ post_sh_head(POST_ARGS) } } if (goodsec != NULL) - mandoc_vmsg(MANDOCERR_SEC_TYPO, mdoc->parse, - nch->line, nch->pos, "Sh %s instead of %s", - nch->string, goodsec); + mandoc_msg(MANDOCERR_SEC_TYPO, nch->line, nch->pos, + "Sh %s instead of %s", nch->string, goodsec); return; } @@ -2405,14 +2352,12 @@ post_sh_head(POST_ARGS) */ if (sec == mdoc->lastnamed) - mandoc_vmsg(MANDOCERR_SEC_REP, mdoc->parse, - mdoc->last->line, mdoc->last->pos, - "Sh %s", secnames[sec]); + mandoc_msg(MANDOCERR_SEC_REP, mdoc->last->line, + mdoc->last->pos, "Sh %s", secnames[sec]); if (sec < mdoc->lastnamed) - mandoc_vmsg(MANDOCERR_SEC_ORDER, mdoc->parse, - mdoc->last->line, mdoc->last->pos, - "Sh %s", secnames[sec]); + mandoc_msg(MANDOCERR_SEC_ORDER, mdoc->last->line, + mdoc->last->pos, "Sh %s", secnames[sec]); /* Mark the last named section. */ @@ -2446,7 +2391,7 @@ post_sh_head(POST_ARGS) break; if (NULL == goodsec) goodsec = "9"; - mandoc_vmsg(MANDOCERR_SEC_MSEC, mdoc->parse, + mandoc_msg(MANDOCERR_SEC_MSEC, mdoc->last->line, mdoc->last->pos, "Sh %s for %s only", secnames[sec], goodsec); break; @@ -2463,13 +2408,13 @@ post_xr(POST_ARGS) n = mdoc->last; nch = n->child; if (nch->next == NULL) { - mandoc_vmsg(MANDOCERR_XR_NOSEC, mdoc->parse, + mandoc_msg(MANDOCERR_XR_NOSEC, n->line, n->pos, "Xr %s", nch->string); } else { assert(nch->next == n->last); if(mandoc_xr_add(nch->next->string, nch->string, nch->line, nch->pos)) - mandoc_vmsg(MANDOCERR_XR_SELF, mdoc->parse, + mandoc_msg(MANDOCERR_XR_SELF, nch->line, nch->pos, "Xr %s %s", nch->string, nch->next->string); } @@ -2496,19 +2441,18 @@ post_ignpar(POST_ARGS) } if ((np = mdoc->last->child) != NULL) - if (np->tok == MDOC_Pp || np->tok == MDOC_Lp) { - mandoc_vmsg(MANDOCERR_PAR_SKIP, - mdoc->parse, np->line, np->pos, + if (np->tok == MDOC_Pp || + np->tok == ROFF_br || np->tok == ROFF_sp) { + mandoc_msg(MANDOCERR_PAR_SKIP, np->line, np->pos, "%s after %s", roff_name[np->tok], roff_name[mdoc->last->tok]); roff_node_delete(mdoc, np); } if ((np = mdoc->last->last) != NULL) - if (np->tok == MDOC_Pp || np->tok == MDOC_Lp) { - mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse, - np->line, np->pos, "%s at the end of %s", - roff_name[np->tok], + if (np->tok == MDOC_Pp || np->tok == ROFF_br) { + mandoc_msg(MANDOCERR_PAR_SKIP, np->line, np->pos, + "%s at the end of %s", roff_name[np->tok], roff_name[mdoc->last->tok]); roff_node_delete(mdoc, np); } @@ -2526,13 +2470,11 @@ post_prevpar(POST_ARGS) return; /* - * Don't allow prior `Lp' or `Pp' prior to a paragraph-type - * block: `Lp', `Pp', or non-compact `Bd' or `Bl'. + * Don't allow `Pp' prior to a paragraph-type + * block: `Pp' or non-compact `Bd' or `Bl'. */ - if (n->prev->tok != MDOC_Pp && - n->prev->tok != MDOC_Lp && - n->prev->tok != ROFF_br) + if (n->prev->tok != MDOC_Pp && n->prev->tok != ROFF_br) return; if (n->tok == MDOC_Bl && n->norm->Bl.comp) return; @@ -2541,9 +2483,8 @@ post_prevpar(POST_ARGS) if (n->tok == MDOC_It && n->parent->norm->Bl.comp) return; - mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse, - n->prev->line, n->prev->pos, "%s before %s", - roff_name[n->prev->tok], roff_name[n->tok]); + mandoc_msg(MANDOCERR_PAR_SKIP, n->prev->line, n->prev->pos, + "%s before %s", roff_name[n->prev->tok], roff_name[n->tok]); roff_node_delete(mdoc, n->prev); } @@ -2552,33 +2493,12 @@ post_par(POST_ARGS) { struct roff_node *np; - np = mdoc->last; - if (np->tok != ROFF_br && np->tok != ROFF_sp) - post_prevpar(mdoc); - - if (np->tok == ROFF_sp) { - if (np->child != NULL && np->child->next != NULL) - mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, - np->child->next->line, np->child->next->pos, - "sp ... %s", np->child->next->string); - } else if (np->child != NULL) - mandoc_vmsg(MANDOCERR_ARG_SKIP, - mdoc->parse, np->line, np->pos, "%s %s", - roff_name[np->tok], np->child->string); - - if ((np = mdoc->last->prev) == NULL) { - np = mdoc->last->parent; - if (np->tok != MDOC_Sh && np->tok != MDOC_Ss) - return; - } else if (np->tok != MDOC_Pp && np->tok != MDOC_Lp && - (mdoc->last->tok != ROFF_br || - (np->tok != ROFF_sp && np->tok != ROFF_br))) - return; + post_prevpar(mdoc); - mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse, - mdoc->last->line, mdoc->last->pos, "%s after %s", - roff_name[mdoc->last->tok], roff_name[np->tok]); - roff_node_delete(mdoc, mdoc->last); + np = mdoc->last; + if (np->child != NULL) + mandoc_msg(MANDOCERR_ARG_SKIP, np->line, np->pos, + "%s %s", roff_name[np->tok], np->child->string); } static void @@ -2591,17 +2511,15 @@ post_dd(POST_ARGS) n->flags |= NODE_NOPRT; if (mdoc->meta.date != NULL) { - mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse, - n->line, n->pos, "Dd"); + mandoc_msg(MANDOCERR_PROLOG_REP, n->line, n->pos, "Dd"); free(mdoc->meta.date); } else if (mdoc->flags & MDOC_PBODY) - mandoc_msg(MANDOCERR_PROLOG_LATE, mdoc->parse, - n->line, n->pos, "Dd"); + mandoc_msg(MANDOCERR_PROLOG_LATE, n->line, n->pos, "Dd"); else if (mdoc->meta.title != NULL) - mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse, + mandoc_msg(MANDOCERR_PROLOG_ORDER, n->line, n->pos, "Dd after Dt"); else if (mdoc->meta.os != NULL) - mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse, + mandoc_msg(MANDOCERR_PROLOG_ORDER, n->line, n->pos, "Dd after Os"); if (n->child == NULL || n->child->string[0] == '\0') { @@ -2632,16 +2550,14 @@ post_dt(POST_ARGS) n->flags |= NODE_NOPRT; if (mdoc->flags & MDOC_PBODY) { - mandoc_msg(MANDOCERR_DT_LATE, mdoc->parse, - n->line, n->pos, "Dt"); + mandoc_msg(MANDOCERR_DT_LATE, n->line, n->pos, "Dt"); return; } if (mdoc->meta.title != NULL) - mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse, - n->line, n->pos, "Dt"); + mandoc_msg(MANDOCERR_PROLOG_REP, n->line, n->pos, "Dt"); else if (mdoc->meta.os != NULL) - mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse, + mandoc_msg(MANDOCERR_PROLOG_ORDER, n->line, n->pos, "Dt after Os"); free(mdoc->meta.title); @@ -2658,8 +2574,7 @@ post_dt(POST_ARGS) nn = n->child; if (nn == NULL || *nn->string == '\0') { - mandoc_msg(MANDOCERR_DT_NOTITLE, - mdoc->parse, n->line, n->pos, "Dt"); + mandoc_msg(MANDOCERR_DT_NOTITLE, n->line, n->pos, "Dt"); mdoc->meta.title = mandoc_strdup("UNTITLED"); } else { mdoc->meta.title = mandoc_strdup(nn->string); @@ -2668,9 +2583,8 @@ post_dt(POST_ARGS) for (p = nn->string; *p != '\0'; p++) if (islower((unsigned char)*p)) { - mandoc_vmsg(MANDOCERR_TITLE_CASE, - mdoc->parse, nn->line, - nn->pos + (p - nn->string), + mandoc_msg(MANDOCERR_TITLE_CASE, nn->line, + nn->pos + (int)(p - nn->string), "Dt %s", nn->string); break; } @@ -2682,8 +2596,7 @@ post_dt(POST_ARGS) nn = nn->next; if (nn == NULL) { - mandoc_vmsg(MANDOCERR_MSEC_MISSING, - mdoc->parse, n->line, n->pos, + mandoc_msg(MANDOCERR_MSEC_MISSING, n->line, n->pos, "Dt %s", mdoc->meta.title); mdoc->meta.vol = mandoc_strdup("LOCAL"); return; /* msec and arch remain NULL. */ @@ -2695,7 +2608,7 @@ post_dt(POST_ARGS) cp = mandoc_a2msec(nn->string); if (cp == NULL) { - mandoc_vmsg(MANDOCERR_MSEC_BAD, mdoc->parse, + mandoc_msg(MANDOCERR_MSEC_BAD, nn->line, nn->pos, "Dt ... %s", nn->string); mdoc->meta.vol = mandoc_strdup(nn->string); } else @@ -2713,7 +2626,7 @@ post_dt(POST_ARGS) /* Ignore fourth and later arguments. */ if ((nn = nn->next) != NULL) - mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, + mandoc_msg(MANDOCERR_ARG_EXCESS, nn->line, nn->pos, "Dt ... %s", nn->string); } @@ -2734,8 +2647,8 @@ post_bx(POST_ARGS) !strcmp(nch->string, "Free") ? "Fx" : !strcmp(nch->string, "DragonFly") ? "Dx" : NULL; if (macro != NULL) - mandoc_msg(MANDOCERR_BX, mdoc->parse, - n->line, n->pos, macro); + mandoc_msg(MANDOCERR_BX, + n->line, n->pos, "%s", macro); mdoc->last = nch; nch = nch->next; mdoc->next = ROFF_NEXT_SIBLING; @@ -2783,11 +2696,9 @@ post_os(POST_ARGS) n->flags |= NODE_NOPRT; if (mdoc->meta.os != NULL) - mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse, - n->line, n->pos, "Os"); + mandoc_msg(MANDOCERR_PROLOG_REP, n->line, n->pos, "Os"); else if (mdoc->flags & MDOC_PBODY) - mandoc_msg(MANDOCERR_PROLOG_LATE, mdoc->parse, - n->line, n->pos, "Os"); + mandoc_msg(MANDOCERR_PROLOG_LATE, n->line, n->pos, "Os"); post_delim(mdoc); @@ -2816,8 +2727,7 @@ post_os(POST_ARGS) #else /*!OSNAME */ if (defbuf == NULL) { if (uname(&utsname) == -1) { - mandoc_msg(MANDOCERR_OS_UNAME, mdoc->parse, - n->line, n->pos, "Os"); + mandoc_msg(MANDOCERR_OS_UNAME, n->line, n->pos, "Os"); defbuf = mandoc_strdup("UNKNOWN"); } else mandoc_asprintf(&defbuf, "%s %s", @@ -2841,8 +2751,7 @@ out: */ if (n->child != NULL) - mandoc_vmsg(MANDOCERR_OS_ARG, mdoc->parse, - n->child->line, n->child->pos, + mandoc_msg(MANDOCERR_OS_ARG, n->child->line, n->child->pos, "Os %s (%s)", n->child->string, mdoc->meta.os_e == MANDOC_OS_OPENBSD ? "OpenBSD" : "NetBSD"); @@ -2854,14 +2763,12 @@ out: return; if (strncmp(n->string, "$" "Mdocdate", 9)) { if (mdoc->meta.os_e == MANDOC_OS_OPENBSD) - mandoc_vmsg(MANDOCERR_MDOCDATE_MISSING, - mdoc->parse, n->line, n->pos, - "Dd %s (OpenBSD)", n->string); + mandoc_msg(MANDOCERR_MDOCDATE_MISSING, n->line, + n->pos, "Dd %s (OpenBSD)", n->string); } else { if (mdoc->meta.os_e == MANDOC_OS_NETBSD) - mandoc_vmsg(MANDOCERR_MDOCDATE, - mdoc->parse, n->line, n->pos, - "Dd %s (NetBSD)", n->string); + mandoc_msg(MANDOCERR_MDOCDATE, n->line, + n->pos, "Dd %s (NetBSD)", n->string); } } diff --git a/usr/src/cmd/mandoc/msec.c b/usr/src/cmd/mandoc/msec.c index 9d41511696..9a52213d95 100644 --- a/usr/src/cmd/mandoc/msec.c +++ b/usr/src/cmd/mandoc/msec.c @@ -1,4 +1,4 @@ -/* $Id: msec.c,v 1.15 2015/10/06 18:32:19 schwarze Exp $ */ +/* $Id: msec.c,v 1.16 2018/12/14 01:18:26 schwarze Exp $ */ /* * Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -18,6 +18,7 @@ #include <sys/types.h> +#include <stdio.h> #include <string.h> #include "mandoc.h" diff --git a/usr/src/cmd/mandoc/out.c b/usr/src/cmd/mandoc/out.c index b2b643787e..d0b0d0a2ac 100644 --- a/usr/src/cmd/mandoc/out.c +++ b/usr/src/cmd/mandoc/out.c @@ -1,7 +1,7 @@ -/* $Id: out.c,v 1.70 2017/06/27 18:25:02 schwarze Exp $ */ +/* $Id: out.c,v 1.78 2019/03/29 21:27:06 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2011, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2011,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 @@ -20,21 +20,29 @@ #include <sys/types.h> #include <assert.h> +#include <ctype.h> #include <stdint.h> #include <stdlib.h> #include <string.h> #include <time.h> #include "mandoc_aux.h" -#include "mandoc.h" +#include "tbl.h" #include "out.h" -static void tblcalc_data(struct rofftbl *, struct roffcol *, +struct tbl_colgroup { + struct tbl_colgroup *next; + size_t wanted; + int startcol; + int endcol; +}; + +static size_t tblcalc_data(struct rofftbl *, struct roffcol *, const struct tbl_opts *, const struct tbl_dat *, size_t); -static void tblcalc_literal(struct rofftbl *, struct roffcol *, +static size_t tblcalc_literal(struct rofftbl *, struct roffcol *, const struct tbl_dat *, size_t); -static void tblcalc_number(struct rofftbl *, struct roffcol *, +static size_t tblcalc_number(struct rofftbl *, struct roffcol *, const struct tbl_opts *, const struct tbl_dat *); @@ -103,16 +111,18 @@ a2roffsu(const char *src, struct roffsu *dst, enum roffscale def) * used for the actual width calculations. */ void -tblcalc(struct rofftbl *tbl, const struct tbl_span *sp, +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; struct roffcol *col; - size_t ewidth, xwidth; - int spans; - int icol, maxcol, necol, nxcol, quirkcol; + struct tbl_colgroup *first_group, **gp, *g; + size_t *colwidth; + size_t ewidth, min1, min2, wanted, width, xwidth; + int done, icol, maxcol, necol, nxcol, quirkcol; /* * Allocate the master column specifiers. These will hold the @@ -120,33 +130,34 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp, * must be freed and nullified by the caller. */ - assert(NULL == tbl->cols); - tbl->cols = mandoc_calloc((size_t)sp->opts->cols, + assert(tbl->cols == NULL); + tbl->cols = mandoc_calloc((size_t)sp_first->opts->cols, sizeof(struct roffcol)); - opts = sp->opts; + opts = sp_first->opts; - for (maxcol = -1; sp; sp = sp->next) { - if (TBL_SPAN_DATA != sp->pos) + maxcol = -1; + first_group = NULL; + for (sp = sp_first; sp != NULL; sp = sp->next) { + if (sp->pos != TBL_SPAN_DATA) continue; - spans = 1; + /* * Account for the data cells in the layout, matching it * to data cells in the data section. */ - for (dp = sp->first; dp; dp = dp->next) { - /* Do not used spanned cells in the calculation. */ - if (0 < --spans) - continue; - spans = dp->spans; - if (1 < spans) - continue; + + gp = &first_group; + for (dp = sp->first; dp != NULL; dp = dp->next) { icol = dp->layout->col; - while (maxcol < icol) + while (maxcol < icol + dp->hspans) tbl->cols[++maxcol].spacing = SIZE_MAX; col = tbl->cols + icol; col->flags |= dp->layout->flags; if (dp->layout->flags & TBL_CELL_WIGN) continue; + + /* Handle explicit width specifications. */ + if (dp->layout->wstr != NULL && dp->layout->width == 0 && a2roffsu(dp->layout->wstr, &su, SCALE_EN) @@ -159,15 +170,165 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp, (col->spacing == SIZE_MAX || col->spacing < dp->layout->spacing)) col->spacing = dp->layout->spacing; - tblcalc_data(tbl, col, opts, dp, + + /* + * Calculate an automatic width. + * Except for spanning cells, apply it. + */ + + width = tblcalc_data(tbl, + dp->hspans == 0 ? col : NULL, + opts, dp, dp->block == 0 ? 0 : dp->layout->width ? dp->layout->width : rmargin ? (rmargin + sp->opts->cols / 2) / (sp->opts->cols + 1) : 0); + if (dp->hspans == 0) + continue; + + /* + * Build an ordered, singly linked list + * of all groups of columns joined by spans, + * recording the minimum width for each group. + */ + + while (*gp != NULL && ((*gp)->startcol < icol || + (*gp)->endcol < icol + dp->hspans)) + gp = &(*gp)->next; + if (*gp == NULL || (*gp)->startcol > icol || + (*gp)->endcol > icol + dp->hspans) { + g = mandoc_malloc(sizeof(*g)); + g->next = *gp; + g->wanted = width; + g->startcol = icol; + g->endcol = icol + dp->hspans; + *gp = g; + } else if ((*gp)->wanted < width) + (*gp)->wanted = width; + } + } + + /* + * Column spacings are needed for span width calculations, + * so set the default values now. + */ + + for (icol = 0; icol <= maxcol; icol++) + if (tbl->cols[icol].spacing == SIZE_MAX || icol == maxcol) + tbl->cols[icol].spacing = 3; + + /* + * Replace the minimum widths with the missing widths, + * and dismiss groups that are already wide enough. + */ + + gp = &first_group; + while ((g = *gp) != NULL) { + done = 0; + for (icol = g->startcol; icol <= g->endcol; icol++) { + width = tbl->cols[icol].width; + if (icol < g->endcol) + width += tbl->cols[icol].spacing; + if (g->wanted <= width) { + done = 1; + break; + } else + (*gp)->wanted -= width; + } + if (done) { + *gp = g->next; + free(g); + } else + gp = &(*gp)->next; + } + + colwidth = mandoc_reallocarray(NULL, maxcol + 1, sizeof(*colwidth)); + while (first_group != NULL) { + + /* + * Rebuild the array of the widths of all columns + * participating in spans that require expansion. + */ + + for (icol = 0; icol <= maxcol; icol++) + colwidth[icol] = SIZE_MAX; + for (g = first_group; g != NULL; g = g->next) + for (icol = g->startcol; icol <= g->endcol; icol++) + colwidth[icol] = tbl->cols[icol].width; + + /* + * Find the smallest and second smallest column width + * among the columns which may need expamsion. + */ + + min1 = min2 = SIZE_MAX; + for (icol = 0; icol <= maxcol; icol++) { + if (min1 > colwidth[icol]) { + min2 = min1; + min1 = colwidth[icol]; + } else if (min1 < colwidth[icol] && + min2 > colwidth[icol]) + min2 = colwidth[icol]; + } + + /* + * Find the minimum wanted width + * for any one of the narrowest columns, + * and mark the columns wanting that width. + */ + + wanted = min2; + for (g = first_group; g != NULL; g = g->next) { + necol = 0; + for (icol = g->startcol; icol <= g->endcol; icol++) + if (tbl->cols[icol].width == min1) + necol++; + if (necol == 0) + continue; + width = min1 + (g->wanted - 1) / necol + 1; + if (width > min2) + width = min2; + if (wanted > width) + wanted = width; + for (icol = g->startcol; icol <= g->endcol; icol++) + if (colwidth[icol] == min1 || + (colwidth[icol] < min2 && + colwidth[icol] > width)) + colwidth[icol] = width; + } + + /* Record the effect of the widening on the group list. */ + + gp = &first_group; + while ((g = *gp) != NULL) { + done = 0; + for (icol = g->startcol; icol <= g->endcol; icol++) { + if (colwidth[icol] != wanted || + tbl->cols[icol].width == wanted) + continue; + if (g->wanted <= wanted - min1) { + done = 1; + break; + } + g->wanted -= wanted - min1; + } + if (done) { + *gp = g->next; + free(g); + } else + gp = &(*gp)->next; } + + /* Record the effect of the widening on the columns. */ + + for (icol = 0; icol <= maxcol; icol++) + if (colwidth[icol] == wanted) + tbl->cols[icol].width = wanted; } + free(colwidth); /* + * Align numbers with text. * Count columns to equalize and columns to maximize. * Find maximum width of the columns to equalize. * Find total width of the columns *not* to maximize. @@ -177,8 +338,10 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp, ewidth = xwidth = 0; for (icol = 0; icol <= maxcol; icol++) { col = tbl->cols + icol; - if (col->spacing == SIZE_MAX || icol == maxcol) - col->spacing = 3; + if (col->width > col->nwidth) + col->decimal += (col->width - col->nwidth) / 2; + else + col->width = col->nwidth; if (col->flags & TBL_CELL_EQUAL) { necol++; if (ewidth < col->width) @@ -251,7 +414,7 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp, } } -static void +static size_t tblcalc_data(struct rofftbl *tbl, struct roffcol *col, const struct tbl_opts *opts, const struct tbl_dat *dp, size_t mw) { @@ -263,26 +426,24 @@ tblcalc_data(struct rofftbl *tbl, struct roffcol *col, case TBL_CELL_HORIZ: case TBL_CELL_DHORIZ: sz = (*tbl->len)(1, tbl->arg); - if (col->width < sz) + if (col != NULL && col->width < sz) col->width = sz; - break; + return sz; case TBL_CELL_LONG: case TBL_CELL_CENTRE: case TBL_CELL_LEFT: case TBL_CELL_RIGHT: - tblcalc_literal(tbl, col, dp, mw); - break; + return tblcalc_literal(tbl, col, dp, mw); case TBL_CELL_NUMBER: - tblcalc_number(tbl, col, opts, dp); - break; + return tblcalc_number(tbl, col, opts, dp); case TBL_CELL_DOWN: - break; + return 0; default: abort(); } } -static void +static size_t tblcalc_literal(struct rofftbl *tbl, struct roffcol *col, const struct tbl_dat *dp, size_t mw) { @@ -291,11 +452,12 @@ tblcalc_literal(struct rofftbl *tbl, struct roffcol *col, char *end; /* End of the current line. */ size_t lsz; /* Length of the current line. */ size_t wsz; /* Length of the current word. */ + size_t msz; /* Length of the longest line. */ if (dp->string == NULL || *dp->string == '\0') - return; + return 0; str = mw ? mandoc_strdup(dp->string) : dp->string; - lsz = 0; + msz = lsz = 0; for (beg = str; beg != NULL && *beg != '\0'; beg = end) { end = mw ? strchr(beg, ' ') : NULL; if (end != NULL) { @@ -308,62 +470,84 @@ tblcalc_literal(struct rofftbl *tbl, struct roffcol *col, lsz += 1 + wsz; else lsz = wsz; - if (col->width < lsz) - col->width = lsz; + if (msz < lsz) + msz = lsz; } if (mw) free((void *)str); + if (col != NULL && col->width < msz) + col->width = msz; + return msz; } -static void +static size_t tblcalc_number(struct rofftbl *tbl, struct roffcol *col, const struct tbl_opts *opts, const struct tbl_dat *dp) { - int i; - size_t sz, psz, ssz, d; - const char *str; - char *cp; + const char *cp, *lastdigit, *lastpoint; + size_t intsz, totsz; char buf[2]; + if (dp->string == NULL || *dp->string == '\0') + return 0; + + totsz = (*tbl->slen)(dp->string, tbl->arg); + if (col == NULL) + return totsz; + /* - * First calculate number width and decimal place (last + 1 for - * non-decimal numbers). If the stored decimal is subsequent to - * ours, make our size longer by that difference - * (right-"shifting"); similarly, if ours is subsequent the - * stored, then extend the stored size by the difference. - * Finally, re-assign the stored values. + * Find the last digit and + * the last decimal point that is adjacent to a digit. + * The alignment indicator "\&" overrides everything. */ - str = dp->string ? dp->string : ""; - sz = (*tbl->slen)(str, tbl->arg); + lastdigit = lastpoint = NULL; + for (cp = dp->string; cp[0] != '\0'; cp++) { + if (cp[0] == '\\' && cp[1] == '&') { + lastdigit = lastpoint = cp; + break; + } else if (cp[0] == opts->decimal && + (isdigit((unsigned char)cp[1]) || + (cp > dp->string && isdigit((unsigned char)cp[-1])))) + lastpoint = cp; + else if (isdigit((unsigned char)cp[0])) + lastdigit = cp; + } - /* FIXME: TBL_DATA_HORIZ et al.? */ + /* Not a number, treat as a literal string. */ - buf[0] = opts->decimal; - buf[1] = '\0'; + if (lastdigit == NULL) { + if (col != NULL && col->width < totsz) + col->width = totsz; + return totsz; + } - psz = (*tbl->slen)(buf, tbl->arg); + /* Measure the width of the integer part. */ - if (NULL != (cp = strrchr(str, opts->decimal))) { - buf[1] = '\0'; - for (ssz = 0, i = 0; cp != &str[i]; i++) { - buf[0] = str[i]; - ssz += (*tbl->slen)(buf, tbl->arg); - } - d = ssz + psz; - } else - d = sz + psz; + if (lastpoint == NULL) + lastpoint = lastdigit + 1; + intsz = 0; + buf[1] = '\0'; + for (cp = dp->string; cp < lastpoint; cp++) { + buf[0] = cp[0]; + intsz += (*tbl->slen)(buf, tbl->arg); + } - /* Adjust the settings for this column. */ + /* + * If this number has more integer digits than all numbers + * seen on earlier lines, shift them all to the right. + * If it has fewer, shift this number to the right. + */ - if (col->decimal > d) { - sz += col->decimal - d; - d = col->decimal; + if (intsz > col->decimal) { + col->nwidth += intsz - col->decimal; + col->decimal = intsz; } else - col->width += d - col->decimal; + totsz += col->decimal - intsz; + + /* Update the maximum total width seen so far. */ - if (sz > col->width) - col->width = sz; - if (d > col->decimal) - col->decimal = d; + if (totsz > col->nwidth) + col->nwidth = totsz; + return totsz; } diff --git a/usr/src/cmd/mandoc/out.h b/usr/src/cmd/mandoc/out.h index 9f0a541d5d..dec6a8f873 100644 --- a/usr/src/cmd/mandoc/out.h +++ b/usr/src/cmd/mandoc/out.h @@ -1,7 +1,7 @@ -/* $Id: out.h,v 1.32 2018/06/25 16:54:59 schwarze Exp $ */ +/* $Id: out.h,v 1.33 2018/08/18 20:18:14 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011 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 @@ -32,6 +32,7 @@ enum roffscale { struct roffcol { size_t width; /* width of cell */ + size_t nwidth; /* max. width of number in cell */ size_t decimal; /* decimal position in cell */ size_t spacing; /* spacing after the column */ int flags; /* layout flags, see tbl_cell */ diff --git a/usr/src/cmd/mandoc/preconv.c b/usr/src/cmd/mandoc/preconv.c index 08f8df86a6..9ed627d446 100644 --- a/usr/src/cmd/mandoc/preconv.c +++ b/usr/src/cmd/mandoc/preconv.c @@ -1,4 +1,4 @@ -/* $Id: preconv.c,v 1.16 2017/02/18 13:43:52 schwarze Exp $ */ +/* $Id: preconv.c,v 1.17 2018/12/13 11:55:47 schwarze Exp $ */ /* * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org> @@ -22,7 +22,10 @@ #include <assert.h> #include <stdio.h> #include <string.h> + #include "mandoc.h" +#include "roff.h" +#include "mandoc_parse.h" #include "libmandoc.h" int diff --git a/usr/src/cmd/mandoc/read.c b/usr/src/cmd/mandoc/read.c index 0a583445f2..0f25ab967c 100644 --- a/usr/src/cmd/mandoc/read.c +++ b/usr/src/cmd/mandoc/read.c @@ -1,7 +1,7 @@ -/* $Id: read.c,v 1.196 2018/07/28 18:34:15 schwarze Exp $ */ +/* $Id: read.c,v 1.213 2019/06/03 19:58:02 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2010-2018 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2010-2019 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 @@ -38,21 +38,19 @@ #include "roff.h" #include "mdoc.h" #include "man.h" +#include "mandoc_parse.h" #include "libmandoc.h" +#include "roff_int.h" #define REPARSE_LIMIT 1000 struct mparse { struct roff *roff; /* roff parser (!NULL) */ struct roff_man *man; /* man parser */ - char *sodest; /* filename pointed to by .so */ - const char *file; /* filename of current input file */ struct buf *primary; /* buffer currently being parsed */ - struct buf *secondary; /* preprocessed copy of input */ + struct buf *secondary; /* copy of top level input */ + struct buf *loop; /* open .while request line */ const char *os_s; /* default operating system */ - mandocmsg mmsg; /* warning/error message handler */ - enum mandoclevel file_status; /* status of current parse */ - enum mandocerr mmin; /* ignore messages below this */ int options; /* parser options */ int gzip; /* current input file is gzipped */ int filenc; /* encoding of the current file */ @@ -61,220 +59,11 @@ struct mparse { }; static void choose_parser(struct mparse *); +static void free_buf_list(struct buf *); static void resize_buf(struct buf *, size_t); static int mparse_buf_r(struct mparse *, struct buf, size_t, int); -static int read_whole_file(struct mparse *, const char *, int, - struct buf *, int *); +static int read_whole_file(struct mparse *, int, struct buf *, int *); static void mparse_end(struct mparse *); -static void mparse_parse_buffer(struct mparse *, struct buf, - const char *); - -static const enum mandocerr mandoclimits[MANDOCLEVEL_MAX] = { - MANDOCERR_OK, - MANDOCERR_OK, - MANDOCERR_WARNING, - MANDOCERR_ERROR, - MANDOCERR_UNSUPP, - MANDOCERR_MAX, - MANDOCERR_MAX -}; - -static const char * const mandocerrs[MANDOCERR_MAX] = { - "ok", - - "base system convention", - - "Mdocdate found", - "Mdocdate missing", - "unknown architecture", - "operating system explicitly specified", - "RCS id missing", - "referenced manual not found", - - "generic style suggestion", - - "legacy man(7) date format", - "normalizing date format to", - "lower case character in document title", - "duplicate RCS id", - "possible typo in section name", - "unterminated quoted argument", - "useless macro", - "consider using OS macro", - "errnos out of order", - "duplicate errno", - "trailing delimiter", - "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", - - "generic warning", - - /* related to the prologue */ - "missing manual title, using UNTITLED", - "missing manual title, using \"\"", - "missing manual section, using \"\"", - "unknown manual section", - "missing date, using today's date", - "cannot parse date, using it verbatim", - "date in the future, using it anyway", - "missing Os macro, using \"\"", - "late prologue macro", - "prologue macros out of order", - - /* related to document structure */ - ".so is fragile, better use ln(1)", - "no document body", - "content before first section header", - "first section is not \"NAME\"", - "NAME section without Nm before Nd", - "NAME section without description", - "description not at the end of NAME", - "bad NAME section content", - "missing comma before name", - "missing description line, using \"\"", - "description line outside NAME section", - "sections out of conventional order", - "duplicate section title", - "unexpected section", - "cross reference to self", - "unusual Xr order", - "unusual Xr punctuation", - "AUTHORS section without An macro", - - /* related to macros and nesting */ - "obsolete macro", - "macro neither callable nor escaped", - "skipping paragraph macro", - "moving paragraph macro out of list", - "skipping no-space macro", - "blocks badly nested", - "nested displays are not portable", - "moving content out of list", - "first macro on line", - "line scope broken", - "skipping blank line in line scope", - - /* related to missing macro arguments */ - "skipping empty request", - "conditional request controls empty scope", - "skipping empty macro", - "empty block", - "empty argument, using 0n", - "missing display type, using -ragged", - "list type is not the first argument", - "missing -width in -tag list, using 6n", - "missing utility name, using \"\"", - "missing function name, using \"\"", - "empty head in list item", - "empty list item", - "missing argument, using next line", - "missing font type, using \\fR", - "unknown font type, using \\fR", - "nothing follows prefix", - "empty reference block", - "missing section argument", - "missing -std argument, adding it", - "missing option string, using \"\"", - "missing resource identifier, using \"\"", - "missing eqn box, using \"\"", - - /* related to bad macro arguments */ - "duplicate argument", - "skipping duplicate argument", - "skipping duplicate display type", - "skipping duplicate list type", - "skipping -width argument", - "wrong number of cells", - "unknown AT&T UNIX version", - "comma in function argument", - "parenthesis in function name", - "unknown library name", - "invalid content in Rs block", - "invalid Boolean argument", - "unknown font, skipping request", - "odd number of characters in request", - - /* related to plain text */ - "blank line in fill mode, using .sp", - "tab in filled text", - "new sentence, new line", - "invalid escape sequence", - "undefined string, using \"\"", - - /* related to tables */ - "tbl line starts with span", - "tbl column starts with span", - "skipping vertical bar in tbl layout", - - "generic error", - - /* related to tables */ - "non-alphabetic character in tbl options", - "skipping unknown tbl option", - "missing tbl option argument", - "wrong tbl option argument size", - "empty tbl layout", - "invalid character in tbl layout", - "unmatched parenthesis in tbl layout", - "tbl without any data cells", - "ignoring data in spanned tbl cell", - "ignoring extra tbl data cells", - "data block open at end of tbl", - - /* related to document structure and macros */ - NULL, - "duplicate prologue macro", - "skipping late title macro", - "input stack limit exceeded, infinite loop?", - "skipping bad character", - "skipping unknown macro", - "skipping insecure request", - "skipping item outside list", - "skipping column outside column list", - "skipping end of block that is not open", - "fewer RS blocks open, skipping", - "inserting missing end of block", - "appending missing end of block", - - /* related to request and macro arguments */ - "escaped character not allowed in a name", - "NOT IMPLEMENTED: Bd -file", - "skipping display without arguments", - "missing list type, using -item", - "argument is not numeric, using 1", - "missing manual name, using \"\"", - "uname(3) system call failed, using UNKNOWN", - "unknown standard specifier", - "skipping request without numeric argument", - "NOT IMPLEMENTED: .so with absolute path or \"..\"", - ".so request failed", - "skipping all arguments", - "skipping excess arguments", - "divide by zero", - - "unsupported feature", - "input too large", - "unsupported control character", - "unsupported roff request", - "eqn delim option in tbl", - "unsupported tbl layout modifier", - "ignoring macro in table", -}; - -static const char * const mandoclevels[MANDOCLEVEL_MAX] = { - "SUCCESS", - "STYLE", - "WARNING", - "ERROR", - "UNSUPP", - "BADARG", - "SYSERR" -}; static void @@ -286,6 +75,19 @@ resize_buf(struct buf *buf, size_t initial) } static void +free_buf_list(struct buf *buf) +{ + struct buf *tmp; + + while (buf != NULL) { + tmp = buf; + buf = tmp->next; + free(tmp->buf); + free(tmp); + } +} + +static void choose_parser(struct mparse *curp) { char *cp, *ep; @@ -320,15 +122,15 @@ choose_parser(struct mparse *curp) } if (format == MPARSE_MDOC) { - curp->man->macroset = MACROSET_MDOC; + curp->man->meta.macroset = MACROSET_MDOC; if (curp->man->mdocmac == NULL) curp->man->mdocmac = roffhash_alloc(MDOC_Dd, MDOC_MAX); } else { - curp->man->macroset = MACROSET_MAN; + curp->man->meta.macroset = MACROSET_MAN; if (curp->man->manmac == NULL) curp->man->manmac = roffhash_alloc(MAN_TH, MAN_MAX); } - curp->man->first->tok = TOKEN_NONE; + curp->man->meta.first->tok = TOKEN_NONE; } /* @@ -342,24 +144,26 @@ static int mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start) { struct buf ln; - const char *save_file; + struct buf *firstln, *lastln, *thisln, *loop; char *cp; size_t pos; /* byte number in the ln buffer */ - enum rofferr rr; + int line_result, result; int of; int lnn; /* line number in the real file */ int fd; + int inloop; /* Saw .while on this level. */ unsigned char c; - memset(&ln, 0, sizeof(ln)); - + ln.sz = 256; + ln.buf = mandoc_malloc(ln.sz); + ln.next = NULL; + firstln = lastln = loop = NULL; lnn = curp->line; pos = 0; + inloop = 0; + result = ROFF_CONT; - while (i < blk.sz) { - if (0 == pos && '\0' == blk.buf[i]) - break; - + while (i < blk.sz && (blk.buf[i] != '\0' || pos != 0)) { if (start) { curp->line = lnn; curp->reparse_count = 0; @@ -389,10 +193,10 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start) /* * Make sure we have space for the worst - * case of 11 bytes: "\\[u10ffff]\0" + * case of 12 bytes: "\\[u10ffff]\n\0" */ - if (pos + 11 > ln.sz) + if (pos + 12 > ln.sz) resize_buf(&ln, 256); /* @@ -403,7 +207,7 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start) if (c & 0x80) { if ( ! (curp->filenc && preconv_encode( &blk, &i, &ln, &pos, &curp->filenc))) { - mandoc_vmsg(MANDOCERR_CHAR_BAD, curp, + mandoc_msg(MANDOCERR_CHAR_BAD, curp->line, pos, "0x%x", c); ln.buf[pos++] = '?'; i++; @@ -416,10 +220,10 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start) */ if (c == 0x7f || (c < 0x20 && c != 0x09)) { - mandoc_vmsg(c == 0x00 || c == 0x04 || + mandoc_msg(c == 0x00 || c == 0x04 || c > 0x0a ? MANDOCERR_CHAR_BAD : MANDOCERR_CHAR_UNSUPP, - curp, curp->line, pos, "0x%x", c); + curp->line, pos, "0x%x", c); i++; if (c != '\r') ln.buf[pos++] = '?'; @@ -428,13 +232,32 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start) ln.buf[pos++] = blk.buf[i++]; } + ln.buf[pos] = '\0'; - if (pos + 1 >= ln.sz) - resize_buf(&ln, 256); + /* + * Maintain a lookaside buffer of all lines. + * parsed from this input source. + */ + + thisln = mandoc_malloc(sizeof(*thisln)); + thisln->buf = mandoc_strdup(ln.buf); + thisln->sz = strlen(ln.buf) + 1; + thisln->next = NULL; + if (firstln == NULL) { + firstln = lastln = thisln; + if (curp->secondary == NULL) + curp->secondary = firstln; + } else { + lastln->next = thisln; + lastln = thisln; + } - if (i == blk.sz || blk.buf[i] == '\0') + /* XXX Ugly hack to mark the end of the input. */ + + if (i == blk.sz || blk.buf[i] == '\0') { ln.buf[pos++] = '\n'; - ln.buf[pos] = '\0'; + ln.buf[pos] = '\0'; + } /* * A significant amount of complexity is contained by @@ -446,74 +269,112 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start) */ of = 0; +rerun: + line_result = roff_parseln(curp->roff, curp->line, &ln, &of); - /* - * Maintain a lookaside buffer of all parsed lines. We - * only do this if mparse_keep() has been invoked (the - * buffer may be accessed with mparse_getkeep()). - */ + /* Process options. */ + + if (line_result & ROFF_APPEND) + assert(line_result == (ROFF_IGN | ROFF_APPEND)); - if (curp->secondary) { - curp->secondary->buf = mandoc_realloc( - curp->secondary->buf, - curp->secondary->sz + pos + 2); - memcpy(curp->secondary->buf + - curp->secondary->sz, - ln.buf, pos); - curp->secondary->sz += pos; - curp->secondary->buf - [curp->secondary->sz] = '\n'; - curp->secondary->sz++; - curp->secondary->buf - [curp->secondary->sz] = '\0'; + if (line_result & ROFF_USERCALL) + assert((line_result & ROFF_MASK) == ROFF_REPARSE); + + if (line_result & ROFF_USERRET) { + assert(line_result == (ROFF_IGN | ROFF_USERRET)); + if (start == 0) { + /* Return from the current macro. */ + result = ROFF_USERRET; + goto out; + } } -rerun: - rr = roff_parseln(curp->roff, curp->line, &ln, &of); - switch (rr) { - case ROFF_REPARSE: - if (++curp->reparse_count > REPARSE_LIMIT) - mandoc_msg(MANDOCERR_ROFFLOOP, curp, + switch (line_result & ROFF_LOOPMASK) { + case ROFF_IGN: + break; + case ROFF_WHILE: + if (curp->loop != NULL) { + if (loop == curp->loop) + break; + mandoc_msg(MANDOCERR_WHILE_NEST, curp->line, pos, NULL); - else if (mparse_buf_r(curp, ln, of, 0) == 1 || - start == 1) { - pos = 0; - continue; } - free(ln.buf); - return 0; - case ROFF_APPEND: - pos = strlen(ln.buf); - continue; + curp->loop = thisln; + loop = NULL; + inloop = 1; + break; + case ROFF_LOOPCONT: + case ROFF_LOOPEXIT: + if (curp->loop == NULL) { + mandoc_msg(MANDOCERR_WHILE_FAIL, + curp->line, pos, NULL); + break; + } + if (inloop == 0) { + mandoc_msg(MANDOCERR_WHILE_INTO, + curp->line, pos, NULL); + curp->loop = loop = NULL; + break; + } + if (line_result & ROFF_LOOPCONT) + loop = curp->loop; + else { + curp->loop = loop = NULL; + inloop = 0; + } + break; + default: + abort(); + } + + /* Process the main instruction from the roff parser. */ + + switch (line_result & ROFF_MASK) { + case ROFF_IGN: + break; + case ROFF_CONT: + if (curp->man->meta.macroset == MACROSET_NONE) + choose_parser(curp); + if ((curp->man->meta.macroset == MACROSET_MDOC ? + mdoc_parseln(curp->man, curp->line, ln.buf, of) : + man_parseln(curp->man, curp->line, ln.buf, of) + ) == 2) + goto out; + break; case ROFF_RERUN: goto rerun; - case ROFF_IGN: - pos = 0; - continue; + case ROFF_REPARSE: + if (++curp->reparse_count > REPARSE_LIMIT) { + /* Abort and return to the top level. */ + result = ROFF_IGN; + mandoc_msg(MANDOCERR_ROFFLOOP, + curp->line, pos, NULL); + goto out; + } + result = mparse_buf_r(curp, ln, of, 0); + if (line_result & ROFF_USERCALL) { + roff_userret(curp->roff); + /* Continue normally. */ + if (result & ROFF_USERRET) + result = ROFF_CONT; + } + if (start == 0 && result != ROFF_CONT) + goto out; + break; case ROFF_SO: if ( ! (curp->options & MPARSE_SO) && (i >= blk.sz || blk.buf[i] == '\0')) { - curp->sodest = mandoc_strdup(ln.buf + of); - free(ln.buf); - return 1; + curp->man->meta.sodest = + mandoc_strdup(ln.buf + of); + goto out; } - /* - * We remove `so' clauses from our lookaside - * buffer because we're going to descend into - * the file recursively. - */ - if (curp->secondary) - curp->secondary->sz -= pos + 1; - save_file = curp->file; if ((fd = mparse_open(curp, ln.buf + of)) != -1) { mparse_readfd(curp, fd, ln.buf + of); close(fd); - curp->file = save_file; } else { - curp->file = save_file; - mandoc_vmsg(MANDOCERR_SO_FAIL, - curp, curp->line, pos, - ".so %s", ln.buf + of); + mandoc_msg(MANDOCERR_SO_FAIL, + curp->line, of, ".so %s: %s", + ln.buf + of, strerror(errno)); ln.sz = mandoc_asprintf(&cp, ".sp\nSee the file %s.\n.sp", ln.buf + of); @@ -522,37 +383,44 @@ rerun: of = 0; mparse_buf_r(curp, ln, of, 0); } - pos = 0; - continue; - default: break; + default: + abort(); } - if (curp->man->macroset == MACROSET_NONE) - choose_parser(curp); - - if ((curp->man->macroset == MACROSET_MDOC ? - mdoc_parseln(curp->man, curp->line, ln.buf, of) : - man_parseln(curp->man, curp->line, ln.buf, of)) == 2) - break; - - /* Temporary buffers typically are not full. */ - - if (0 == start && '\0' == blk.buf[i]) - break; - /* Start the next input line. */ - pos = 0; - } + if (loop != NULL && + (line_result & ROFF_LOOPMASK) == ROFF_IGN) + loop = loop->next; + + if (loop != NULL) { + if ((line_result & ROFF_APPEND) == 0) + *ln.buf = '\0'; + if (ln.sz < loop->sz) + resize_buf(&ln, loop->sz); + (void)strlcat(ln.buf, loop->buf, ln.sz); + of = 0; + goto rerun; + } + pos = (line_result & ROFF_APPEND) ? strlen(ln.buf) : 0; + } +out: + if (inloop) { + if (result != ROFF_USERRET) + mandoc_msg(MANDOCERR_WHILE_OUTOF, + curp->line, pos, NULL); + curp->loop = NULL; + } free(ln.buf); - return 1; + if (firstln != curp->secondary) + free_buf_list(firstln); + return result; } static int -read_whole_file(struct mparse *curp, const char *file, int fd, - struct buf *fb, int *with_mmap) +read_whole_file(struct mparse *curp, int fd, struct buf *fb, int *with_mmap) { struct stat st; gzFile gz; @@ -561,7 +429,7 @@ read_whole_file(struct mparse *curp, const char *file, int fd, int gzerrnum, retval; if (fstat(fd, &st) == -1) { - mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0, + mandoc_msg(MANDOCERR_FILE, 0, 0, "fstat: %s", strerror(errno)); return 0; } @@ -575,7 +443,7 @@ read_whole_file(struct mparse *curp, const char *file, int fd, if (curp->gzip == 0 && S_ISREG(st.st_mode)) { if (st.st_size > 0x7fffffff) { - mandoc_msg(MANDOCERR_TOOLARGE, curp, 0, 0, NULL); + mandoc_msg(MANDOCERR_TOOLARGE, 0, 0, NULL); return 0; } *with_mmap = 1; @@ -594,12 +462,12 @@ read_whole_file(struct mparse *curp, const char *file, int fd, * which this function must not do. */ if ((fd = dup(fd)) == -1) { - mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0, + mandoc_msg(MANDOCERR_FILE, 0, 0, "dup: %s", strerror(errno)); return 0; } if ((gz = gzdopen(fd, "rb")) == NULL) { - mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0, + mandoc_msg(MANDOCERR_FILE, 0, 0, "gzdopen: %s", strerror(errno)); close(fd); return 0; @@ -620,8 +488,7 @@ read_whole_file(struct mparse *curp, const char *file, int fd, for (;;) { if (off == fb->sz) { if (fb->sz == (1U << 31)) { - mandoc_msg(MANDOCERR_TOOLARGE, curp, - 0, 0, NULL); + mandoc_msg(MANDOCERR_TOOLARGE, 0, 0, NULL); break; } resize_buf(fb, 65536); @@ -637,7 +504,7 @@ read_whole_file(struct mparse *curp, const char *file, int fd, if (ssz == -1) { if (curp->gzip) (void)gzerror(gz, &gzerrnum); - mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0, "read: %s", + mandoc_msg(MANDOCERR_FILE, 0, 0, "read: %s", curp->gzip && gzerrnum != Z_ERRNO ? zError(gzerrnum) : strerror(errno)); break; @@ -646,7 +513,7 @@ read_whole_file(struct mparse *curp, const char *file, int fd, } if (curp->gzip && (gzerrnum = gzclose(gz)) != Z_OK) - mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0, "gzclose: %s", + mandoc_msg(MANDOCERR_FILE, 0, 0, "gzclose: %s", gzerrnum == Z_ERRNO ? strerror(errno) : zError(gzerrnum)); if (retval == 0) { @@ -659,35 +526,51 @@ read_whole_file(struct mparse *curp, const char *file, int fd, static void mparse_end(struct mparse *curp) { - if (curp->man->macroset == MACROSET_NONE) - curp->man->macroset = MACROSET_MAN; - if (curp->man->macroset == MACROSET_MDOC) + if (curp->man->meta.macroset == MACROSET_NONE) + curp->man->meta.macroset = MACROSET_MAN; + if (curp->man->meta.macroset == MACROSET_MDOC) mdoc_endparse(curp->man); else man_endparse(curp->man); roff_endparse(curp->roff); } -static void -mparse_parse_buffer(struct mparse *curp, struct buf blk, const char *file) +/* + * Read the whole file into memory and call the parsers. + * Called recursively when an .so request is encountered. + */ +void +mparse_readfd(struct mparse *curp, int fd, const char *filename) { - struct buf *svprimary; - const char *svfile; - size_t offset; static int recursion_depth; - if (64 < recursion_depth) { - mandoc_msg(MANDOCERR_ROFFLOOP, curp, curp->line, 0, NULL); + struct buf blk; + struct buf *save_primary; + const char *save_filename; + size_t offset; + int save_filenc, save_lineno; + int with_mmap; + + if (recursion_depth > 64) { + mandoc_msg(MANDOCERR_ROFFLOOP, curp->line, 0, NULL); return; } + if (read_whole_file(curp, fd, &blk, &with_mmap) == 0) + return; + + /* + * Save some properties of the parent file. + */ + + save_primary = curp->primary; + save_filenc = curp->filenc; + save_lineno = curp->line; + save_filename = mandoc_msg_getinfilename(); - /* Line number is per-file. */ - svfile = curp->file; - curp->file = file; - svprimary = curp->primary; curp->primary = &blk; + curp->filenc = curp->options & (MPARSE_UTF8 | MPARSE_LATIN1); curp->line = 1; - recursion_depth++; + mandoc_msg_setinfilename(filename); /* Skip an UTF-8 byte order mark. */ if (curp->filenc & MPARSE_UTF8 && blk.sz > 2 && @@ -699,60 +582,33 @@ mparse_parse_buffer(struct mparse *curp, struct buf blk, const char *file) } else offset = 0; + recursion_depth++; mparse_buf_r(curp, blk, offset, 1); - if (--recursion_depth == 0) mparse_end(curp); - curp->primary = svprimary; - curp->file = svfile; -} - -enum mandoclevel -mparse_readmem(struct mparse *curp, void *buf, size_t len, - const char *file) -{ - struct buf blk; - - blk.buf = buf; - blk.sz = len; + /* + * Clean up and restore saved parent properties. + */ - mparse_parse_buffer(curp, blk, file); - return curp->file_status; -} + if (with_mmap) + munmap(blk.buf, blk.sz); + else + free(blk.buf); -/* - * Read the whole file into memory and call the parsers. - * Called recursively when an .so request is encountered. - */ -enum mandoclevel -mparse_readfd(struct mparse *curp, int fd, const char *file) -{ - struct buf blk; - int with_mmap; - int save_filenc; - - if (read_whole_file(curp, file, fd, &blk, &with_mmap)) { - save_filenc = curp->filenc; - curp->filenc = curp->options & - (MPARSE_UTF8 | MPARSE_LATIN1); - mparse_parse_buffer(curp, blk, file); - curp->filenc = save_filenc; - if (with_mmap) - munmap(blk.buf, blk.sz); - else - free(blk.buf); - } - return curp->file_status; + curp->primary = save_primary; + curp->filenc = save_filenc; + curp->line = save_lineno; + if (save_filename != NULL) + mandoc_msg_setinfilename(save_filename); } int mparse_open(struct mparse *curp, const char *file) { char *cp; - int fd; + int fd, save_errno; - curp->file = file; cp = strrchr(file, '.'); curp->gzip = (cp != NULL && ! strcmp(cp + 1, "gz")); @@ -767,9 +623,11 @@ mparse_open(struct mparse *curp, const char *file) */ if ( ! curp->gzip) { + save_errno = errno; mandoc_asprintf(&cp, "%s.gz", file); fd = open(cp, O_RDONLY); free(cp); + errno = save_errno; if (fd != -1) { curp->gzip = 1; return fd; @@ -778,36 +636,32 @@ mparse_open(struct mparse *curp, const char *file) /* Neither worked, give up. */ - mandoc_msg(MANDOCERR_FILE, curp, 0, 0, strerror(errno)); return -1; } struct mparse * -mparse_alloc(int options, enum mandocerr mmin, mandocmsg mmsg, - enum mandoc_os os_e, const char *os_s) +mparse_alloc(int options, enum mandoc_os os_e, const char *os_s) { struct mparse *curp; curp = mandoc_calloc(1, sizeof(struct mparse)); curp->options = options; - curp->mmin = mmin; - curp->mmsg = mmsg; curp->os_s = os_s; - curp->roff = roff_alloc(curp, options); - curp->man = roff_man_alloc(curp->roff, curp, curp->os_s, + curp->roff = roff_alloc(options); + curp->man = roff_man_alloc(curp->roff, curp->os_s, curp->options & MPARSE_QUICK ? 1 : 0); if (curp->options & MPARSE_MDOC) { - curp->man->macroset = MACROSET_MDOC; + curp->man->meta.macroset = MACROSET_MDOC; if (curp->man->mdocmac == NULL) curp->man->mdocmac = roffhash_alloc(MDOC_Dd, MDOC_MAX); } else if (curp->options & MPARSE_MAN) { - curp->man->macroset = MACROSET_MAN; + curp->man->meta.macroset = MACROSET_MAN; if (curp->man->manmac == NULL) curp->man->manmac = roffhash_alloc(MAN_TH, MAN_MAX); } - curp->man->first->tok = TOKEN_NONE; + curp->man->meta.first->tok = TOKEN_NONE; curp->man->meta.os_e = os_e; return curp; } @@ -817,112 +671,40 @@ mparse_reset(struct mparse *curp) { roff_reset(curp->roff); roff_man_reset(curp->man); - - free(curp->sodest); - curp->sodest = NULL; - - if (curp->secondary) - curp->secondary->sz = 0; - - curp->file_status = MANDOCLEVEL_OK; + free_buf_list(curp->secondary); + curp->secondary = NULL; curp->gzip = 0; } void mparse_free(struct mparse *curp) { - roffhash_free(curp->man->mdocmac); roffhash_free(curp->man->manmac); roff_man_free(curp->man); roff_free(curp->roff); - if (curp->secondary) - free(curp->secondary->buf); - - free(curp->secondary); - free(curp->sodest); + free_buf_list(curp->secondary); free(curp); } -void -mparse_result(struct mparse *curp, struct roff_man **man, - char **sodest) +struct roff_meta * +mparse_result(struct mparse *curp) { - - if (sodest && NULL != (*sodest = curp->sodest)) { - *man = NULL; - return; + roff_state_reset(curp->man); + if (curp->options & MPARSE_VALIDATE) { + if (curp->man->meta.macroset == MACROSET_MDOC) + mdoc_validate(curp->man); + else + man_validate(curp->man); } - if (man) - *man = curp->man; + return &curp->man->meta; } void -mparse_updaterc(struct mparse *curp, enum mandoclevel *rc) -{ - if (curp->file_status > *rc) - *rc = curp->file_status; -} - -void -mandoc_vmsg(enum mandocerr t, struct mparse *m, - int ln, int pos, const char *fmt, ...) -{ - char buf[256]; - va_list ap; - - va_start(ap, fmt); - (void)vsnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - - mandoc_msg(t, m, ln, pos, buf); -} - -void -mandoc_msg(enum mandocerr er, struct mparse *m, - int ln, int col, const char *msg) -{ - enum mandoclevel level; - - if (er < m->mmin && er != MANDOCERR_FILE) - return; - - level = MANDOCLEVEL_UNSUPP; - while (er < mandoclimits[level]) - level--; - - if (m->mmsg) - (*m->mmsg)(er, level, m->file, ln, col, msg); - - if (m->file_status < level) - m->file_status = level; -} - -const char * -mparse_strerror(enum mandocerr er) -{ - - return mandocerrs[er]; -} - -const char * -mparse_strlevel(enum mandoclevel lvl) -{ - return mandoclevels[lvl]; -} - -void -mparse_keep(struct mparse *p) -{ - - assert(NULL == p->secondary); - p->secondary = mandoc_calloc(1, sizeof(struct buf)); -} - -const char * -mparse_getkeep(const struct mparse *p) +mparse_copy(const struct mparse *p) { + struct buf *buf; - assert(p->secondary); - return p->secondary->sz ? p->secondary->buf : NULL; + for (buf = p->secondary; buf != NULL; buf = buf->next) + puts(buf->buf); } diff --git a/usr/src/cmd/mandoc/roff.c b/usr/src/cmd/mandoc/roff.c index 86e145e366..e84295aac3 100644 --- a/usr/src/cmd/mandoc/roff.c +++ b/usr/src/cmd/mandoc/roff.c @@ -1,7 +1,7 @@ -/* $Id: roff.c,v 1.329 2018/08/01 15:40:17 schwarze Exp $ */ +/* $Id: roff.c,v 1.363 2019/02/06 21:11:43 schwarze Exp $ */ /* * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2010-2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2010-2015, 2017-2019 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 @@ -28,13 +28,23 @@ #include <stdlib.h> #include <string.h> -#include "mandoc.h" #include "mandoc_aux.h" #include "mandoc_ohash.h" +#include "mandoc.h" #include "roff.h" +#include "mandoc_parse.h" #include "libmandoc.h" #include "roff_int.h" -#include "libroff.h" +#include "tbl_parse.h" +#include "eqn_parse.h" + +/* + * ASCII_ESC is used to signal from roff_getarg() to roff_expand() + * that an escape sequence resulted from copy-in processing and + * needs to be checked or interpolated. As it is used nowhere + * else, it is defined here rather than in a header file. + */ +#define ASCII_ESC 27 /* Maximum number of string expansions per line, to break infinite loops. */ #define EXPAND_LIMIT 1000 @@ -85,10 +95,20 @@ struct roffreq { char name[]; }; +/* + * A macro processing context. + * More than one is needed when macro calls are nested. + */ +struct mctx { + char **argv; + int argc; + int argsz; +}; + struct roff { - struct mparse *parse; /* parse point */ struct roff_man *man; /* mdoc or man parser */ struct roffnode *last; /* leaf of stack */ + struct mctx *mstack; /* stack of macro contexts */ int *rstack; /* stack of inverted `ie' values */ struct ohash *reqtab; /* request lookup table */ struct roffreg *regtab; /* number registers */ @@ -104,10 +124,11 @@ struct roff { struct eqn_node *eqn; /* active equation parser */ int eqn_inline; /* current equation is inline */ int options; /* parse options */ + int mstacksz; /* current size of mstack */ + int mstackpos; /* position in mstack */ int rstacksz; /* current size limit of rstack */ int rstackpos; /* position in rstack */ int format; /* current file in mdoc or man format */ - int argc; /* number of args of the last macro */ char control; /* control character */ char escape; /* escape character */ }; @@ -131,7 +152,7 @@ struct roffnode { int pos, /* current pos in buffer */ \ int *offs /* reset offset of buffer data */ -typedef enum rofferr (*roffproc)(ROFF_ARGS); +typedef int (*roffproc)(ROFF_ARGS); struct roffmac { roffproc proc; /* process new macro */ @@ -151,32 +172,34 @@ struct predef { /* --- function prototypes ------------------------------------------------ */ -static void roffnode_cleanscope(struct roff *); -static void roffnode_pop(struct roff *); +static int roffnode_cleanscope(struct roff *); +static int roffnode_pop(struct roff *); static void roffnode_push(struct roff *, enum roff_tok, const char *, int, int); -static void roff_addtbl(struct roff_man *, struct tbl_node *); -static enum rofferr roff_als(ROFF_ARGS); -static enum rofferr roff_block(ROFF_ARGS); -static enum rofferr roff_block_text(ROFF_ARGS); -static enum rofferr roff_block_sub(ROFF_ARGS); -static enum rofferr roff_br(ROFF_ARGS); -static enum rofferr roff_cblock(ROFF_ARGS); -static enum rofferr roff_cc(ROFF_ARGS); -static void roff_ccond(struct roff *, int, int); -static enum rofferr roff_cond(ROFF_ARGS); -static enum rofferr roff_cond_text(ROFF_ARGS); -static enum rofferr roff_cond_sub(ROFF_ARGS); -static enum rofferr roff_ds(ROFF_ARGS); -static enum rofferr roff_ec(ROFF_ARGS); -static enum rofferr roff_eo(ROFF_ARGS); -static enum rofferr roff_eqndelim(struct roff *, struct buf *, int); +static void roff_addtbl(struct roff_man *, int, struct tbl_node *); +static int roff_als(ROFF_ARGS); +static int roff_block(ROFF_ARGS); +static int roff_block_text(ROFF_ARGS); +static int roff_block_sub(ROFF_ARGS); +static int roff_cblock(ROFF_ARGS); +static int roff_cc(ROFF_ARGS); +static int roff_ccond(struct roff *, int, int); +static int roff_char(ROFF_ARGS); +static int roff_cond(ROFF_ARGS); +static int roff_cond_text(ROFF_ARGS); +static int roff_cond_sub(ROFF_ARGS); +static int roff_ds(ROFF_ARGS); +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 *r, 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_evalstrcond(const char *, int *); +static int roff_expand(struct roff *, struct buf *, + int, int, char); static void roff_free1(struct roff *); static void roff_freereg(struct roffreg *); static void roff_freestr(struct roffkv *); @@ -191,39 +214,42 @@ static const char *roff_getstrn(struct roff *, const char *, size_t, int *); static int roff_hasregn(const struct roff *, const char *, size_t); -static enum rofferr roff_insec(ROFF_ARGS); -static enum rofferr roff_it(ROFF_ARGS); -static enum rofferr roff_line_ignore(ROFF_ARGS); +static int roff_insec(ROFF_ARGS); +static int roff_it(ROFF_ARGS); +static int roff_line_ignore(ROFF_ARGS); static void roff_man_alloc1(struct roff_man *); static void roff_man_free1(struct roff_man *); -static enum rofferr roff_manyarg(ROFF_ARGS); -static enum rofferr roff_nr(ROFF_ARGS); -static enum rofferr roff_onearg(ROFF_ARGS); +static int roff_manyarg(ROFF_ARGS); +static int roff_noarg(ROFF_ARGS); +static int roff_nop(ROFF_ARGS); +static int roff_nr(ROFF_ARGS); +static int roff_onearg(ROFF_ARGS); static enum roff_tok roff_parse(struct roff *, char *, int *, int, int); -static enum rofferr roff_parsetext(struct roff *, struct buf *, +static int roff_parsetext(struct roff *, struct buf *, int, int *); -static enum rofferr roff_renamed(ROFF_ARGS); -static enum rofferr roff_res(struct roff *, struct buf *, int, int); -static enum rofferr roff_rm(ROFF_ARGS); -static enum rofferr roff_rn(ROFF_ARGS); -static enum rofferr roff_rr(ROFF_ARGS); +static int roff_renamed(ROFF_ARGS); +static int roff_return(ROFF_ARGS); +static int roff_rm(ROFF_ARGS); +static int roff_rn(ROFF_ARGS); +static int 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 *, size_t, const char *, size_t, int); -static enum rofferr roff_so(ROFF_ARGS); -static enum rofferr roff_tr(ROFF_ARGS); -static enum rofferr roff_Dd(ROFF_ARGS); -static enum rofferr roff_TE(ROFF_ARGS); -static enum rofferr roff_TS(ROFF_ARGS); -static enum rofferr roff_EQ(ROFF_ARGS); -static enum rofferr roff_EN(ROFF_ARGS); -static enum rofferr roff_T_(ROFF_ARGS); -static enum rofferr roff_unsupp(ROFF_ARGS); -static enum rofferr roff_userdef(ROFF_ARGS); +static int roff_shift(ROFF_ARGS); +static int roff_so(ROFF_ARGS); +static int roff_tr(ROFF_ARGS); +static int roff_Dd(ROFF_ARGS); +static int roff_TE(ROFF_ARGS); +static int roff_TS(ROFF_ARGS); +static int roff_EQ(ROFF_ARGS); +static int roff_EN(ROFF_ARGS); +static int roff_T_(ROFF_ARGS); +static int roff_unsupp(ROFF_ARGS); +static int roff_userdef(ROFF_ARGS); /* --- constant data ------------------------------------------------------ */ @@ -231,8 +257,9 @@ static enum rofferr roff_userdef(ROFF_ARGS); #define ROFFNUM_WHITE (1 << 1) /* Skip whitespace in roff_evalnum(). */ const char *__roff_name[MAN_MAX + 1] = { - "br", "ce", "ft", "ll", - "mc", "po", "rj", "sp", + "br", "ce", "fi", "ft", + "ll", "mc", "nf", + "po", "rj", "sp", "ta", "ti", NULL, "ab", "ad", "af", "aln", "als", "am", "am1", "ami", @@ -326,24 +353,27 @@ const char *__roff_name[MAN_MAX + 1] = { "Dx", "%Q", "%U", "Ta", NULL, "TH", "SH", "SS", "TP", + "TQ", "LP", "PP", "P", "IP", "HP", "SM", "SB", "BI", "IB", "BR", "RB", "R", "B", "I", "IR", "RI", - "nf", "fi", "RE", "RS", "DT", "UC", "PD", "AT", "in", - "OP", "EX", "EE", "UR", + "SY", "YS", "OP", + "EX", "EE", "UR", "UE", "MT", "ME", NULL }; const char *const *roff_name = __roff_name; static struct roffmac roffs[TOKEN_NONE] = { - { roff_br, NULL, NULL, 0 }, /* br */ + { roff_noarg, NULL, NULL, 0 }, /* br */ { roff_onearg, NULL, NULL, 0 }, /* ce */ + { roff_noarg, NULL, NULL, 0 }, /* fi */ { roff_onearg, NULL, NULL, 0 }, /* ft */ { roff_onearg, NULL, NULL, 0 }, /* ll */ { roff_onearg, NULL, NULL, 0 }, /* mc */ + { roff_noarg, NULL, NULL, 0 }, /* nf */ { roff_onearg, NULL, NULL, 0 }, /* po */ { roff_onearg, NULL, NULL, 0 }, /* rj */ { roff_onearg, NULL, NULL, 0 }, /* sp */ @@ -373,14 +403,14 @@ static struct roffmac roffs[TOKEN_NONE] = { { roff_unsupp, NULL, NULL, 0 }, /* break */ { roff_line_ignore, NULL, NULL, 0 }, /* breakchar */ { roff_line_ignore, NULL, NULL, 0 }, /* brnl */ - { roff_br, NULL, NULL, 0 }, /* brp */ + { roff_noarg, NULL, NULL, 0 }, /* brp */ { roff_line_ignore, NULL, NULL, 0 }, /* brpnl */ { roff_unsupp, NULL, NULL, 0 }, /* c2 */ { roff_cc, NULL, NULL, 0 }, /* cc */ { roff_insec, NULL, NULL, 0 }, /* cf */ { roff_line_ignore, NULL, NULL, 0 }, /* cflags */ { roff_line_ignore, NULL, NULL, 0 }, /* ch */ - { roff_unsupp, NULL, NULL, 0 }, /* char */ + { roff_char, NULL, NULL, 0 }, /* char */ { roff_unsupp, NULL, NULL, 0 }, /* chop */ { roff_line_ignore, NULL, NULL, 0 }, /* class */ { roff_insec, NULL, NULL, 0 }, /* close */ @@ -490,7 +520,7 @@ static struct roffmac roffs[TOKEN_NONE] = { { roff_line_ignore, NULL, NULL, 0 }, /* nhychar */ { roff_unsupp, NULL, NULL, 0 }, /* nm */ { roff_unsupp, NULL, NULL, 0 }, /* nn */ - { roff_unsupp, NULL, NULL, 0 }, /* nop */ + { roff_nop, NULL, NULL, 0 }, /* nop */ { roff_nr, NULL, NULL, 0 }, /* nr */ { roff_unsupp, NULL, NULL, 0 }, /* nrf */ { roff_line_ignore, NULL, NULL, 0 }, /* nroff */ @@ -519,7 +549,7 @@ static struct roffmac roffs[TOKEN_NONE] = { { roff_unsupp, NULL, NULL, 0 }, /* rchar */ { roff_line_ignore, NULL, NULL, 0 }, /* rd */ { roff_line_ignore, NULL, NULL, 0 }, /* recursionlimit */ - { roff_unsupp, NULL, NULL, 0 }, /* return */ + { roff_return, NULL, NULL, 0 }, /* return */ { roff_unsupp, NULL, NULL, 0 }, /* rfschar */ { roff_line_ignore, NULL, NULL, 0 }, /* rhang */ { roff_rm, NULL, NULL, 0 }, /* rm */ @@ -531,7 +561,7 @@ static struct roffmac roffs[TOKEN_NONE] = { { roff_unsupp, NULL, NULL, 0 }, /* schar */ { roff_line_ignore, NULL, NULL, 0 }, /* sentchar */ { roff_line_ignore, NULL, NULL, 0 }, /* shc */ - { roff_unsupp, NULL, NULL, 0 }, /* shift */ + { roff_shift, NULL, NULL, 0 }, /* shift */ { roff_line_ignore, NULL, NULL, 0 }, /* sizes */ { roff_so, NULL, NULL, 0 }, /* so */ { roff_line_ignore, NULL, NULL, 0 }, /* spacewidth */ @@ -573,7 +603,7 @@ static struct roffmac roffs[TOKEN_NONE] = { { roff_line_ignore, NULL, NULL, 0 }, /* watchlength */ { roff_line_ignore, NULL, NULL, 0 }, /* watchn */ { roff_unsupp, NULL, NULL, 0 }, /* wh */ - { roff_unsupp, NULL, NULL, 0 }, /* while */ + { roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT }, /*while*/ { roff_insec, NULL, NULL, 0 }, /* write */ { roff_insec, NULL, NULL, 0 }, /* writec */ { roff_insec, NULL, NULL, 0 }, /* writem */ @@ -657,18 +687,19 @@ roffhash_find(struct ohash *htab, const char *name, size_t sz) * Pop the current node off of the stack of roff instructions currently * pending. */ -static void +static int roffnode_pop(struct roff *r) { struct roffnode *p; + int inloop; - assert(r->last); p = r->last; - - r->last = r->last->parent; + inloop = p->tok == ROFF_while; + r->last = p->parent; free(p->name); free(p->end); free(p); + return inloop; } /* @@ -698,19 +729,17 @@ roffnode_push(struct roff *r, enum roff_tok tok, const char *name, static void roff_free1(struct roff *r) { - struct tbl_node *tbl; int i; - while (NULL != (tbl = r->first_tbl)) { - r->first_tbl = tbl->next; - tbl_free(tbl); - } + tbl_free(r->first_tbl); r->first_tbl = r->last_tbl = r->tbl = NULL; - if (r->last_eqn != NULL) - eqn_free(r->last_eqn); + eqn_free(r->last_eqn); r->last_eqn = r->eqn = NULL; + while (r->mstackpos >= 0) + roff_userret(r); + while (r->last) roffnode_pop(r); @@ -750,21 +779,26 @@ roff_reset(struct roff *r) void roff_free(struct roff *r) { + int i; + roff_free1(r); + for (i = 0; i < r->mstacksz; i++) + free(r->mstack[i].argv); + free(r->mstack); roffhash_free(r->reqtab); free(r); } struct roff * -roff_alloc(struct mparse *parse, int options) +roff_alloc(int options) { struct roff *r; r = mandoc_calloc(1, sizeof(struct roff)); - r->parse = parse; r->reqtab = roffhash_alloc(0, ROFF_RENAMED); r->options = options; r->format = options & (MPARSE_MDOC | MPARSE_MAN); + r->mstackpos = -1; r->rstackpos = -1; r->escape = '\\'; return r; @@ -775,9 +809,8 @@ roff_alloc(struct mparse *parse, int options) static void roff_man_free1(struct roff_man *man) { - - if (man->first != NULL) - roff_node_delete(man, man->first); + if (man->meta.first != NULL) + roff_node_delete(man, man->meta.first); free(man->meta.msec); free(man->meta.vol); free(man->meta.os); @@ -785,27 +818,33 @@ roff_man_free1(struct roff_man *man) free(man->meta.title); free(man->meta.name); free(man->meta.date); + free(man->meta.sodest); } -static void -roff_man_alloc1(struct roff_man *man) +void +roff_state_reset(struct roff_man *man) { - - memset(&man->meta, 0, sizeof(man->meta)); - man->first = mandoc_calloc(1, sizeof(*man->first)); - man->first->type = ROFFT_ROOT; - man->last = man->first; + man->last = man->meta.first; man->last_es = NULL; man->flags = 0; - man->macroset = MACROSET_NONE; man->lastsec = man->lastnamed = SEC_NONE; man->next = ROFF_NEXT_CHILD; + roff_setreg(man->roff, "nS", 0, '='); +} + +static void +roff_man_alloc1(struct roff_man *man) +{ + memset(&man->meta, 0, sizeof(man->meta)); + man->meta.first = mandoc_calloc(1, sizeof(*man->meta.first)); + man->meta.first->type = ROFFT_ROOT; + man->meta.macroset = MACROSET_NONE; + roff_state_reset(man); } void roff_man_reset(struct roff_man *man) { - roff_man_free1(man); roff_man_alloc1(man); } @@ -813,19 +852,16 @@ roff_man_reset(struct roff_man *man) void roff_man_free(struct roff_man *man) { - roff_man_free1(man); free(man); } struct roff_man * -roff_man_alloc(struct roff *roff, struct mparse *parse, - const char *os_s, int quick) +roff_man_alloc(struct roff *roff, const char *os_s, int quick) { struct roff_man *man; man = mandoc_calloc(1, sizeof(*man)); - man->parse = parse; man->roff = roff; man->os_s = os_s; man->quick = quick; @@ -853,6 +889,10 @@ roff_node_alloc(struct roff_man *man, int line, int pos, n->flags |= NODE_SYNPRETTY; else n->flags &= ~NODE_SYNPRETTY; + if ((man->flags & (ROFF_NOFILL | ROFF_NONOFILL)) == ROFF_NOFILL) + n->flags |= NODE_NOFILL; + else + n->flags &= ~NODE_NOFILL; if (man->flags & MDOC_NEWLINE) n->flags |= NODE_LINE; man->flags &= ~MDOC_NEWLINE; @@ -985,15 +1025,15 @@ roff_body_alloc(struct roff_man *man, int line, int pos, int tok) } static void -roff_addtbl(struct roff_man *man, struct tbl_node *tbl) +roff_addtbl(struct roff_man *man, int line, struct tbl_node *tbl) { struct roff_node *n; - const struct tbl_span *span; + struct tbl_span *span; - if (man->macroset == MACROSET_MAN) + if (man->meta.macroset == MACROSET_MAN) man_breakscope(man, ROFF_TS); while ((span = tbl_span(tbl)) != NULL) { - n = roff_node_alloc(man, tbl->line, 0, ROFFT_TBL, TOKEN_NONE); + n = roff_node_alloc(man, line, 0, ROFFT_TBL, TOKEN_NONE); n->span = span; roff_node_append(man, n); n->flags |= NODE_VALID | NODE_ENDED; @@ -1034,8 +1074,16 @@ roff_node_unlink(struct roff_man *man, struct roff_node *n) man->next = ROFF_NEXT_SIBLING; } } - if (man->first == n) - man->first = NULL; + if (man->meta.first == n) + man->meta.first = NULL; +} + +void +roff_node_relink(struct roff_man *man, struct roff_node *n) +{ + roff_node_unlink(man, n); + n->prev = n->next = NULL; + roff_node_append(man, n); } void @@ -1046,8 +1094,7 @@ roff_node_free(struct roff_node *n) mdoc_argv_free(n->args); if (n->type == ROFFT_BLOCK || n->type == ROFFT_ELEM) free(n->norm); - if (n->eqn != NULL) - eqn_box_free(n->eqn); + eqn_box_free(n->eqn); free(n->string); free(n); } @@ -1114,17 +1161,19 @@ deroff(char **dest, const struct roff_node *n) /* --- main functions of the roff parser ---------------------------------- */ /* - * In the current line, expand escape sequences that tend to get - * used in numerical expressions and conditional requests. - * Also check the syntax of the remaining escape sequences. + * In the current line, expand escape sequences that produce parsable + * input text. Also check the syntax of the remaining escape sequences, + * which typically produce output glyphs or change formatter state. */ -static enum rofferr -roff_res(struct roff *r, struct buf *buf, int ln, int pos) +static int +roff_expand(struct roff *r, struct buf *buf, int ln, int pos, char newesc) { + struct mctx *ctx; /* current macro call context */ 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 ('\\') */ + const char *esct; /* type of esccape 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 ']' */ @@ -1132,14 +1181,17 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos) char *nbuf; /* new buffer to copy buf->buf to */ size_t maxl; /* expected length of the escape name */ size_t naml; /* actual length of the escape name */ - enum mandoc_esc esc; /* type of the escape sequence */ + size_t asz; /* length of the replacement */ + size_t rsz; /* length of the rest of the string */ int inaml; /* length returned from mandoc_escape() */ int expand_count; /* to avoid infinite loops */ int npos; /* position in numeric expression */ int arg_complete; /* argument not interrupted by eol */ + int quote_args; /* true for \\$@, false for \\$* */ int done; /* no more input available */ int deftype; /* type of definition to paste */ int rcsid; /* kind of RCS id seen */ + enum mandocerr err; /* for escape sequence problems */ char sign; /* increment number register */ char term; /* character terminating the escape */ @@ -1148,7 +1200,7 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos) done = 0; start = buf->buf + pos; for (stesc = buf->buf + pos; *stesc != '\0'; stesc++) { - if (stesc[0] != r->escape || stesc[1] == '\0') + if (stesc[0] != newesc || stesc[1] == '\0') continue; stesc++; if (*stesc != '"' && *stesc != '#') @@ -1168,8 +1220,9 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos) isalnum((unsigned char)*cp) == 0 && strchr(cp, '$') != NULL) { if (r->man->meta.rcsids & rcsid) - mandoc_msg(MANDOCERR_RCS_REP, r->parse, - ln, stesc + 1 - buf->buf, stesc + 1); + mandoc_msg(MANDOCERR_RCS_REP, ln, + (int)(stesc - buf->buf) + 1, + "%s", stesc + 1); r->man->meta.rcsids |= rcsid; } @@ -1181,15 +1234,15 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos) ep--; } if (*ep == ' ' || *ep == '\t') - mandoc_msg(MANDOCERR_SPACE_EOL, r->parse, - ln, ep - buf->buf, NULL); + mandoc_msg(MANDOCERR_SPACE_EOL, + ln, (int)(ep - buf->buf), NULL); /* * Save comments preceding the title macro * in the syntax tree. */ - if (r->format == 0) { + if (newesc != ASCII_ESC && r->format == 0) { while (*ep == ' ' || *ep == '\t') ep--; ep[1] = '\0'; @@ -1202,9 +1255,17 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos) r->man->next = ROFF_NEXT_SIBLING; } - /* Discard comments. */ + /* Line continuation with comment. */ + + if (stesc[1] == '#') { + *stesc = '\0'; + return ROFF_IGN | ROFF_APPEND; + } + + /* Discard normal comments. */ - while (stesc > start && stesc[-1] == ' ') + while (stesc > start && stesc[-1] == ' ' && + (stesc == start + 1 || stesc[-2] != '\\')) stesc--; *stesc = '\0'; break; @@ -1222,11 +1283,16 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos) expand_count = 0; while (stesc >= start) { + if (*stesc != newesc) { - /* Search backwards for the next backslash. */ + /* + * If we have a non-standard escape character, + * escape literal backslashes because all + * processing in subsequent functions uses + * the standard escaping rules. + */ - if (*stesc != r->escape) { - if (*stesc == '\\') { + if (newesc != ASCII_ESC && *stesc == '\\') { *stesc = '\0'; buf->sz = mandoc_asprintf(&nbuf, "%s\\e%s", buf->buf, stesc + 1) + 1; @@ -1235,6 +1301,9 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos) free(buf->buf); buf->buf = nbuf; } + + /* Search backwards for the next escape. */ + stesc--; continue; } @@ -1256,15 +1325,19 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos) if (done) continue; else - return ROFF_APPEND; + return ROFF_IGN | ROFF_APPEND; } /* Decide whether to expand or to check only. */ term = '\0'; cp = stesc + 1; - switch (*cp) { + if (*cp == 'E') + cp++; + esct = cp; + switch (*esct) { case '*': + case '$': res = NULL; break; case 'B': @@ -1278,19 +1351,33 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos) res = ubuf; break; default: - esc = mandoc_escape(&cp, &stnam, &inaml); - if (esc == ESCAPE_ERROR || - (esc == ESCAPE_SPECIAL && - mchars_spec2cp(stnam, inaml) < 0)) - mandoc_vmsg(MANDOCERR_ESC_BAD, - r->parse, ln, (int)(stesc - buf->buf), + err = MANDOCERR_OK; + switch(mandoc_escape(&cp, &stnam, &inaml)) { + case ESCAPE_SPECIAL: + if (mchars_spec2cp(stnam, inaml) >= 0) + break; + /* FALLTHROUGH */ + case ESCAPE_ERROR: + err = MANDOCERR_ESC_BAD; + break; + case ESCAPE_UNDEF: + err = MANDOCERR_ESC_UNDEF; + break; + case ESCAPE_UNSUPP: + err = MANDOCERR_ESC_UNSUPP; + break; + default: + break; + } + if (err != MANDOCERR_OK) + mandoc_msg(err, ln, (int)(stesc - buf->buf), "%.*s", (int)(cp - stesc), stesc); stesc--; continue; } if (EXPAND_LIMIT < ++expand_count) { - mandoc_msg(MANDOCERR_ROFFLOOP, r->parse, + mandoc_msg(MANDOCERR_ROFFLOOP, ln, (int)(stesc - buf->buf), NULL); return ROFF_IGN; } @@ -1331,8 +1418,8 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos) arg_complete = 1; while (maxl == 0 || naml < maxl) { if (*cp == '\0') { - mandoc_msg(MANDOCERR_ESC_BAD, r->parse, - ln, (int)(stesc - buf->buf), stesc); + mandoc_msg(MANDOCERR_ESC_BAD, ln, + (int)(stesc - buf->buf), "%s", stesc); arg_complete = 0; break; } @@ -1340,7 +1427,7 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos) cp++; break; } - if (*cp++ != '\\' || stesc[1] != 'w') { + if (*cp++ != '\\' || *esct != 'w') { naml++; continue; } @@ -1348,6 +1435,7 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos) case ESCAPE_SPECIAL: case ESCAPE_UNICODE: case ESCAPE_NUMBERED: + case ESCAPE_UNDEF: case ESCAPE_OVERSTRIKE: naml++; break; @@ -1361,13 +1449,80 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos) * undefined, resume searching for escapes. */ - switch (stesc[1]) { + switch (*esct) { case '*': if (arg_complete) { deftype = ROFFDEF_USER | ROFFDEF_PRE; res = roff_getstrn(r, stnam, naml, &deftype); + + /* + * If not overriden, let \*(.T + * through to the formatters. + */ + + if (res == NULL && naml == 2 && + stnam[0] == '.' && stnam[1] == 'T') { + roff_setstrn(&r->strtab, + ".T", 2, NULL, 0, 0); + stesc--; + continue; + } } break; + case '$': + if (r->mstackpos < 0) { + mandoc_msg(MANDOCERR_ARG_UNDEF, ln, + (int)(stesc - buf->buf), "%.3s", stesc); + break; + } + ctx = r->mstack + r->mstackpos; + npos = esct[1] - '1'; + if (npos >= 0 && npos <= 8) { + res = npos < ctx->argc ? + ctx->argv[npos] : ""; + break; + } + if (esct[1] == '*') + quote_args = 0; + else if (esct[1] == '@') + quote_args = 1; + else { + mandoc_msg(MANDOCERR_ARG_NONUM, ln, + (int)(stesc - buf->buf), "%.3s", stesc); + break; + } + asz = 0; + for (npos = 0; npos < ctx->argc; npos++) { + if (npos) + asz++; /* blank */ + if (quote_args) + asz += 2; /* quotes */ + asz += strlen(ctx->argv[npos]); + } + if (asz != 3) { + rsz = buf->sz - (stesc - buf->buf) - 3; + if (asz < 3) + memmove(stesc + asz, stesc + 3, rsz); + buf->sz += asz - 3; + nbuf = mandoc_realloc(buf->buf, buf->sz); + start = nbuf + pos; + stesc = nbuf + (stesc - buf->buf); + buf->buf = nbuf; + if (asz > 3) + memmove(stesc + asz, stesc + 3, rsz); + } + for (npos = 0; npos < ctx->argc; npos++) { + if (npos) + *stesc++ = ' '; + if (quote_args) + *stesc++ = '"'; + cp = ctx->argv[npos]; + while (*cp != '\0') + *stesc++ = *cp++; + if (quote_args) + *stesc++ = '"'; + } + continue; case 'B': npos = 0; ubuf[0] = arg_complete && @@ -1391,12 +1546,13 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos) } if (res == NULL) { - mandoc_vmsg(MANDOCERR_STR_UNDEF, - r->parse, ln, (int)(stesc - buf->buf), - "%.*s", (int)naml, stnam); + if (*esct == '*') + mandoc_msg(MANDOCERR_STR_UNDEF, + ln, (int)(stesc - buf->buf), + "%.*s", (int)naml, stnam); res = ""; } else if (buf->sz + strlen(res) > SHRT_MAX) { - mandoc_msg(MANDOCERR_ROFFLOOP, r->parse, + mandoc_msg(MANDOCERR_ROFFLOOP, ln, (int)(stesc - buf->buf), NULL); return ROFF_IGN; } @@ -1418,9 +1574,121 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos) } /* + * Parse a quoted or unquoted roff-style request or macro argument. + * Return a pointer to the parsed argument, which is either the original + * pointer or advanced by one byte in case the argument is quoted. + * NUL-terminate the argument in place. + * Collapse pairs of quotes inside quoted arguments. + * Advance the argument pointer to the next argument, + * or to the NUL byte terminating the argument line. + */ +char * +roff_getarg(struct roff *r, char **cpp, int ln, int *pos) +{ + struct buf buf; + char *cp, *start; + int newesc, pairs, quoted, white; + + /* Quoting can only start with a new word. */ + start = *cpp; + quoted = 0; + if ('"' == *start) { + quoted = 1; + start++; + } + + newesc = pairs = white = 0; + for (cp = start; '\0' != *cp; cp++) { + + /* + * Move the following text left + * after quoted quotes and after "\\" and "\t". + */ + if (pairs) + cp[-pairs] = cp[0]; + + if ('\\' == cp[0]) { + /* + * In copy mode, translate double to single + * backslashes and backslash-t to literal tabs. + */ + switch (cp[1]) { + case 'a': + case 't': + cp[-pairs] = '\t'; + pairs++; + cp++; + break; + case '\\': + newesc = 1; + cp[-pairs] = ASCII_ESC; + pairs++; + cp++; + break; + case ' ': + /* Skip escaped blanks. */ + if (0 == quoted) + cp++; + break; + default: + break; + } + } else if (0 == quoted) { + if (' ' == cp[0]) { + /* Unescaped blanks end unquoted args. */ + white = 1; + break; + } + } else if ('"' == cp[0]) { + if ('"' == cp[1]) { + /* Quoted quotes collapse. */ + pairs++; + cp++; + } else { + /* Unquoted quotes end quoted args. */ + quoted = 2; + break; + } + } + } + + /* Quoted argument without a closing quote. */ + if (1 == quoted) + mandoc_msg(MANDOCERR_ARG_QUOTE, ln, *pos, NULL); + + /* NUL-terminate this argument and move to the next one. */ + if (pairs) + cp[-pairs] = '\0'; + if ('\0' != *cp) { + *cp++ = '\0'; + while (' ' == *cp) + cp++; + } + *pos += (int)(cp - start) + (quoted ? 1 : 0); + *cpp = cp; + + if ('\0' == *cp && (white || ' ' == cp[-1])) + mandoc_msg(MANDOCERR_SPACE_EOL, ln, *pos, NULL); + + start = mandoc_strdup(start); + if (newesc == 0) + return start; + + buf.buf = start; + buf.sz = strlen(start) + 1; + buf.next = NULL; + if (roff_expand(r, &buf, ln, 0, ASCII_ESC) & ROFF_IGN) { + free(buf.buf); + buf.buf = mandoc_strdup(""); + } + return buf.buf; +} + + +/* * Process text streams. */ -static enum rofferr +static int roff_parsetext(struct roff *r, struct buf *buf, int pos, int *offs) { size_t sz; @@ -1486,11 +1754,11 @@ roff_parsetext(struct roff *r, struct buf *buf, int pos, int *offs) return ROFF_CONT; } -enum rofferr +int roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs) { enum roff_tok t; - enum rofferr e; + int e; int pos; /* parse point */ int spos; /* saved parse point for messages */ int ppos; /* original offset in buf->buf */ @@ -1511,8 +1779,8 @@ roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs) /* Expand some escape sequences. */ - e = roff_res(r, buf, ln, pos); - if (e == ROFF_IGN || e == ROFF_APPEND) + e = roff_expand(r, buf, ln, pos, r->escape); + if ((e & ROFF_MASK) == ROFF_IGN) return e; assert(e == ROFF_CONT); @@ -1529,27 +1797,27 @@ roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs) if (r->last != NULL && ! ctl) { t = r->last->tok; e = (*roffs[t].text)(r, t, buf, ln, pos, pos, offs); - if (e == ROFF_IGN) + if ((e & ROFF_MASK) == ROFF_IGN) return e; - assert(e == ROFF_CONT); - } + e &= ~ROFF_MASK; + } else + e = ROFF_IGN; if (r->eqn != NULL && strncmp(buf->buf + ppos, ".EN", 3)) { eqn_read(r->eqn, buf->buf + ppos); - return ROFF_IGN; + return e; } if (r->tbl != NULL && (ctl == 0 || buf->buf[pos] == '\0')) { tbl_read(r->tbl, ln, buf->buf, ppos); - roff_addtbl(r->man, r->tbl); - return ROFF_IGN; + roff_addtbl(r->man, ln, r->tbl); + return e; } if ( ! ctl) - return roff_parsetext(r, buf, pos, offs); + return roff_parsetext(r, buf, pos, offs) | e; /* Skip empty request lines. */ if (buf->buf[pos] == '"') { - mandoc_msg(MANDOCERR_COMMENT_BAD, r->parse, - ln, pos, NULL); + mandoc_msg(MANDOCERR_COMMENT_BAD, ln, pos, NULL); return ROFF_IGN; } else if (buf->buf[pos] == '\0') return ROFF_IGN; @@ -1574,8 +1842,8 @@ roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs) if (r->tbl != NULL && (t == TOKEN_NONE || t == ROFF_TS || t == ROFF_br || t == ROFF_ce || t == ROFF_rj || t == ROFF_sp)) { - mandoc_msg(MANDOCERR_TBLMACRO, r->parse, - ln, pos, buf->buf + spos); + mandoc_msg(MANDOCERR_TBLMACRO, + ln, pos, "%s", buf->buf + spos); if (t != TOKEN_NONE) return ROFF_IGN; while (buf->buf[pos] != '\0' && buf->buf[pos] != ' ') @@ -1583,7 +1851,7 @@ roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs) while (buf->buf[pos] == ' ') pos++; tbl_read(r->tbl, ln, buf->buf, pos); - roff_addtbl(r->man, r->tbl); + roff_addtbl(r->man, ln, r->tbl); return ROFF_IGN; } @@ -1611,25 +1879,41 @@ roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs) return (*roffs[t].proc)(r, t, buf, ln, spos, pos, offs); } +/* + * Internal interface function to tell the roff parser that execution + * of the current macro ended. This is required because macro + * definitions usually do not end with a .return request. + */ +void +roff_userret(struct roff *r) +{ + struct mctx *ctx; + int i; + + assert(r->mstackpos >= 0); + ctx = r->mstack + r->mstackpos; + for (i = 0; i < ctx->argc; i++) + free(ctx->argv[i]); + ctx->argc = 0; + r->mstackpos--; +} + void roff_endparse(struct roff *r) { if (r->last != NULL) - mandoc_msg(MANDOCERR_BLK_NOEND, r->parse, - r->last->line, r->last->col, - roff_name[r->last->tok]); + mandoc_msg(MANDOCERR_BLK_NOEND, r->last->line, + r->last->col, "%s", roff_name[r->last->tok]); if (r->eqn != NULL) { - mandoc_msg(MANDOCERR_BLK_NOEND, r->parse, + mandoc_msg(MANDOCERR_BLK_NOEND, r->eqn->node->line, r->eqn->node->pos, "EQ"); eqn_parse(r->eqn); r->eqn = NULL; } if (r->tbl != NULL) { - mandoc_msg(MANDOCERR_BLK_NOEND, r->parse, - r->tbl->line, r->tbl->pos, "TS"); - tbl_end(r->tbl); + tbl_end(r->tbl, 1); r->tbl = NULL; } } @@ -1680,7 +1964,7 @@ roff_parse(struct roff *r, char *buf, int *pos, int ln, int ppos) /* --- handling of request blocks ----------------------------------------- */ -static enum rofferr +static int roff_cblock(ROFF_ARGS) { @@ -1690,8 +1974,7 @@ roff_cblock(ROFF_ARGS) */ if (r->last == NULL) { - mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse, - ln, ppos, ".."); + mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, ".."); return ROFF_IGN; } @@ -1705,13 +1988,12 @@ roff_cblock(ROFF_ARGS) case ROFF_ig: break; default: - mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse, - ln, ppos, ".."); + mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, ".."); return ROFF_IGN; } if (buf->buf[pos] != '\0') - mandoc_vmsg(MANDOCERR_ARG_SKIP, r->parse, ln, pos, + mandoc_msg(MANDOCERR_ARG_SKIP, ln, pos, ".. %s", buf->buf + pos); roffnode_pop(r); @@ -1720,50 +2002,48 @@ roff_cblock(ROFF_ARGS) } -static void +static int roffnode_cleanscope(struct roff *r) { + int inloop; - while (r->last) { + inloop = 0; + while (r->last != NULL) { if (--r->last->endspan != 0) break; - roffnode_pop(r); + inloop += roffnode_pop(r); } + return inloop; } -static void +static int roff_ccond(struct roff *r, int ln, int ppos) { - if (NULL == r->last) { - mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse, - ln, ppos, "\\}"); - return; + mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "\\}"); + return 0; } switch (r->last->tok) { case ROFF_el: case ROFF_ie: case ROFF_if: + case ROFF_while: break; default: - mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse, - ln, ppos, "\\}"); - return; + mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "\\}"); + return 0; } if (r->last->endspan > -1) { - mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse, - ln, ppos, "\\}"); - return; + mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "\\}"); + return 0; } - roffnode_pop(r); - roffnode_cleanscope(r); - return; + return roffnode_pop(r) + roffnode_cleanscope(r); } -static enum rofferr +static int roff_block(ROFF_ARGS) { const char *name, *value; @@ -1800,8 +2080,8 @@ roff_block(ROFF_ARGS) deftype = ROFFDEF_USER; name = roff_getstrn(r, iname, namesz, &deftype); if (name == NULL) { - mandoc_vmsg(MANDOCERR_STR_UNDEF, - r->parse, ln, (int)(iname - buf->buf), + mandoc_msg(MANDOCERR_STR_UNDEF, + ln, (int)(iname - buf->buf), "%.*s", (int)namesz, iname); namesz = 0; } else @@ -1810,8 +2090,8 @@ roff_block(ROFF_ARGS) name = iname; if (namesz == 0 && tok != ROFF_ig) { - mandoc_msg(MANDOCERR_REQ_EMPTY, r->parse, - ln, ppos, roff_name[tok]); + mandoc_msg(MANDOCERR_REQ_EMPTY, + ln, ppos, "%s", roff_name[tok]); return ROFF_IGN; } @@ -1869,8 +2149,8 @@ roff_block(ROFF_ARGS) deftype = ROFFDEF_USER; name = roff_getstrn(r, iname, namesz, &deftype); if (name == NULL) { - mandoc_vmsg(MANDOCERR_STR_UNDEF, - r->parse, ln, (int)(iname - buf->buf), + mandoc_msg(MANDOCERR_STR_UNDEF, + ln, (int)(iname - buf->buf), "%.*s", (int)namesz, iname); namesz = 0; } else @@ -1882,13 +2162,13 @@ roff_block(ROFF_ARGS) r->last->end = mandoc_strndup(name, namesz); if (*cp != '\0') - mandoc_vmsg(MANDOCERR_ARG_EXCESS, r->parse, + mandoc_msg(MANDOCERR_ARG_EXCESS, ln, pos, ".%s ... %s", roff_name[tok], cp); return ROFF_IGN; } -static enum rofferr +static int roff_block_sub(ROFF_ARGS) { enum roff_tok t; @@ -1942,7 +2222,7 @@ roff_block_sub(ROFF_ARGS) return (*roffs[t].proc)(r, t, buf, ln, ppos, pos, offs); } -static enum rofferr +static int roff_block_text(ROFF_ARGS) { @@ -1952,15 +2232,19 @@ roff_block_text(ROFF_ARGS) return ROFF_IGN; } -static enum rofferr +static int roff_cond_sub(ROFF_ARGS) { - enum roff_tok t; char *ep; - int rr; + int endloop, irc, rr; + enum roff_tok t; + irc = ROFF_IGN; rr = r->last->rule; - roffnode_cleanscope(r); + endloop = tok != ROFF_while ? ROFF_IGN : + rr ? ROFF_LOOPCONT : ROFF_LOOPEXIT; + if (roffnode_cleanscope(r)) + irc |= endloop; /* * If `\}' occurs on a macro line without a preceding macro, @@ -1971,13 +2255,17 @@ roff_cond_sub(ROFF_ARGS) if (ep[0] == '\\' && ep[1] == '}') rr = 0; - /* Always check for the closing delimiter `\}'. */ + /* + * The closing delimiter `\}' rewinds the conditional scope + * but is otherwise ignored when interpreting the line. + */ while ((ep = strchr(ep, '\\')) != NULL) { switch (ep[1]) { case '}': memmove(ep, ep + 2, strlen(ep + 2) + 1); - roff_ccond(r, ln, ep - buf->buf); + if (roff_ccond(r, ln, ep - buf->buf)) + irc |= endloop; break; case '\0': ++ep; @@ -1994,30 +2282,57 @@ roff_cond_sub(ROFF_ARGS) */ t = roff_parse(r, buf->buf, &pos, ln, ppos); - return t != TOKEN_NONE && (rr || roffs[t].flags & ROFFMAC_STRUCT) - ? (*roffs[t].proc)(r, t, buf, ln, ppos, pos, offs) : rr - ? ROFF_CONT : ROFF_IGN; + irc |= t != TOKEN_NONE && (rr || roffs[t].flags & ROFFMAC_STRUCT) ? + (*roffs[t].proc)(r, t, buf, ln, ppos, pos, offs) : + rr ? ROFF_CONT : ROFF_IGN; + return irc; } -static enum rofferr +static int roff_cond_text(ROFF_ARGS) { char *ep; - int rr; + int endloop, irc, rr; + irc = ROFF_IGN; rr = r->last->rule; - roffnode_cleanscope(r); + endloop = tok != ROFF_while ? ROFF_IGN : + rr ? ROFF_LOOPCONT : ROFF_LOOPEXIT; + if (roffnode_cleanscope(r)) + irc |= endloop; + + /* + * If `\}' occurs on a text line with neither preceding + * nor following characters, drop the line completely. + */ ep = buf->buf + pos; + if (strcmp(ep, "\\}") == 0) + rr = 0; + + /* + * The closing delimiter `\}' rewinds the conditional scope + * but is otherwise ignored when interpreting the line. + */ + while ((ep = strchr(ep, '\\')) != NULL) { - if (*(++ep) == '}') { - *ep = '&'; - roff_ccond(r, ln, ep - buf->buf - 1); - } - if (*ep != '\0') + switch (ep[1]) { + case '}': + memmove(ep, ep + 2, strlen(ep + 2) + 1); + if (roff_ccond(r, ln, ep - buf->buf)) + irc |= endloop; + break; + case '\0': ++ep; + break; + default: + ep += 2; + break; + } } - return rr ? ROFF_CONT : ROFF_IGN; + if (rr) + irc |= ROFF_CONT; + return irc; } /* --- handling of numeric and conditional expressions -------------------- */ @@ -2144,9 +2459,10 @@ out: static int roff_evalcond(struct roff *r, int ln, char *v, int *pos) { - char *cp, *name; - size_t sz; - int deftype, number, savepos, istrue, wanttrue; + const char *start, *end; + char *cp, *name; + size_t sz; + int deftype, len, number, savepos, istrue, wanttrue; if ('!' == v[*pos]) { wanttrue = 0; @@ -2161,12 +2477,50 @@ roff_evalcond(struct roff *r, int ln, char *v, int *pos) case 'o': (*pos)++; return wanttrue; - case 'c': case 'e': case 't': case 'v': (*pos)++; return !wanttrue; + case 'c': + do { + (*pos)++; + } while (v[*pos] == ' '); + + /* + * Quirk for groff compatibility: + * The horizontal tab is neither available nor unavailable. + */ + + if (v[*pos] == '\t') { + (*pos)++; + return 0; + } + + /* Printable ASCII characters are available. */ + + if (v[*pos] != '\\') { + (*pos)++; + return wanttrue; + } + + end = v + ++*pos; + switch (mandoc_escape(&end, &start, &len)) { + case ESCAPE_SPECIAL: + istrue = mchars_spec2cp(start, len) != -1; + break; + case ESCAPE_UNICODE: + istrue = 1; + break; + case ESCAPE_NUMBERED: + istrue = mchars_num2char(start, len) != -1; + break; + default: + istrue = !wanttrue; + break; + } + *pos = end - v; + return istrue == wanttrue; case 'd': case 'r': cp = v + *pos + 1; @@ -2183,7 +2537,7 @@ roff_evalcond(struct roff *r, int ln, char *v, int *pos) roff_getstrn(r, name, sz, &deftype); istrue = !!deftype; } - *pos = cp - v; + *pos = (name + sz) - v; return istrue == wanttrue; default: break; @@ -2198,34 +2552,33 @@ roff_evalcond(struct roff *r, int ln, char *v, int *pos) return 0; } -static enum rofferr +static int roff_line_ignore(ROFF_ARGS) { return ROFF_IGN; } -static enum rofferr +static int roff_insec(ROFF_ARGS) { - mandoc_msg(MANDOCERR_REQ_INSEC, r->parse, - ln, ppos, roff_name[tok]); + mandoc_msg(MANDOCERR_REQ_INSEC, ln, ppos, "%s", roff_name[tok]); return ROFF_IGN; } -static enum rofferr +static int roff_unsupp(ROFF_ARGS) { - mandoc_msg(MANDOCERR_REQ_UNSUPP, r->parse, - ln, ppos, roff_name[tok]); + mandoc_msg(MANDOCERR_REQ_UNSUPP, ln, ppos, "%s", roff_name[tok]); return ROFF_IGN; } -static enum rofferr +static int roff_cond(ROFF_ARGS) { + int irc; roffnode_push(r, tok, NULL, ln, ppos); @@ -2264,9 +2617,10 @@ roff_cond(ROFF_ARGS) * Determine scope. * If there is nothing on the line after the conditional, * not even whitespace, use next-line scope. + * Except that .while does not support next-line scope. */ - if (buf->buf[pos] == '\0') { + if (buf->buf[pos] == '\0' && tok != ROFF_while) { r->last->endspan = 2; goto out; } @@ -2291,17 +2645,20 @@ roff_cond(ROFF_ARGS) */ if (buf->buf[pos] == '\0') - mandoc_msg(MANDOCERR_COND_EMPTY, r->parse, - ln, ppos, roff_name[tok]); + mandoc_msg(MANDOCERR_COND_EMPTY, + ln, ppos, "%s", roff_name[tok]); r->last->endspan = 1; out: *offs = pos; - return ROFF_RERUN; + irc = ROFF_RERUN; + if (tok == ROFF_while) + irc |= ROFF_WHILE; + return irc; } -static enum rofferr +static int roff_ds(ROFF_ARGS) { char *string; @@ -2326,8 +2683,15 @@ roff_ds(ROFF_ARGS) return ROFF_IGN; namesz = roff_getname(r, &string, ln, pos); - if (name[namesz] == '\\') + switch (name[namesz]) { + case '\\': return ROFF_IGN; + case '\t': + string = buf->buf + pos + namesz; + break; + default: + break; + } /* Read past the initial double-quote, if any. */ if (*string == '"') @@ -2492,7 +2856,7 @@ roff_evalnum(struct roff *r, int ln, const char *v, case '/': if (operand2 == 0) { mandoc_msg(MANDOCERR_DIVZERO, - r->parse, ln, *pos, v); + ln, *pos, "%s", v); *res = 0; break; } @@ -2501,7 +2865,7 @@ roff_evalnum(struct roff *r, int ln, const char *v, case '%': if (operand2 == 0) { mandoc_msg(MANDOCERR_DIVZERO, - r->parse, ln, *pos, v); + ln, *pos, "%s", v); *res = 0; break; } @@ -2600,7 +2964,7 @@ roff_getregro(const struct roff *r, const char *name) switch (*name) { case '$': /* Number of arguments of the last macro evaluated. */ - return r->argc; + return r->mstackpos < 0 ? 0 : r->mstack[r->mstackpos].argc; case 'A': /* ASCII approximation mode is always off. */ return 0; case 'g': /* Groff compatibility mode is always on. */ @@ -2690,7 +3054,7 @@ roff_freereg(struct roffreg *reg) } } -static enum rofferr +static int roff_nr(ROFF_ARGS) { char *key, *val, *step; @@ -2703,7 +3067,7 @@ roff_nr(ROFF_ARGS) return ROFF_IGN; keysz = roff_getname(r, &val, ln, pos); - if (key[keysz] == '\\') + if (key[keysz] == '\\' || key[keysz] == '\t') return ROFF_IGN; sign = *val; @@ -2724,7 +3088,7 @@ roff_nr(ROFF_ARGS) return ROFF_IGN; } -static enum rofferr +static int roff_rr(ROFF_ARGS) { struct roffreg *reg, **prev; @@ -2754,7 +3118,7 @@ roff_rr(ROFF_ARGS) /* --- handler functions for roff requests -------------------------------- */ -static enum rofferr +static int roff_rm(ROFF_ARGS) { const char *name; @@ -2767,13 +3131,13 @@ roff_rm(ROFF_ARGS) namesz = roff_getname(r, &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] == '\\') + if (name[namesz] == '\\' || name[namesz] == '\t') break; } return ROFF_IGN; } -static enum rofferr +static int roff_it(ROFF_ARGS) { int iv; @@ -2781,8 +3145,8 @@ roff_it(ROFF_ARGS) /* Parse the number of lines. */ if ( ! roff_evalnum(r, ln, buf->buf, &pos, &iv, 0)) { - mandoc_msg(MANDOCERR_IT_NONUM, r->parse, - ln, ppos, buf->buf + 1); + mandoc_msg(MANDOCERR_IT_NONUM, + ln, ppos, "%s", buf->buf + 1); return ROFF_IGN; } @@ -2802,7 +3166,7 @@ roff_it(ROFF_ARGS) return ROFF_IGN; } -static enum rofferr +static int roff_Dd(ROFF_ARGS) { int mask; @@ -2832,15 +3196,15 @@ roff_Dd(ROFF_ARGS) return ROFF_CONT; } -static enum rofferr +static int roff_TE(ROFF_ARGS) { + r->man->flags &= ~ROFF_NONOFILL; if (r->tbl == NULL) { - mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse, - ln, ppos, "TE"); + mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "TE"); return ROFF_IGN; } - if (tbl_end(r->tbl) == 0) { + if (tbl_end(r->tbl, 0) == 0) { r->tbl = NULL; free(buf->buf); buf->buf = mandoc_strdup(".sp"); @@ -2852,13 +3216,12 @@ roff_TE(ROFF_ARGS) return ROFF_IGN; } -static enum rofferr +static int roff_T_(ROFF_ARGS) { if (NULL == r->tbl) - mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse, - ln, ppos, "T&"); + mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "T&"); else tbl_restart(ln, ppos, r->tbl); @@ -2868,7 +3231,7 @@ roff_T_(ROFF_ARGS) /* * Handle in-line equation delimiters. */ -static enum rofferr +static int roff_eqndelim(struct roff *r, struct buf *buf, int pos) { char *cp1, *cp2; @@ -2931,68 +3294,85 @@ roff_eqndelim(struct roff *r, struct buf *buf, int pos) return ROFF_REPARSE; } -static enum rofferr +static int roff_EQ(ROFF_ARGS) { struct roff_node *n; - if (r->man->macroset == MACROSET_MAN) + if (r->man->meta.macroset == MACROSET_MAN) man_breakscope(r->man, ROFF_EQ); n = roff_node_alloc(r->man, ln, ppos, ROFFT_EQN, TOKEN_NONE); if (ln > r->man->last->line) n->flags |= NODE_LINE; - n->eqn = mandoc_calloc(1, sizeof(*n->eqn)); - n->eqn->expectargs = UINT_MAX; + n->eqn = eqn_box_new(); roff_node_append(r->man, n); r->man->next = ROFF_NEXT_SIBLING; assert(r->eqn == NULL); if (r->last_eqn == NULL) - r->last_eqn = eqn_alloc(r->parse); + r->last_eqn = eqn_alloc(); else eqn_reset(r->last_eqn); r->eqn = r->last_eqn; r->eqn->node = n; if (buf->buf[pos] != '\0') - mandoc_vmsg(MANDOCERR_ARG_SKIP, r->parse, ln, pos, + mandoc_msg(MANDOCERR_ARG_SKIP, ln, pos, ".EQ %s", buf->buf + pos); return ROFF_IGN; } -static enum rofferr +static int roff_EN(ROFF_ARGS) { if (r->eqn != NULL) { eqn_parse(r->eqn); r->eqn = NULL; } else - mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse, ln, ppos, "EN"); + mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "EN"); if (buf->buf[pos] != '\0') - mandoc_vmsg(MANDOCERR_ARG_SKIP, r->parse, ln, pos, + mandoc_msg(MANDOCERR_ARG_SKIP, ln, pos, "EN %s", buf->buf + pos); return ROFF_IGN; } -static enum rofferr +static int roff_TS(ROFF_ARGS) { if (r->tbl != NULL) { - mandoc_msg(MANDOCERR_BLK_BROKEN, r->parse, - ln, ppos, "TS breaks TS"); - tbl_end(r->tbl); + mandoc_msg(MANDOCERR_BLK_BROKEN, ln, ppos, "TS breaks TS"); + tbl_end(r->tbl, 0); } - r->tbl = tbl_alloc(ppos, ln, r->parse); - if (r->last_tbl) - r->last_tbl->next = r->tbl; - else + r->man->flags |= ROFF_NONOFILL; + r->tbl = tbl_alloc(ppos, ln, r->last_tbl); + if (r->last_tbl == NULL) r->first_tbl = r->tbl; r->last_tbl = r->tbl; return ROFF_IGN; } -static enum rofferr +static int +roff_noarg(ROFF_ARGS) +{ + if (r->man->flags & (MAN_BLINE | MAN_ELINE)) + man_breakscope(r->man, tok); + if (tok == ROFF_brp) + tok = ROFF_br; + roff_elem_alloc(r->man, ln, ppos, tok); + if (buf->buf[pos] != '\0') + mandoc_msg(MANDOCERR_ARG_SKIP, ln, pos, + "%s %s", roff_name[tok], buf->buf + pos); + if (tok == ROFF_nf) + r->man->flags |= ROFF_NOFILL; + else if (tok == ROFF_fi) + r->man->flags &= ~ROFF_NOFILL; + r->man->last->flags |= NODE_LINE | NODE_VALID | NODE_ENDED; + r->man->next = ROFF_NEXT_SIBLING; + return ROFF_IGN; +} + +static int roff_onearg(ROFF_ARGS) { struct roff_node *n; @@ -3019,8 +3399,8 @@ roff_onearg(ROFF_ARGS) while (*cp == ' ') *cp++ = '\0'; if (*cp != '\0') - mandoc_vmsg(MANDOCERR_ARG_EXCESS, - r->parse, ln, cp - buf->buf, + mandoc_msg(MANDOCERR_ARG_EXCESS, + ln, (int)(cp - buf->buf), "%s ... %s", roff_name[tok], cp); roff_word_alloc(r->man, ln, pos, buf->buf + pos); } @@ -3033,8 +3413,8 @@ roff_onearg(ROFF_ARGS) npos = 0; if (roff_evalnum(r, ln, r->man->last->string, &npos, &roffce_lines, 0) == 0) { - mandoc_vmsg(MANDOCERR_CE_NONUM, - r->parse, ln, pos, "ce %s", buf->buf + pos); + mandoc_msg(MANDOCERR_CE_NONUM, + ln, pos, "ce %s", buf->buf + pos); roffce_lines = 1; } if (roffce_lines < 1) { @@ -3052,7 +3432,7 @@ roff_onearg(ROFF_ARGS) return ROFF_IGN; } -static enum rofferr +static int roff_manyarg(ROFF_ARGS) { struct roff_node *n; @@ -3075,7 +3455,7 @@ roff_manyarg(ROFF_ARGS) return ROFF_IGN; } -static enum rofferr +static int roff_als(ROFF_ARGS) { char *oldn, *newn, *end, *value; @@ -3086,7 +3466,7 @@ roff_als(ROFF_ARGS) return ROFF_IGN; newsz = roff_getname(r, &oldn, ln, pos); - if (newn[newsz] == '\\' || *oldn == '\0') + if (newn[newsz] == '\\' || newn[newsz] == '\t' || *oldn == '\0') return ROFF_IGN; end = oldn; @@ -3094,7 +3474,7 @@ roff_als(ROFF_ARGS) if (oldsz == 0) return ROFF_IGN; - valsz = mandoc_asprintf(&value, ".%.*s \\$*\\\"\n", + valsz = mandoc_asprintf(&value, ".%.*s \\$@\\\"\n", (int)oldsz, oldn); roff_setstrn(&r->strtab, newn, newsz, value, valsz, 0); roff_setstrn(&r->rentab, newn, newsz, NULL, 0, 0); @@ -3102,21 +3482,7 @@ roff_als(ROFF_ARGS) return ROFF_IGN; } -static enum rofferr -roff_br(ROFF_ARGS) -{ - if (r->man->flags & (MAN_BLINE | MAN_ELINE)) - man_breakscope(r->man, ROFF_br); - roff_elem_alloc(r->man, ln, ppos, ROFF_br); - if (buf->buf[pos] != '\0') - mandoc_vmsg(MANDOCERR_ARG_SKIP, r->parse, ln, pos, - "%s %s", roff_name[tok], buf->buf + pos); - r->man->last->flags |= NODE_LINE | NODE_VALID | NODE_ENDED; - r->man->next = ROFF_NEXT_SIBLING; - return ROFF_IGN; -} - -static enum rofferr +static int roff_cc(ROFF_ARGS) { const char *p; @@ -3127,13 +3493,83 @@ roff_cc(ROFF_ARGS) r->control = '\0'; if (*p != '\0') - mandoc_vmsg(MANDOCERR_ARG_EXCESS, r->parse, + mandoc_msg(MANDOCERR_ARG_EXCESS, ln, p - buf->buf, "cc ... %s", p); return ROFF_IGN; } -static enum rofferr +static int +roff_char(ROFF_ARGS) +{ + const char *p, *kp, *vp; + size_t ksz, vsz; + int font; + + /* Parse the character to be replaced. */ + + kp = buf->buf + pos; + p = kp + 1; + if (*kp == '\0' || (*kp == '\\' && + mandoc_escape(&p, NULL, NULL) != ESCAPE_SPECIAL) || + (*p != ' ' && *p != '\0')) { + mandoc_msg(MANDOCERR_CHAR_ARG, ln, pos, "char %s", kp); + return ROFF_IGN; + } + ksz = p - kp; + while (*p == ' ') + p++; + + /* + * If the replacement string contains a font escape sequence, + * we have to restore the font at the end. + */ + + vp = p; + vsz = strlen(p); + font = 0; + while (*p != '\0') { + if (*p++ != '\\') + continue; + switch (mandoc_escape(&p, NULL, NULL)) { + case ESCAPE_FONT: + case ESCAPE_FONTROMAN: + case ESCAPE_FONTITALIC: + case ESCAPE_FONTBOLD: + case ESCAPE_FONTBI: + case ESCAPE_FONTCW: + case ESCAPE_FONTPREV: + font++; + break; + default: + break; + } + } + if (font > 1) + mandoc_msg(MANDOCERR_CHAR_FONT, + ln, (int)(vp - buf->buf), "%s", vp); + + /* + * Approximate the effect of .char using the .tr tables. + * XXX In groff, .char and .tr interact differently. + */ + + if (ksz == 1) { + if (r->xtab == NULL) + r->xtab = mandoc_calloc(128, sizeof(*r->xtab)); + assert((unsigned int)*kp < 128); + free(r->xtab[(int)*kp].p); + r->xtab[(int)*kp].sz = mandoc_asprintf(&r->xtab[(int)*kp].p, + "%s%s", vp, font ? "\fP" : ""); + } else { + roff_setstrn(&r->xmbtab, kp, ksz, vp, vsz, 0); + if (font) + roff_setstrn(&r->xmbtab, kp, ksz, "\\fP", 3, 1); + } + return ROFF_IGN; +} + +static int roff_ec(ROFF_ARGS) { const char *p; @@ -3144,23 +3580,32 @@ roff_ec(ROFF_ARGS) else { r->escape = *p; if (*++p != '\0') - mandoc_vmsg(MANDOCERR_ARG_EXCESS, r->parse, - ln, p - buf->buf, "ec ... %s", p); + mandoc_msg(MANDOCERR_ARG_EXCESS, ln, + (int)(p - buf->buf), "ec ... %s", p); } return ROFF_IGN; } -static enum rofferr +static int roff_eo(ROFF_ARGS) { r->escape = '\0'; if (buf->buf[pos] != '\0') - mandoc_vmsg(MANDOCERR_ARG_SKIP, r->parse, + mandoc_msg(MANDOCERR_ARG_SKIP, ln, pos, "eo %s", buf->buf + pos); return ROFF_IGN; } -static enum rofferr +static int +roff_nop(ROFF_ARGS) +{ + while (buf->buf[pos] == ' ') + pos++; + *offs = pos; + return ROFF_RERUN; +} + +static int roff_tr(ROFF_ARGS) { const char *p, *first, *second; @@ -3170,7 +3615,7 @@ roff_tr(ROFF_ARGS) p = buf->buf + pos; if (*p == '\0') { - mandoc_msg(MANDOCERR_REQ_EMPTY, r->parse, ln, ppos, "tr"); + mandoc_msg(MANDOCERR_REQ_EMPTY, ln, ppos, "tr"); return ROFF_IGN; } @@ -3181,8 +3626,8 @@ roff_tr(ROFF_ARGS) if (*first == '\\') { esc = mandoc_escape(&p, NULL, NULL); if (esc == ESCAPE_ERROR) { - mandoc_msg(MANDOCERR_ESC_BAD, r->parse, - ln, (int)(p - buf->buf), first); + mandoc_msg(MANDOCERR_ESC_BAD, ln, + (int)(p - buf->buf), "%s", first); return ROFF_IGN; } fsz = (size_t)(p - first); @@ -3192,14 +3637,14 @@ roff_tr(ROFF_ARGS) if (*second == '\\') { esc = mandoc_escape(&p, NULL, NULL); if (esc == ESCAPE_ERROR) { - mandoc_msg(MANDOCERR_ESC_BAD, r->parse, - ln, (int)(p - buf->buf), second); + mandoc_msg(MANDOCERR_ESC_BAD, ln, + (int)(p - buf->buf), "%s", second); return ROFF_IGN; } ssz = (size_t)(p - second); } else if (*second == '\0') { - mandoc_vmsg(MANDOCERR_TR_ODD, r->parse, - ln, first - buf->buf, "tr %s", first); + mandoc_msg(MANDOCERR_TR_ODD, ln, + (int)(first - buf->buf), "tr %s", first); second = " "; p--; } @@ -3222,7 +3667,23 @@ roff_tr(ROFF_ARGS) return ROFF_IGN; } -static enum rofferr +/* + * Implementation of the .return request. + * There is no need to call roff_userret() from here. + * The read module will call that after rewinding the reader stack + * to the place from where the current macro was called. + */ +static int +roff_return(ROFF_ARGS) +{ + if (r->mstackpos >= 0) + return ROFF_IGN | ROFF_USERRET; + + mandoc_msg(MANDOCERR_REQ_NOMAC, ln, ppos, "return"); + return ROFF_IGN; +} + +static int roff_rn(ROFF_ARGS) { const char *value; @@ -3235,7 +3696,7 @@ roff_rn(ROFF_ARGS) return ROFF_IGN; oldsz = roff_getname(r, &newn, ln, pos); - if (oldn[oldsz] == '\\' || *newn == '\0') + if (oldn[oldsz] == '\\' || oldn[oldsz] == '\t' || *newn == '\0') return ROFF_IGN; end = newn; @@ -3272,13 +3733,46 @@ roff_rn(ROFF_ARGS) return ROFF_IGN; } -static enum rofferr +static int +roff_shift(ROFF_ARGS) +{ + struct mctx *ctx; + int levels, i; + + levels = 1; + if (buf->buf[pos] != '\0' && + roff_evalnum(r, ln, buf->buf, &pos, &levels, 0) == 0) { + mandoc_msg(MANDOCERR_CE_NONUM, + ln, pos, "shift %s", buf->buf + pos); + levels = 1; + } + if (r->mstackpos < 0) { + mandoc_msg(MANDOCERR_REQ_NOMAC, ln, ppos, "shift"); + return ROFF_IGN; + } + ctx = r->mstack + r->mstackpos; + if (levels > ctx->argc) { + mandoc_msg(MANDOCERR_SHIFT, + ln, pos, "%d, but max is %d", levels, ctx->argc); + levels = ctx->argc; + } + if (levels == 0) + return ROFF_IGN; + for (i = 0; i < levels; i++) + free(ctx->argv[i]); + ctx->argc -= levels; + for (i = 0; i < ctx->argc; i++) + ctx->argv[i] = ctx->argv[i + levels]; + return ROFF_IGN; +} + +static int roff_so(ROFF_ARGS) { char *name, *cp; name = buf->buf + pos; - mandoc_vmsg(MANDOCERR_SO, r->parse, ln, ppos, "so %s", name); + mandoc_msg(MANDOCERR_SO, ln, ppos, "so %s", name); /* * Handle `so'. Be EXTREMELY careful, as we shouldn't be @@ -3288,8 +3782,7 @@ roff_so(ROFF_ARGS) */ if (*name == '/' || strstr(name, "../") || strstr(name, "/..")) { - mandoc_vmsg(MANDOCERR_SO_PATH, r->parse, ln, ppos, - ".so %s", name); + mandoc_msg(MANDOCERR_SO_PATH, ln, ppos, ".so %s", name); buf->sz = mandoc_asprintf(&cp, ".sp\nSee the file %s.\n.sp", name) + 1; free(buf->buf); @@ -3304,154 +3797,69 @@ roff_so(ROFF_ARGS) /* --- user defined strings and macros ------------------------------------ */ -static enum rofferr +static int roff_userdef(ROFF_ARGS) { - const char *arg[16], *ap; - char *cp, *n1, *n2; - int expand_count, i, ib, ie; - size_t asz, rsz; + struct mctx *ctx; + char *arg, *ap, *dst, *src; + size_t sz; - /* - * Collect pointers to macro argument strings - * and NUL-terminate them. - */ + /* Initialize a new macro stack context. */ - r->argc = 0; - cp = buf->buf + pos; - for (i = 0; i < 16; i++) { - if (*cp == '\0') - arg[i] = ""; - else { - arg[i] = mandoc_getarg(r->parse, &cp, ln, &pos); - r->argc = i + 1; - } + if (++r->mstackpos == r->mstacksz) { + r->mstack = mandoc_recallocarray(r->mstack, + r->mstacksz, r->mstacksz + 8, sizeof(*r->mstack)); + r->mstacksz += 8; } + ctx = r->mstack + r->mstackpos; + ctx->argsz = 0; + ctx->argc = 0; + ctx->argv = NULL; /* - * Expand macro arguments. + * Collect pointers to macro argument strings, + * NUL-terminating them and escaping quotes. */ - buf->sz = strlen(r->current_string) + 1; - n1 = n2 = cp = mandoc_malloc(buf->sz); - memcpy(n1, r->current_string, buf->sz); - expand_count = 0; - while (*cp != '\0') { - - /* Scan ahead for the next argument invocation. */ - - if (*cp++ != '\\') - continue; - if (*cp++ != '$') - continue; - if (*cp == '*') { /* \\$* inserts all arguments */ - ib = 0; - ie = r->argc - 1; - } else { /* \\$1 .. \\$9 insert one argument */ - ib = ie = *cp - '1'; - if (ib < 0 || ib > 8) - continue; - } - cp -= 2; - - /* - * Prevent infinite recursion. - */ - - if (cp >= n2) - expand_count = 1; - else if (++expand_count > EXPAND_LIMIT) { - mandoc_msg(MANDOCERR_ROFFLOOP, r->parse, - ln, (int)(cp - n1), NULL); - free(buf->buf); - buf->buf = n1; - *offs = 0; - return ROFF_IGN; - } - - /* - * Determine the size of the expanded argument, - * taking escaping of quotes into account. - */ - - asz = ie > ib ? ie - ib : 0; /* for blanks */ - for (i = ib; i <= ie; i++) { - for (ap = arg[i]; *ap != '\0'; ap++) { - asz++; - if (*ap == '"') - asz += 3; - } - } - if (asz != 3) { - - /* - * Determine the size of the rest of the - * unexpanded macro, including the NUL. - */ - - rsz = buf->sz - (cp - n1) - 3; - - /* - * When shrinking, move before - * releasing the storage. - */ - - if (asz < 3) - memmove(cp + asz, cp + 3, rsz); - - /* - * Resize the storage for the macro - * and readjust the parse pointer. - */ - - buf->sz += asz - 3; - n2 = mandoc_realloc(n1, buf->sz); - cp = n2 + (cp - n1); - n1 = n2; - - /* - * When growing, make room - * for the expanded argument. - */ - - if (asz > 3) - memmove(cp + asz, cp + 3, rsz); + src = buf->buf + pos; + while (*src != '\0') { + if (ctx->argc == ctx->argsz) { + ctx->argsz += 8; + ctx->argv = mandoc_reallocarray(ctx->argv, + ctx->argsz, sizeof(*ctx->argv)); } - - /* Copy the expanded argument, escaping quotes. */ - - n2 = cp; - for (i = ib; i <= ie; i++) { - for (ap = arg[i]; *ap != '\0'; ap++) { - if (*ap == '"') { - memcpy(n2, "\\(dq", 4); - n2 += 4; - } else - *n2++ = *ap; - } - if (i < ie) - *n2++ = ' '; + arg = roff_getarg(r, &src, ln, &pos); + sz = 1; /* For the terminating NUL. */ + for (ap = arg; *ap != '\0'; ap++) + sz += *ap == '"' ? 4 : 1; + ctx->argv[ctx->argc++] = dst = mandoc_malloc(sz); + for (ap = arg; *ap != '\0'; ap++) { + if (*ap == '"') { + memcpy(dst, "\\(dq", 4); + dst += 4; + } else + *dst++ = *ap; } + *dst = '\0'; + free(arg); } - /* - * Replace the macro invocation - * by the expanded macro. - */ + /* Replace the macro invocation by the macro definition. */ free(buf->buf); - buf->buf = n1; + buf->buf = mandoc_strdup(r->current_string); + buf->sz = strlen(buf->buf) + 1; *offs = 0; return buf->sz > 1 && buf->buf[buf->sz - 2] == '\n' ? - ROFF_REPARSE : ROFF_APPEND; + ROFF_REPARSE | ROFF_USERCALL : ROFF_IGN | ROFF_APPEND; } /* * Calling a high-level macro that was renamed with .rn. * r->current_string has already been set up by roff_parse(). */ -static enum rofferr +static int roff_renamed(ROFF_ARGS) { char *nbuf; @@ -3464,6 +3872,10 @@ roff_renamed(ROFF_ARGS) return ROFF_CONT; } +/* + * Measure the length in bytes of the roff identifier at *cpp + * and advance the pointer to the next word. + */ static size_t roff_getname(struct roff *r, char **cpp, int ln, int pos) { @@ -3471,31 +3883,34 @@ roff_getname(struct roff *r, char **cpp, int ln, int pos) size_t namesz; name = *cpp; - if ('\0' == *name) + if (*name == '\0') return 0; - /* Read until end of name and terminate it with NUL. */ + /* Advance cp to the byte after the end of the name. */ + for (cp = name; 1; cp++) { - if ('\0' == *cp || ' ' == *cp) { - namesz = cp - name; + namesz = cp - name; + if (*cp == '\0') + break; + if (*cp == ' ' || *cp == '\t') { + cp++; break; } - if ('\\' != *cp) + if (*cp != '\\') continue; - namesz = cp - name; - if ('{' == cp[1] || '}' == cp[1]) + if (cp[1] == '{' || cp[1] == '}') break; - cp++; - if ('\\' == *cp) + if (*++cp == '\\') continue; - mandoc_vmsg(MANDOCERR_NAMESC, r->parse, ln, pos, + mandoc_msg(MANDOCERR_NAMESC, ln, pos, "%.*s", (int)(cp - name + 1), name); mandoc_escape((const char **)&cp, NULL, NULL); break; } /* Read past spaces. */ - while (' ' == *cp) + + while (*cp == ' ') cp++; *cpp = cp; @@ -3638,7 +4053,7 @@ roff_getstrn(struct roff *r, const char *name, size_t len, break; } } - if (r->man->macroset != MACROSET_MAN) { + if (r->man->meta.macroset != MACROSET_MAN) { for (tok = MDOC_Dd; tok < MDOC_MAX; tok++) { if (strncmp(name, roff_name[tok], len) != 0 || roff_name[tok][len] != '\0') @@ -3652,7 +4067,7 @@ roff_getstrn(struct roff *r, const char *name, size_t len, } } } - if (r->man->macroset != MACROSET_MDOC) { + if (r->man->meta.macroset != MACROSET_MDOC) { for (tok = MAN_TH; tok < MAN_MAX; tok++) { if (strncmp(name, roff_name[tok], len) != 0 || roff_name[tok][len] != '\0') @@ -3783,7 +4198,7 @@ roff_strdup(const struct roff *r, const char *p) /* * We bail out on bad escapes. * No need to warn: we already did so when - * roff_res() was called. + * roff_expand() was called. */ sz = (int)(p - pp); res = mandoc_realloc(res, ssz + sz + 1); diff --git a/usr/src/cmd/mandoc/roff.h b/usr/src/cmd/mandoc/roff.h index f0da74bd9a..49b0927513 100644 --- a/usr/src/cmd/mandoc/roff.h +++ b/usr/src/cmd/mandoc/roff.h @@ -1,7 +1,7 @@ -/* $Id: roff.h,v 1.59 2018/04/11 17:11:13 schwarze Exp $ */ +/* $Id: roff.h,v 1.69 2019/03/04 13:01:57 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2013-2015, 2017-2019 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 @@ -14,11 +14,15 @@ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Common data types for all syntax trees and related functions. */ struct ohash; struct mdoc_arg; union mdoc_data; +struct tbl_span; +struct eqn_box; enum roff_macroset { MACROSET_NONE = 0, @@ -69,9 +73,11 @@ enum roff_type { enum roff_tok { ROFF_br = 0, ROFF_ce, + ROFF_fi, ROFF_ft, ROFF_ll, ROFF_mc, + ROFF_nf, ROFF_po, ROFF_rj, ROFF_sp, @@ -156,7 +162,6 @@ enum roff_tok { ROFF_fcolor, ROFF_fdeferlig, ROFF_feature, - /* MAN_fi; ignored in mdoc(7) */ ROFF_fkern, ROFF_fl, ROFF_flig, @@ -216,7 +221,6 @@ enum roff_tok { ROFF_mso, ROFF_na, ROFF_ne, - /* MAN_nf; ignored in mdoc(7) */ ROFF_nh, ROFF_nhychar, ROFF_nm, @@ -438,6 +442,7 @@ enum roff_tok { MAN_SH, MAN_SS, MAN_TP, + MAN_TQ, MAN_LP, MAN_PP, MAN_P, @@ -454,8 +459,6 @@ enum roff_tok { MAN_I, MAN_IR, MAN_RI, - MAN_nf, - MAN_fi, MAN_RE, MAN_RS, MAN_DT, @@ -463,6 +466,8 @@ enum roff_tok { MAN_PD, MAN_AT, MAN_in, + MAN_SY, + MAN_YS, MAN_OP, MAN_EX, MAN_EE, @@ -473,11 +478,6 @@ enum roff_tok { MAN_MAX }; -enum roff_next { - ROFF_NEXT_SIBLING = 0, - ROFF_NEXT_CHILD -}; - /* * Indicates that a BODY's formatting has ended, but * the scope is still open. Used for badly nested blocks. @@ -487,6 +487,12 @@ enum mdoc_endbody { ENDBODY_SPACE /* Is broken: append a space. */ }; +enum mandoc_os { + MANDOC_OS_OTHER = 0, + MANDOC_OS_NETBSD, + MANDOC_OS_OPENBSD +}; + struct roff_node { struct roff_node *parent; /* Parent AST node. */ struct roff_node *child; /* First child AST node. */ @@ -499,21 +505,22 @@ struct roff_node { struct mdoc_arg *args; /* BLOCK/ELEM */ union mdoc_data *norm; /* Normalized arguments. */ char *string; /* TEXT */ - const struct tbl_span *span; /* TBL */ + struct tbl_span *span; /* TBL */ struct eqn_box *eqn; /* EQN */ int line; /* Input file line number. */ int pos; /* Input file column number. */ int flags; #define NODE_VALID (1 << 0) /* Has been validated. */ #define NODE_ENDED (1 << 1) /* Gone past body end mark. */ -#define NODE_EOS (1 << 2) /* At sentence boundary. */ +#define NODE_BROKEN (1 << 2) /* Must validate parent when ending. */ #define NODE_LINE (1 << 3) /* First macro/text on line. */ -#define NODE_SYNPRETTY (1 << 4) /* SYNOPSIS-style formatting. */ -#define NODE_BROKEN (1 << 5) /* Must validate parent when ending. */ -#define NODE_DELIMO (1 << 6) -#define NODE_DELIMC (1 << 7) -#define NODE_NOSRC (1 << 8) /* Generated node, not in input file. */ -#define NODE_NOPRT (1 << 9) /* Shall not print anything. */ +#define NODE_DELIMO (1 << 4) +#define NODE_DELIMC (1 << 5) +#define NODE_EOS (1 << 6) /* At sentence boundary. */ +#define NODE_SYNPRETTY (1 << 7) /* SYNOPSIS-style formatting. */ +#define NODE_NOFILL (1 << 8) /* Fill mode switched off. */ +#define NODE_NOSRC (1 << 9) /* Generated node, not in input file. */ +#define NODE_NOPRT (1 << 10) /* Shall not print anything. */ int prev_font; /* Before entering this node. */ int aux; /* Decoded node data, type-dependent. */ enum roff_tok tok; /* Request or macro ID. */ @@ -523,6 +530,7 @@ struct roff_node { }; struct roff_meta { + struct roff_node *first; /* The first node parsed. */ char *msec; /* Manual section, usually a digit. */ char *vol; /* Manual volume title. */ char *os; /* Operating system. */ @@ -530,51 +538,15 @@ struct roff_meta { char *title; /* Manual title, usually CAPS. */ char *name; /* Leading manual name. */ char *date; /* Normalized date. */ + char *sodest; /* .so target file name or NULL. */ int hasbody; /* Document is not empty. */ int rcsids; /* Bits indexed by enum mandoc_os. */ enum mandoc_os os_e; /* Operating system. */ -}; - -struct roff_man { - struct roff_meta meta; /* Document meta-data. */ - struct mparse *parse; /* Parse pointer. */ - struct roff *roff; /* Roff parser state data. */ - struct ohash *mdocmac; /* Mdoc macro lookup table. */ - struct ohash *manmac; /* Man macro lookup table. */ - const char *os_s; /* Default operating system. */ - struct roff_node *first; /* The first node parsed. */ - struct roff_node *last; /* The last node parsed. */ - struct roff_node *last_es; /* The most recent Es node. */ - int quick; /* Abort parse early. */ - int flags; /* Parse flags. */ -#define MDOC_LITERAL (1 << 1) /* In a literal scope. */ -#define MDOC_PBODY (1 << 2) /* In the document body. */ -#define MDOC_NEWLINE (1 << 3) /* First macro/text in a line. */ -#define MDOC_PHRASE (1 << 4) /* In a Bl -column phrase. */ -#define MDOC_PHRASELIT (1 << 5) /* Literal within a phrase. */ -#define MDOC_FREECOL (1 << 6) /* `It' invocation should close. */ -#define MDOC_SYNOPSIS (1 << 7) /* SYNOPSIS-style formatting. */ -#define MDOC_KEEP (1 << 8) /* In a word keep. */ -#define MDOC_SMOFF (1 << 9) /* Spacing is off. */ -#define MDOC_NODELIMC (1 << 10) /* Disable closing delimiter handling. */ -#define MAN_ELINE (1 << 11) /* Next-line element scope. */ -#define MAN_BLINE (1 << 12) /* Next-line block scope. */ -#define MDOC_PHRASEQF (1 << 13) /* Quote first word encountered. */ -#define MDOC_PHRASEQL (1 << 14) /* Quote last word of this phrase. */ -#define MDOC_PHRASEQN (1 << 15) /* Quote first word of the next phrase. */ -#define MAN_LITERAL MDOC_LITERAL -#define MAN_NEWLINE MDOC_NEWLINE enum roff_macroset macroset; /* Kind of high-level macros used. */ - enum roff_sec lastsec; /* Last section seen. */ - enum roff_sec lastnamed; /* Last standard section seen. */ - enum roff_next next; /* Where to put the next node. */ }; extern const char *const *roff_name; +int arch_valid(const char *, enum mandoc_os); void deroff(char **, const struct roff_node *); -struct ohash *roffhash_alloc(enum roff_tok, enum roff_tok); -enum roff_tok roffhash_find(struct ohash *, const char *, size_t); -void roffhash_free(struct ohash *); -void roff_validate(struct roff_man *); diff --git a/usr/src/cmd/mandoc/roff_html.c b/usr/src/cmd/mandoc/roff_html.c index 6a06c0d878..02b8beea3b 100644 --- a/usr/src/cmd/mandoc/roff_html.c +++ b/usr/src/cmd/mandoc/roff_html.c @@ -1,7 +1,7 @@ -/* $Id: roff_html.c,v 1.12 2018/06/25 14:53:58 schwarze Exp $ */ +/* $Id: roff_html.c,v 1.19 2019/01/07 07:26:29 schwarze Exp $ */ /* * Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2014, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2014, 2017, 2018, 2019 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 @@ -18,7 +18,8 @@ #include <sys/types.h> #include <assert.h> -#include <stddef.h> +#include <stdio.h> +#include <string.h> #include "mandoc.h" #include "roff.h" @@ -31,14 +32,19 @@ typedef void (*roff_html_pre_fp)(ROFF_HTML_ARGS); static void roff_html_pre_br(ROFF_HTML_ARGS); static void roff_html_pre_ce(ROFF_HTML_ARGS); +static void roff_html_pre_fi(ROFF_HTML_ARGS); +static void roff_html_pre_ft(ROFF_HTML_ARGS); +static void roff_html_pre_nf(ROFF_HTML_ARGS); static void roff_html_pre_sp(ROFF_HTML_ARGS); static const roff_html_pre_fp roff_html_pre_acts[ROFF_MAX] = { roff_html_pre_br, /* br */ roff_html_pre_ce, /* ce */ - NULL, /* ft */ + roff_html_pre_fi, /* fi */ + roff_html_pre_ft, /* ft */ NULL, /* ll */ NULL, /* mc */ + roff_html_pre_nf, /* nf */ NULL, /* po */ roff_html_pre_ce, /* rj */ roff_html_pre_sp, /* sp */ @@ -58,11 +64,7 @@ roff_html_pre(struct html *h, const struct roff_node *n) static void roff_html_pre_br(ROFF_HTML_ARGS) { - struct tag *t; - - t = print_otag(h, TAG_DIV, ""); - print_text(h, "\\~"); /* So the div isn't empty. */ - print_tagq(h, t); + print_otag(h, TAG_BR, ""); } static void @@ -80,7 +82,36 @@ roff_html_pre_ce(ROFF_HTML_ARGS) } static void +roff_html_pre_fi(ROFF_HTML_ARGS) +{ + if (html_fillmode(h, TOKEN_NONE) == ROFF_fi) + print_otag(h, TAG_BR, ""); +} + +static void +roff_html_pre_ft(ROFF_HTML_ARGS) +{ + const char *cp; + + cp = n->child->string; + print_metaf(h, mandoc_font(cp, (int)strlen(cp))); +} + +static void +roff_html_pre_nf(ROFF_HTML_ARGS) +{ + if (html_fillmode(h, TOKEN_NONE) == ROFF_nf) + print_otag(h, TAG_BR, ""); +} + +static void roff_html_pre_sp(ROFF_HTML_ARGS) { - print_paragraph(h); + if (html_fillmode(h, TOKEN_NONE) == ROFF_nf) { + h->col++; + print_endline(h); + } else { + html_close_paragraph(h); + print_otag(h, TAG_P, "c", "Pp"); + } } diff --git a/usr/src/cmd/mandoc/roff_int.h b/usr/src/cmd/mandoc/roff_int.h index 48996dce53..d033f86ace 100644 --- a/usr/src/cmd/mandoc/roff_int.h +++ b/usr/src/cmd/mandoc/roff_int.h @@ -1,7 +1,7 @@ -/* $Id: roff_int.h,v 1.9 2017/07/08 17:52:50 schwarze Exp $ */ +/* $Id: roff_int.h,v 1.16 2019/01/05 00:36:50 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2013-2015, 2017-2019 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 @@ -14,8 +14,54 @@ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Parser internals shared by multiple parsers. */ +struct ohash; +struct roff_node; +struct roff_meta; +struct roff; +struct mdoc_arg; + +enum roff_next { + ROFF_NEXT_SIBLING = 0, + ROFF_NEXT_CHILD +}; + +struct roff_man { + struct roff_meta meta; /* Public parse results. */ + struct roff *roff; /* Roff parser state data. */ + struct ohash *mdocmac; /* Mdoc macro lookup table. */ + struct ohash *manmac; /* Man macro lookup table. */ + const char *os_s; /* Default operating system. */ + struct roff_node *last; /* The last node parsed. */ + struct roff_node *last_es; /* The most recent Es node. */ + int quick; /* Abort parse early. */ + int flags; /* Parse flags. */ +#define ROFF_NOFILL (1 << 1) /* Fill mode switched off. */ +#define MDOC_PBODY (1 << 2) /* In the document body. */ +#define MDOC_NEWLINE (1 << 3) /* First macro/text in a line. */ +#define MDOC_PHRASE (1 << 4) /* In a Bl -column phrase. */ +#define MDOC_PHRASELIT (1 << 5) /* Literal within a phrase. */ +#define MDOC_FREECOL (1 << 6) /* `It' invocation should close. */ +#define MDOC_SYNOPSIS (1 << 7) /* SYNOPSIS-style formatting. */ +#define MDOC_KEEP (1 << 8) /* In a word keep. */ +#define MDOC_SMOFF (1 << 9) /* Spacing is off. */ +#define MDOC_NODELIMC (1 << 10) /* Disable closing delimiter handling. */ +#define MAN_ELINE (1 << 11) /* Next-line element scope. */ +#define MAN_BLINE (1 << 12) /* Next-line block scope. */ +#define MDOC_PHRASEQF (1 << 13) /* Quote first word encountered. */ +#define MDOC_PHRASEQL (1 << 14) /* Quote last word of this phrase. */ +#define MDOC_PHRASEQN (1 << 15) /* Quote first word of the next phrase. */ +#define ROFF_NONOFILL (1 << 16) /* Temporarily suspend no-fill mode. */ +#define MAN_NEWLINE MDOC_NEWLINE + enum roff_sec lastsec; /* Last section seen. */ + enum roff_sec lastnamed; /* Last standard section seen. */ + enum roff_next next; /* Where to put the next node. */ +}; + + struct roff_node *roff_node_alloc(struct roff_man *, int, int, enum roff_type, int); void roff_node_append(struct roff_man *, struct roff_node *); @@ -26,9 +72,17 @@ struct roff_node *roff_block_alloc(struct roff_man *, int, int, int); struct roff_node *roff_head_alloc(struct roff_man *, int, int, int); struct roff_node *roff_body_alloc(struct roff_man *, int, int, int); void roff_node_unlink(struct roff_man *, struct roff_node *); +void roff_node_relink(struct roff_man *, struct roff_node *); void roff_node_free(struct roff_node *); void roff_node_delete(struct roff_man *, struct roff_node *); +struct ohash *roffhash_alloc(enum roff_tok, enum roff_tok); +enum roff_tok roffhash_find(struct ohash *, const char *, size_t); +void roffhash_free(struct ohash *); + +void roff_state_reset(struct roff_man *); +void roff_validate(struct roff_man *); + /* * Functions called from roff.c need to be declared here, * not in libmdoc.h or libman.h, even if they are specific diff --git a/usr/src/cmd/mandoc/roff_term.c b/usr/src/cmd/mandoc/roff_term.c index b5ec764963..f10bb61d2c 100644 --- a/usr/src/cmd/mandoc/roff_term.c +++ b/usr/src/cmd/mandoc/roff_term.c @@ -1,6 +1,6 @@ -/* $Id: roff_term.c,v 1.14 2017/06/24 14:38:33 schwarze Exp $ */ +/* $Id: roff_term.c,v 1.19 2019/01/04 03:24:33 schwarze Exp $ */ /* - * Copyright (c) 2010, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2010,2014,2015,2017-2019 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,7 +17,8 @@ #include <sys/types.h> #include <assert.h> -#include <stddef.h> +#include <stdio.h> +#include <string.h> #include "mandoc.h" #include "roff.h" @@ -41,9 +42,11 @@ static void roff_term_pre_ti(ROFF_TERM_ARGS); static const roff_term_pre_fp roff_term_pre_acts[ROFF_MAX] = { roff_term_pre_br, /* br */ roff_term_pre_ce, /* ce */ + roff_term_pre_br, /* fi */ roff_term_pre_ft, /* ft */ roff_term_pre_ll, /* ll */ roff_term_pre_mc, /* mc */ + roff_term_pre_br, /* nf */ roff_term_pre_po, /* po */ roff_term_pre_ce, /* rj */ roff_term_pre_sp, /* sp */ @@ -66,7 +69,9 @@ roff_term_pre_br(ROFF_TERM_ARGS) if (p->flags & TERMP_BRIND) { p->tcol->offset = p->tcol->rmargin; p->tcol->rmargin = p->maxrmargin; + p->trailspace = 0; p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); + p->flags |= TERMP_NOSPACE; } } @@ -74,27 +79,16 @@ static void roff_term_pre_ce(ROFF_TERM_ARGS) { const struct roff_node *nc1, *nc2; - size_t len, lm; roff_term_pre_br(p, n); - lm = p->tcol->offset; + p->flags |= n->tok == ROFF_ce ? TERMP_CENTER : TERMP_RIGHT; nc1 = n->child->next; while (nc1 != NULL) { nc2 = nc1; - len = 0; do { - if (nc2->type == ROFFT_TEXT) { - if (len) - len++; - len += term_strlen(p, nc2->string); - } nc2 = nc2->next; } while (nc2 != NULL && (nc2->type != ROFFT_TEXT || (nc2->flags & NODE_LINE) == 0)); - p->tcol->offset = len >= p->tcol->rmargin ? 0 : - lm + len >= p->tcol->rmargin ? p->tcol->rmargin - len : - n->tok == ROFF_rj ? p->tcol->rmargin - len : - (lm + p->tcol->rmargin - len) / 2; while (nc1 != nc2) { if (nc1->type == ROFFT_TEXT) term_word(p, nc1->string); @@ -105,28 +99,30 @@ roff_term_pre_ce(ROFF_TERM_ARGS) p->flags |= TERMP_NOSPACE; term_flushln(p); } - p->tcol->offset = lm; + p->flags &= ~(TERMP_CENTER | TERMP_RIGHT); } static void roff_term_pre_ft(ROFF_TERM_ARGS) { - switch (*n->child->string) { - case '4': - case '3': - case 'B': + const char *cp; + + cp = n->child->string; + switch (mandoc_font(cp, (int)strlen(cp))) { + case ESCAPE_FONTBOLD: term_fontrepl(p, TERMFONT_BOLD); break; - case '2': - case 'I': + case ESCAPE_FONTITALIC: term_fontrepl(p, TERMFONT_UNDER); break; - case 'P': + case ESCAPE_FONTBI: + term_fontrepl(p, TERMFONT_BI); + break; + case ESCAPE_FONTPREV: term_fontlast(p); break; - case '1': - case 'C': - case 'R': + case ESCAPE_FONTROMAN: + case ESCAPE_FONTCW: term_fontrepl(p, TERMFONT_NONE); break; default: diff --git a/usr/src/cmd/mandoc/roff_validate.c b/usr/src/cmd/mandoc/roff_validate.c index 801e931485..9080f28797 100644 --- a/usr/src/cmd/mandoc/roff_validate.c +++ b/usr/src/cmd/mandoc/roff_validate.c @@ -1,6 +1,6 @@ -/* $Id: roff_validate.c,v 1.9 2017/06/14 22:51:25 schwarze Exp $ */ +/* $Id: roff_validate.c,v 1.18 2018/12/31 09:02:37 schwarze Exp $ */ /* - * Copyright (c) 2010, 2017 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2010, 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 @@ -17,7 +17,8 @@ #include <sys/types.h> #include <assert.h> -#include <stddef.h> +#include <stdio.h> +#include <string.h> #include "mandoc.h" #include "roff.h" @@ -28,17 +29,23 @@ typedef void (*roff_valid_fp)(ROFF_VALID_ARGS); +static void roff_valid_br(ROFF_VALID_ARGS); +static void roff_valid_fi(ROFF_VALID_ARGS); static void roff_valid_ft(ROFF_VALID_ARGS); +static void roff_valid_nf(ROFF_VALID_ARGS); +static void roff_valid_sp(ROFF_VALID_ARGS); static const roff_valid_fp roff_valids[ROFF_MAX] = { - NULL, /* br */ + roff_valid_br, /* br */ NULL, /* ce */ + roff_valid_fi, /* fi */ roff_valid_ft, /* ft */ NULL, /* ll */ NULL, /* mc */ + roff_valid_nf, /* nf */ NULL, /* po */ NULL, /* rj */ - NULL, /* sp */ + roff_valid_sp, /* sp */ NULL, /* ta */ NULL, /* ti */ }; @@ -56,9 +63,45 @@ roff_validate(struct roff_man *man) } static void +roff_valid_br(ROFF_VALID_ARGS) +{ + struct roff_node *np; + + if (n->next != NULL && n->next->type == ROFFT_TEXT && + *n->next->string == ' ') { + mandoc_msg(MANDOCERR_PAR_SKIP, n->line, n->pos, + "br before text line with leading blank"); + roff_node_delete(man, n); + return; + } + + if ((np = n->prev) == NULL) + return; + + switch (np->tok) { + case ROFF_br: + case ROFF_sp: + case MDOC_Pp: + mandoc_msg(MANDOCERR_PAR_SKIP, + n->line, n->pos, "br after %s", roff_name[np->tok]); + roff_node_delete(man, n); + break; + default: + break; + } +} + +static void +roff_valid_fi(ROFF_VALID_ARGS) +{ + if ((n->flags & NODE_NOFILL) == 0) + mandoc_msg(MANDOCERR_FI_SKIP, n->line, n->pos, "fi"); +} + +static void roff_valid_ft(ROFF_VALID_ARGS) { - char *cp; + const char *cp; if (n->child == NULL) { man->next = ROFF_NEXT_CHILD; @@ -68,30 +111,39 @@ roff_valid_ft(ROFF_VALID_ARGS) } cp = n->child->string; - switch (*cp) { - case '1': - case '2': - case '3': - case '4': - case 'I': - case 'P': - case 'R': - if (cp[1] == '\0') - return; - break; - case 'B': - if (cp[1] == '\0' || (cp[1] == 'I' && cp[2] == '\0')) - return; + if (mandoc_font(cp, (int)strlen(cp)) != ESCAPE_ERROR) + return; + mandoc_msg(MANDOCERR_FT_BAD, n->line, n->pos, "ft %s", cp); + roff_node_delete(man, n); +} + +static void +roff_valid_nf(ROFF_VALID_ARGS) +{ + if (n->flags & NODE_NOFILL) + mandoc_msg(MANDOCERR_NF_SKIP, n->line, n->pos, "nf"); +} + +static void +roff_valid_sp(ROFF_VALID_ARGS) +{ + struct roff_node *np; + + if ((np = n->prev) == NULL) + return; + + switch (np->tok) { + case ROFF_br: + mandoc_msg(MANDOCERR_PAR_SKIP, + np->line, np->pos, "br before sp"); + roff_node_delete(man, np); break; - case 'C': - if (cp[1] == 'W' && cp[2] == '\0') - return; + case MDOC_Pp: + mandoc_msg(MANDOCERR_PAR_SKIP, + n->line, n->pos, "sp after Pp"); + roff_node_delete(man, n); break; default: break; } - - mandoc_vmsg(MANDOCERR_FT_BAD, man->parse, - n->line, n->pos, "ft %s", cp); - roff_node_delete(man, n); } diff --git a/usr/src/cmd/mandoc/st.c b/usr/src/cmd/mandoc/st.c index d166566ece..c4d86e33fe 100644 --- a/usr/src/cmd/mandoc/st.c +++ b/usr/src/cmd/mandoc/st.c @@ -1,6 +1,6 @@ -/* $Id: st.c,v 1.14 2017/06/24 14:38:33 schwarze Exp $ */ +/* $Id: st.c,v 1.16 2018/12/14 01:18:26 schwarze Exp $ */ /* - * Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2009, 2010 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 @@ -18,11 +18,11 @@ #include <sys/types.h> +#include <stdio.h> #include <string.h> #include "mandoc.h" #include "roff.h" -#include "mdoc.h" #include "libmdoc.h" #define LINE(x, y) \ @@ -31,8 +31,52 @@ const char * mdoc_a2st(const char *p) { - -#include "st.in" +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)") return NULL; } diff --git a/usr/src/cmd/mandoc/st.in b/usr/src/cmd/mandoc/st.in deleted file mode 100644 index 557a70d10d..0000000000 --- a/usr/src/cmd/mandoc/st.in +++ /dev/null @@ -1,76 +0,0 @@ -/* $Id: st.in,v 1.30 2018/04/05 09:17:26 schwarze Exp $ */ -/* - * Copyright (c) 2009, 2010 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 - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/* - * This file defines the .St macro arguments. If you add a new - * standard, make sure that the left-and side corresponds to the .St - * argument (like .St -p1003.1) and the right-hand side corresponds to - * the formatted output string. - * - * Be sure to escape strings. - * The non-breaking blanks prevent ending an output line right before - * a number. Groff prevent line breaks at the same places. - * - * 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("-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)") diff --git a/usr/src/cmd/mandoc/tag.c b/usr/src/cmd/mandoc/tag.c index c0832c4f74..473ea7b6f4 100644 --- a/usr/src/cmd/mandoc/tag.c +++ b/usr/src/cmd/mandoc/tag.c @@ -1,6 +1,6 @@ -/* $Id: tag.c,v 1.19 2018/02/23 16:47:10 schwarze Exp $ */ +/* $Id: tag.c,v 1.21 2018/11/22 11:30:23 schwarze Exp $ */ /* - * Copyright (c) 2015, 2016 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2015, 2016, 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 @@ -18,6 +18,10 @@ #include <sys/types.h> +#if HAVE_ERR +#include <err.h> +#endif +#include <limits.h> #include <signal.h> #include <stddef.h> #include <stdint.h> @@ -121,41 +125,57 @@ fail: /* * Set the line number where a term is defined, - * unless it is already defined at a higher priority. + * unless it is already defined at a lower priority. */ void tag_put(const char *s, int prio, size_t line) { struct tag_entry *entry; + const char *se; size_t len; unsigned int slot; - /* Sanity checks. */ - if (tag_files.tfd <= 0) return; + if (s[0] == '\\' && (s[1] == '&' || s[1] == 'e')) s += 2; - if (*s == '\0' || strchr(s, ' ') != NULL) + + /* + * Skip whitespace and whatever follows it, + * and if there is any, downgrade the priority. + */ + + len = strcspn(s, " \t"); + if (len == 0) return; - slot = ohash_qlookup(&tag_data, s); + se = s + len; + if (*se != '\0') + prio = INT_MAX; + + slot = ohash_qlookupi(&tag_data, s, &se); entry = ohash_find(&tag_data, slot); if (entry == NULL) { /* Build a new entry. */ - len = strlen(s) + 1; - entry = mandoc_malloc(sizeof(*entry) + len); + entry = mandoc_malloc(sizeof(*entry) + len + 1); memcpy(entry->s, s, len); + entry->s[len] = '\0'; entry->lines = NULL; entry->maxlines = entry->nlines = 0; ohash_insert(&tag_data, slot, entry); } else { - /* Handle priority 0 entries. */ + /* + * Lower priority numbers take precedence, + * but 0 is special. + * A tag with priority 0 is only used + * if the tag occurs exactly once. + */ if (prio == 0) { if (entry->prio == 0) @@ -199,6 +219,11 @@ tag_write(void) if (tag_files.tfd <= 0) return; + if (tag_files.tagname != NULL && ohash_find(&tag_data, + ohash_qlookup(&tag_data, tag_files.tagname)) == NULL) { + warnx("%s: no such tag", tag_files.tagname); + tag_files.tagname = NULL; + } stream = fdopen(tag_files.tfd, "w"); entry = ohash_first(&tag_data, &slot); while (entry != NULL) { diff --git a/usr/src/cmd/mandoc/tag.h b/usr/src/cmd/mandoc/tag.h index ab1388d798..bbd40b737e 100644 --- a/usr/src/cmd/mandoc/tag.h +++ b/usr/src/cmd/mandoc/tag.h @@ -1,4 +1,4 @@ -/* $Id: tag.h,v 1.7 2015/11/20 21:59:54 schwarze Exp $ */ +/* $Id: tag.h,v 1.8 2018/11/22 11:30:23 schwarze Exp $ */ /* * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org> * @@ -18,6 +18,7 @@ struct tag_files { char ofn[20]; char tfn[20]; + char *tagname; int ofd; int tfd; pid_t tcpgid; diff --git a/usr/src/cmd/mandoc/tbl.c b/usr/src/cmd/mandoc/tbl.c index 3fb8e52a4c..036a117752 100644 --- a/usr/src/cmd/mandoc/tbl.c +++ b/usr/src/cmd/mandoc/tbl.c @@ -1,4 +1,4 @@ -/* $Id: tbl.c,v 1.42 2017/07/08 17:52:50 schwarze Exp $ */ +/* $Id: tbl.c,v 1.46 2018/12/14 06:33:14 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2011, 2015 Ingo Schwarze <schwarze@openbsd.org> @@ -25,10 +25,12 @@ #include <string.h> #include <time.h> -#include "mandoc.h" #include "mandoc_aux.h" +#include "mandoc.h" +#include "tbl.h" #include "libmandoc.h" -#include "libroff.h" +#include "tbl_parse.h" +#include "tbl_int.h" void @@ -86,14 +88,15 @@ tbl_read(struct tbl_node *tbl, int ln, const char *p, int pos) } struct tbl_node * -tbl_alloc(int pos, int line, struct mparse *parse) +tbl_alloc(int pos, int line, struct tbl_node *last_tbl) { struct tbl_node *tbl; tbl = mandoc_calloc(1, sizeof(*tbl)); + if (last_tbl != NULL) + last_tbl->next = tbl; tbl->line = line; tbl->pos = pos; - tbl->parse = parse; tbl->part = TBL_PART_OPTS; tbl->opts.tab = '\t'; tbl->opts.decimal = '.'; @@ -103,76 +106,77 @@ tbl_alloc(int pos, int line, struct mparse *parse) void tbl_free(struct tbl_node *tbl) { + struct tbl_node *old_tbl; struct tbl_row *rp; struct tbl_cell *cp; struct tbl_span *sp; struct tbl_dat *dp; - while ((rp = tbl->first_row) != NULL) { - tbl->first_row = rp->next; - while (rp->first != NULL) { - cp = rp->first; - rp->first = cp->next; - free(cp->wstr); - free(cp); + while (tbl != NULL) { + while ((rp = tbl->first_row) != NULL) { + tbl->first_row = rp->next; + while (rp->first != NULL) { + cp = rp->first; + rp->first = cp->next; + free(cp->wstr); + free(cp); + } + free(rp); } - free(rp); - } - - while ((sp = tbl->first_span) != NULL) { - tbl->first_span = sp->next; - while (sp->first != NULL) { - dp = sp->first; - sp->first = dp->next; - free(dp->string); - free(dp); + while ((sp = tbl->first_span) != NULL) { + tbl->first_span = sp->next; + while (sp->first != NULL) { + dp = sp->first; + sp->first = dp->next; + free(dp->string); + free(dp); + } + free(sp); } - free(sp); + old_tbl = tbl; + tbl = tbl->next; + free(old_tbl); } - - free(tbl); } void tbl_restart(int line, int pos, struct tbl_node *tbl) { if (tbl->part == TBL_PART_CDATA) - mandoc_msg(MANDOCERR_TBLDATA_BLK, tbl->parse, - line, pos, "T&"); + mandoc_msg(MANDOCERR_TBLDATA_BLK, line, pos, "T&"); tbl->part = TBL_PART_LAYOUT; tbl->line = line; tbl->pos = pos; } -const struct tbl_span * +struct tbl_span * tbl_span(struct tbl_node *tbl) { struct tbl_span *span; - assert(tbl); span = tbl->current_span ? tbl->current_span->next : tbl->first_span; - if (span) + if (span != NULL) tbl->current_span = span; return span; } int -tbl_end(struct tbl_node *tbl) +tbl_end(struct tbl_node *tbl, int still_open) { struct tbl_span *sp; - if (tbl->part == TBL_PART_CDATA) - mandoc_msg(MANDOCERR_TBLDATA_BLK, tbl->parse, - tbl->line, tbl->pos, "TE"); + if (still_open) + mandoc_msg(MANDOCERR_BLK_NOEND, tbl->line, tbl->pos, "TS"); + else if (tbl->part == TBL_PART_CDATA) + mandoc_msg(MANDOCERR_TBLDATA_BLK, tbl->line, tbl->pos, "TE"); sp = tbl->first_span; while (sp != NULL && sp->first == NULL) sp = sp->next; if (sp == NULL) { - mandoc_msg(MANDOCERR_TBLDATA_NONE, tbl->parse, - tbl->line, tbl->pos, NULL); + mandoc_msg(MANDOCERR_TBLDATA_NONE, tbl->line, tbl->pos, NULL); return 0; } return 1; diff --git a/usr/src/cmd/mandoc/tbl.h b/usr/src/cmd/mandoc/tbl.h new file mode 100644 index 0000000000..365ae929ed --- /dev/null +++ b/usr/src/cmd/mandoc/tbl.h @@ -0,0 +1,122 @@ +/* $Id: tbl.h,v 1.1 2018/12/12 21:54:35 schwarze Exp $ */ +/* + * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * 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 + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +struct tbl_opts { + int opts; +#define TBL_OPT_ALLBOX (1 << 0) /* Option "allbox". */ +#define TBL_OPT_BOX (1 << 1) /* Option "box". */ +#define TBL_OPT_CENTRE (1 << 2) /* Option "center". */ +#define TBL_OPT_DBOX (1 << 3) /* Option "doublebox". */ +#define TBL_OPT_EXPAND (1 << 4) /* Option "expand". */ +#define TBL_OPT_NOKEEP (1 << 5) /* Option "nokeep". */ +#define TBL_OPT_NOSPACE (1 << 6) /* Option "nospaces". */ +#define TBL_OPT_NOWARN (1 << 7) /* Option "nowarn". */ + int cols; /* Number of columns. */ + int lvert; /* Width of left vertical line. */ + int rvert; /* Width of right vertical line. */ + char tab; /* Option "tab": cell separator. */ + char decimal; /* Option "decimalpoint". */ +}; + +enum tbl_cellt { + TBL_CELL_CENTRE, /* c, C */ + TBL_CELL_RIGHT, /* r, R */ + TBL_CELL_LEFT, /* l, L */ + TBL_CELL_NUMBER, /* n, N */ + TBL_CELL_SPAN, /* s, S */ + TBL_CELL_LONG, /* a, A */ + TBL_CELL_DOWN, /* ^ */ + TBL_CELL_HORIZ, /* _, - */ + TBL_CELL_DHORIZ, /* = */ + TBL_CELL_MAX +}; + +/* + * A cell in a layout row. + */ +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. */ + int col; /* Column number, starting from 0. */ + int flags; +#define TBL_CELL_BOLD (1 << 0) /* b, B, fB */ +#define TBL_CELL_ITALIC (1 << 1) /* i, I, fI */ +#define TBL_CELL_TALIGN (1 << 2) /* t, T */ +#define TBL_CELL_UP (1 << 3) /* u, U */ +#define TBL_CELL_BALIGN (1 << 4) /* d, D */ +#define TBL_CELL_WIGN (1 << 5) /* z, Z */ +#define TBL_CELL_EQUAL (1 << 6) /* e, E */ +#define TBL_CELL_WMAX (1 << 7) /* x, X */ + enum tbl_cellt pos; +}; + +/* + * A layout row. + */ +struct tbl_row { + struct tbl_row *next; /* Layout row below. */ + struct tbl_cell *first; /* Leftmost layout cell. */ + struct tbl_cell *last; /* Rightmost layout cell. */ + int vert; /* Width of left vertical line. */ +}; + +enum tbl_datt { + TBL_DATA_NONE, /* Uninitialized row. */ + TBL_DATA_DATA, /* Contains data rather than a line. */ + TBL_DATA_HORIZ, /* _: connecting horizontal line. */ + TBL_DATA_DHORIZ, /* =: connecting double horizontal line. */ + TBL_DATA_NHORIZ, /* \_: isolated horizontal line. */ + TBL_DATA_NDHORIZ /* \=: isolated double horizontal line. */ +}; + +/* + * A cell within a row of data. The "string" field contains the + * actual string value that's in the cell. The rest is layout. + */ +struct tbl_dat { + struct tbl_dat *next; /* Data cell to the right. */ + struct tbl_cell *layout; /* Associated layout cell. */ + char *string; /* Data, or NULL if not TBL_DATA_DATA. */ + int hspans; /* How many horizontal spans follow. */ + int vspans; /* How many vertical spans follow. */ + int block; /* T{ text block T} */ + enum tbl_datt pos; +}; + +enum tbl_spant { + TBL_SPAN_DATA, /* Contains data rather than a line. */ + TBL_SPAN_HORIZ, /* _: horizontal line. */ + TBL_SPAN_DHORIZ /* =: double horizontal line. */ +}; + +/* + * A row of data in a table. + */ +struct tbl_span { + struct tbl_opts *opts; /* Options for the table as a whole. */ + struct tbl_span *prev; /* Data row above. */ + struct tbl_span *next; /* Data row below. */ + struct tbl_row *layout; /* Associated layout row. */ + struct tbl_dat *first; /* Leftmost data cell. */ + struct tbl_dat *last; /* Rightmost data cell. */ + int line; /* Input file line number. */ + enum tbl_spant pos; +}; diff --git a/usr/src/cmd/mandoc/tbl_data.c b/usr/src/cmd/mandoc/tbl_data.c index ae1906ef73..9a58d32562 100644 --- a/usr/src/cmd/mandoc/tbl_data.c +++ b/usr/src/cmd/mandoc/tbl_data.c @@ -1,7 +1,7 @@ -/* $Id: tbl_data.c,v 1.45 2017/07/08 17:52:50 schwarze Exp $ */ +/* $Id: tbl_data.c,v 1.52 2019/02/09 16:00:39 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2011, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2011,2015,2017,2018,2019 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,14 +21,16 @@ #include <assert.h> #include <ctype.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> -#include "mandoc.h" #include "mandoc_aux.h" +#include "mandoc.h" +#include "tbl.h" #include "libmandoc.h" -#include "libroff.h" +#include "tbl_int.h" static void getdata(struct tbl_node *, struct tbl_span *, int, const char *, int *); @@ -40,10 +42,20 @@ static void getdata(struct tbl_node *tbl, struct tbl_span *dp, int ln, const char *p, int *pos) { - struct tbl_dat *dat; + struct tbl_dat *dat, *pdat; struct tbl_cell *cp; + struct tbl_span *pdp; int sv; + /* + * Determine the length of the string in the cell + * and advance the parse point to the end of the cell. + */ + + sv = *pos; + while (p[*pos] != '\0' && p[*pos] != tbl->opts.tab) + (*pos)++; + /* Advance to the next layout cell, skipping spanners. */ cp = dp->last == NULL ? dp->layout->first : dp->last->layout->next; @@ -65,34 +77,68 @@ getdata(struct tbl_node *tbl, struct tbl_span *dp, cp->col = dp->layout->last->col + 1; dp->layout->last = cp; } else { - mandoc_msg(MANDOCERR_TBLDATA_EXTRA, tbl->parse, - ln, *pos, p + *pos); - while (p[*pos]) + mandoc_msg(MANDOCERR_TBLDATA_EXTRA, + ln, sv, "%s", p + sv); + while (p[*pos] != '\0') (*pos)++; return; } } - dat = mandoc_calloc(1, sizeof(*dat)); + dat = mandoc_malloc(sizeof(*dat)); dat->layout = cp; + dat->next = NULL; + dat->string = NULL; + dat->hspans = 0; + dat->vspans = 0; + dat->block = 0; dat->pos = TBL_DATA_NONE; - dat->spans = 0; + + /* + * Increment the number of vertical spans in a data cell above, + * if this cell vertically extends one or more cells above. + * The iteration must be done over data rows, + * not over layout rows, because one layout row + * can be reused for more than one data row. + */ + + if (cp->pos == TBL_CELL_DOWN || + (*pos - sv == 2 && p[sv] == '\\' && p[sv + 1] == '^')) { + pdp = dp; + while ((pdp = pdp->prev) != NULL) { + pdat = pdp->first; + while (pdat != NULL && + pdat->layout->col < dat->layout->col) + pdat = pdat->next; + if (pdat == NULL) + break; + if (pdat->layout->pos != TBL_CELL_DOWN && + strcmp(pdat->string, "\\^") != 0) { + pdat->vspans++; + break; + } + } + } + + /* + * Count the number of horizontal spans to the right of this cell. + * This is purely a matter of the layout, independent of the data. + */ + for (cp = cp->next; cp != NULL; cp = cp->next) if (cp->pos == TBL_CELL_SPAN) - dat->spans++; + dat->hspans++; else break; + /* Append the new data cell to the data row. */ + if (dp->last == NULL) dp->first = dat; else dp->last->next = dat; dp->last = dat; - sv = *pos; - while (p[*pos] && p[*pos] != tbl->opts.tab) - (*pos)++; - /* * Check for a continued-data scope opening. This consists of a * trailing `T{' at the end of the line. Subsequent lines, @@ -106,7 +152,7 @@ getdata(struct tbl_node *tbl, struct tbl_span *dp, dat->string = mandoc_strndup(p + sv, *pos - sv); - if (p[*pos]) + if (p[*pos] != '\0') (*pos)++; if ( ! strcmp(dat->string, "_")) @@ -125,7 +171,7 @@ getdata(struct tbl_node *tbl, struct tbl_span *dp, dat->layout->pos == TBL_CELL_DOWN) && dat->pos == TBL_DATA_DATA && *dat->string != '\0') mandoc_msg(MANDOCERR_TBLDATA_SPAN, - tbl->parse, ln, sv, dat->string); + ln, sv, "%s", dat->string); } void @@ -164,8 +210,8 @@ tbl_cdata(struct tbl_node *tbl, int ln, const char *p, int pos) dat->string = mandoc_strdup(p + pos); if (dat->layout->pos == TBL_CELL_DOWN) - mandoc_msg(MANDOCERR_TBLDATA_SPAN, tbl->parse, - ln, pos, dat->string); + mandoc_msg(MANDOCERR_TBLDATA_SPAN, + ln, pos, "%s", dat->string); } static struct tbl_span * @@ -202,14 +248,27 @@ tbl_data(struct tbl_node *tbl, int ln, const char *p, int pos) assert(rp != NULL); - if ( ! strcmp(p, "_")) { - sp = newspan(tbl, ln, rp); - sp->pos = TBL_SPAN_HORIZ; - return; - } else if ( ! strcmp(p, "=")) { - sp = newspan(tbl, ln, rp); - sp->pos = TBL_SPAN_DHORIZ; - return; + if (p[1] == '\0') { + switch (p[0]) { + case '.': + /* + * Empty request lines must be handled here + * and cannot be discarded in roff_parseln() + * because in the layout section, they + * are significant and end the layout. + */ + return; + case '_': + sp = newspan(tbl, ln, rp); + sp->pos = TBL_SPAN_HORIZ; + return; + case '=': + sp = newspan(tbl, ln, rp); + sp->pos = TBL_SPAN_DHORIZ; + return; + default: + break; + } } /* diff --git a/usr/src/cmd/mandoc/tbl_html.c b/usr/src/cmd/mandoc/tbl_html.c index b87804fda3..4ab6bed10b 100644 --- a/usr/src/cmd/mandoc/tbl_html.c +++ b/usr/src/cmd/mandoc/tbl_html.c @@ -1,7 +1,7 @@ -/* $Id: tbl_html.c,v 1.24 2018/06/25 13:45:57 schwarze Exp $ */ +/* $Id: tbl_html.c,v 1.32 2019/01/06 04:55:09 schwarze Exp $ */ /* * Copyright (c) 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 @@ -25,6 +25,7 @@ #include <string.h> #include "mandoc.h" +#include "tbl.h" #include "out.h" #include "html.h" @@ -79,6 +80,7 @@ html_tbl_sulen(const struct roffsu *su, void *arg) static void html_tblopen(struct html *h, const struct tbl_span *sp) { + html_close_paragraph(h); if (h->tbl.cols == NULL) { h->tbl.len = html_tbl_len; h->tbl.slen = html_tbl_strlen; @@ -86,7 +88,15 @@ html_tblopen(struct html *h, const struct tbl_span *sp) tblcalc(&h->tbl, sp, 0, 0); } assert(NULL == h->tblt); - h->tblt = print_otag(h, TAG_TABLE, "c", "tbl"); + h->tblt = print_otag(h, TAG_TABLE, "c?ss", "tbl", + "border", + sp->opts->opts & TBL_OPT_ALLBOX ? "1" : NULL, + "border-style", + sp->opts->opts & TBL_OPT_DBOX ? "double" : + sp->opts->opts & TBL_OPT_BOX ? "solid" : NULL, + "border-top-style", + sp->pos == TBL_SPAN_DHORIZ ? "double" : + sp->pos == TBL_SPAN_HORIZ ? "solid" : NULL); } void @@ -101,43 +111,138 @@ print_tblclose(struct html *h) void print_tbl(struct html *h, const struct tbl_span *sp) { - const struct tbl_dat *dp; - struct tag *tt; - int ic; - - /* Inhibit printing of spaces: we do padding ourselves. */ + const struct tbl_dat *dp; + const struct tbl_cell *cp; + const struct tbl_span *psp; + struct tag *tt; + const char *hspans, *vspans, *halign, *valign; + const char *bborder, *lborder, *rborder; + char hbuf[4], vbuf[4]; + int i; if (h->tblt == NULL) html_tblopen(h, sp); - assert(h->tblt); + /* + * Horizontal lines spanning the whole table + * are handled by previous or following table rows. + */ + + if (sp->pos != TBL_SPAN_DATA) + return; + + /* Inhibit printing of spaces: we do padding ourselves. */ h->flags |= HTML_NONOSPACE; h->flags |= HTML_NOSPACE; - tt = print_otag(h, TAG_TR, ""); + /* Draw a vertical line left of this row? */ - switch (sp->pos) { - case TBL_SPAN_HORIZ: - case TBL_SPAN_DHORIZ: - print_otag(h, TAG_TD, "?", "colspan", "0"); + switch (sp->layout->vert) { + case 2: + lborder = "double"; + break; + case 1: + lborder = "solid"; break; default: - dp = sp->first; - for (ic = 0; ic < sp->opts->cols; ic++) { - print_stagq(h, tt); - print_otag(h, TAG_TD, ""); - - if (dp == NULL || dp->layout->col > ic) - continue; - if (dp->layout->pos != TBL_CELL_DOWN) - if (dp->string != NULL) - print_text(h, dp->string); - dp = dp->next; - } + lborder = NULL; break; } + /* Draw a horizontal line below this row? */ + + bborder = NULL; + if ((psp = sp->next) != NULL) { + switch (psp->pos) { + case TBL_SPAN_DHORIZ: + bborder = "double"; + break; + case TBL_SPAN_HORIZ: + bborder = "solid"; + break; + default: + break; + } + } + + tt = print_otag(h, TAG_TR, "ss", + "border-left-style", lborder, + "border-bottom-style", bborder); + + for (dp = sp->first; dp != NULL; dp = dp->next) { + print_stagq(h, tt); + + /* + * Do not generate <td> elements for continuations + * of spanned cells. Larger <td> elements covering + * this space were already generated earlier. + */ + + cp = dp->layout; + if (cp->pos == TBL_CELL_SPAN || cp->pos == TBL_CELL_DOWN || + (dp->string != NULL && strcmp(dp->string, "\\^") == 0)) + continue; + + /* Determine the attribute values. */ + + if (dp->hspans > 0) { + (void)snprintf(hbuf, sizeof(hbuf), + "%d", dp->hspans + 1); + hspans = hbuf; + } else + hspans = NULL; + if (dp->vspans > 0) { + (void)snprintf(vbuf, sizeof(vbuf), + "%d", dp->vspans + 1); + vspans = vbuf; + } else + vspans = NULL; + + switch (cp->pos) { + case TBL_CELL_CENTRE: + halign = "center"; + break; + case TBL_CELL_RIGHT: + case TBL_CELL_NUMBER: + halign = "right"; + break; + default: + halign = NULL; + break; + } + if (cp->flags & TBL_CELL_TALIGN) + valign = "top"; + else if (cp->flags & TBL_CELL_BALIGN) + valign = "bottom"; + else + valign = NULL; + + for (i = dp->hspans; i > 0; i--) + cp = cp->next; + switch (cp->vert) { + case 2: + rborder = "double"; + break; + case 1: + rborder = "solid"; + break; + default: + rborder = NULL; + break; + } + + /* Print the element and the attributes. */ + + print_otag(h, TAG_TD, "??sss", + "colspan", hspans, "rowspan", vspans, + "vertical-align", valign, + "text-align", halign, + "border-right-style", rborder); + if (dp->string != NULL) + print_text(h, dp->string); + } + print_tagq(h, tt); h->flags &= ~HTML_NONOSPACE; @@ -148,5 +253,4 @@ print_tbl(struct html *h, const struct tbl_span *sp) h->tbl.cols = NULL; print_tblclose(h); } - } diff --git a/usr/src/cmd/mandoc/tbl_int.h b/usr/src/cmd/mandoc/tbl_int.h new file mode 100644 index 0000000000..fc32910fc7 --- /dev/null +++ b/usr/src/cmd/mandoc/tbl_int.h @@ -0,0 +1,47 @@ +/* $Id: tbl_int.h,v 1.2 2018/12/14 06:33:14 schwarze Exp $ */ +/* + * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2011,2013,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 + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Internal interfaces of the tbl(7) parser. + * For use inside the tbl(7) parser only. + */ + +enum tbl_part { + TBL_PART_OPTS, /* In the first line, ends with semicolon. */ + TBL_PART_LAYOUT, /* In the layout section, ends with full stop. */ + TBL_PART_DATA, /* In the data section, ends with TE. */ + TBL_PART_CDATA /* In a T{ block, ends with T} */ +}; + +struct tbl_node { + struct tbl_opts opts; /* Options for the whole table. */ + struct tbl_node *next; /* Next table. */ + struct tbl_row *first_row; /* First layout row. */ + struct tbl_row *last_row; /* Last layout row. */ + struct tbl_span *first_span; /* First data row. */ + struct tbl_span *current_span; /* Data row being parsed. */ + struct tbl_span *last_span; /* Last data row. */ + int line; /* Line number in input file. */ + int pos; /* Column number in input file. */ + enum tbl_part part; /* Table section being parsed. */ +}; + + +void tbl_option(struct tbl_node *, int, const char *, int *); +void tbl_layout(struct tbl_node *, int, const char *, int); +void tbl_data(struct tbl_node *, int, const char *, int); +void tbl_cdata(struct tbl_node *, int, const char *, int); +void tbl_reset(struct tbl_node *); diff --git a/usr/src/cmd/mandoc/tbl_layout.c b/usr/src/cmd/mandoc/tbl_layout.c index 42fc0e8296..58599705c1 100644 --- a/usr/src/cmd/mandoc/tbl_layout.c +++ b/usr/src/cmd/mandoc/tbl_layout.c @@ -1,4 +1,4 @@ -/* $Id: tbl_layout.c,v 1.44 2017/06/27 18:25:02 schwarze Exp $ */ +/* $Id: tbl_layout.c,v 1.48 2018/12/14 05:18:03 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2012, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org> @@ -21,14 +21,16 @@ #include <ctype.h> #include <stdint.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> -#include "mandoc.h" #include "mandoc_aux.h" +#include "mandoc.h" +#include "tbl.h" #include "libmandoc.h" -#include "libroff.h" +#include "tbl_int.h" struct tbl_phrase { char name; @@ -84,8 +86,7 @@ mod: (*pos)++; goto mod; } - mandoc_msg(MANDOCERR_TBLLAYOUT_PAR, tbl->parse, - ln, *pos, NULL); + mandoc_msg(MANDOCERR_TBLLAYOUT_PAR, ln, *pos, NULL); return; } @@ -113,8 +114,7 @@ mod: cp->flags |= TBL_CELL_ITALIC; goto mod; case 'm': - mandoc_msg(MANDOCERR_TBLLAYOUT_MOD, tbl->parse, - ln, *pos, "m"); + mandoc_msg(MANDOCERR_TBLLAYOUT_MOD, ln, *pos, "m"); goto mod; case 'p': case 'v': @@ -157,10 +157,10 @@ mod: cp->vert++; else mandoc_msg(MANDOCERR_TBLLAYOUT_VERT, - tbl->parse, ln, *pos - 1, NULL); + ln, *pos - 1, NULL); goto mod; default: - mandoc_vmsg(MANDOCERR_TBLLAYOUT_CHAR, tbl->parse, + mandoc_msg(MANDOCERR_TBLLAYOUT_CHAR, ln, *pos - 1, "%c", p[*pos - 1]); goto mod; } @@ -173,7 +173,7 @@ mod: /* Support only one-character font-names for now. */ if (p[*pos] == '\0' || (p[*pos + 1] != ' ' && p[*pos + 1] != '.')) { - mandoc_vmsg(MANDOCERR_FT_BAD, tbl->parse, + mandoc_msg(MANDOCERR_FT_BAD, ln, *pos, "TS %s", p + *pos - 1); if (p[*pos] != '\0') (*pos)++; @@ -195,7 +195,7 @@ mod: case 'R': goto mod; default: - mandoc_vmsg(MANDOCERR_FT_BAD, tbl->parse, + mandoc_msg(MANDOCERR_FT_BAD, ln, *pos - 1, "TS f%c", p[*pos - 1]); goto mod; } @@ -216,7 +216,7 @@ cell(struct tbl_node *tbl, struct tbl_row *rp, rp->vert++; else mandoc_msg(MANDOCERR_TBLLAYOUT_VERT, - tbl->parse, ln, *pos, NULL); + ln, *pos, NULL); } (*pos)++; } @@ -235,7 +235,7 @@ again: break; if (i == KEYS_MAX) { - mandoc_vmsg(MANDOCERR_TBLLAYOUT_CHAR, tbl->parse, + mandoc_msg(MANDOCERR_TBLLAYOUT_CHAR, ln, *pos, "%c", p[*pos]); (*pos)++; goto again; @@ -246,14 +246,12 @@ again: if (c == TBL_CELL_SPAN) { if (rp->last == NULL) - mandoc_msg(MANDOCERR_TBLLAYOUT_SPAN, - tbl->parse, ln, *pos, NULL); + mandoc_msg(MANDOCERR_TBLLAYOUT_SPAN, ln, *pos, NULL); else if (rp->last->pos == TBL_CELL_HORIZ || rp->last->pos == TBL_CELL_DHORIZ) c = rp->last->pos; } else if (c == TBL_CELL_DOWN && rp == tbl->first_row) - mandoc_msg(MANDOCERR_TBLLAYOUT_DOWN, - tbl->parse, ln, *pos, NULL); + mandoc_msg(MANDOCERR_TBLLAYOUT_DOWN, ln, *pos, NULL); (*pos)++; @@ -296,7 +294,7 @@ tbl_layout(struct tbl_node *tbl, int ln, const char *p, int pos) } if (tbl->first_row->first == NULL) { mandoc_msg(MANDOCERR_TBLLAYOUT_NONE, - tbl->parse, ln, pos, NULL); + ln, pos, NULL); cell_alloc(tbl, tbl->first_row, TBL_CELL_LEFT); if (tbl->opts.lvert < tbl->first_row->vert) diff --git a/usr/src/cmd/mandoc/tbl_opts.c b/usr/src/cmd/mandoc/tbl_opts.c index f2f5942ae6..e3a8373702 100644 --- a/usr/src/cmd/mandoc/tbl_opts.c +++ b/usr/src/cmd/mandoc/tbl_opts.c @@ -1,4 +1,4 @@ -/* $Id: tbl_opts.c,v 1.21 2015/09/26 00:54:04 schwarze Exp $ */ +/* $Id: tbl_opts.c,v 1.24 2018/12/14 05:18:03 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org> @@ -25,8 +25,9 @@ #include <string.h> #include "mandoc.h" +#include "tbl.h" #include "libmandoc.h" -#include "libroff.h" +#include "tbl_int.h" #define KEY_DPOINT 0 #define KEY_DELIM 1 @@ -80,7 +81,7 @@ arg(struct tbl_node *tbl, int ln, const char *p, int *pos, int key) switch (key) { case KEY_DELIM: - mandoc_vmsg(MANDOCERR_TBLOPT_EQN, tbl->parse, + mandoc_msg(MANDOCERR_TBLOPT_EQN, ln, *pos, "%.*s", len, p + *pos); want = 2; break; @@ -102,12 +103,11 @@ arg(struct tbl_node *tbl, int ln, const char *p, int *pos, int key) } if (len == 0) - mandoc_msg(MANDOCERR_TBLOPT_NOARG, - tbl->parse, ln, *pos, keys[key].name); + mandoc_msg(MANDOCERR_TBLOPT_NOARG, ln, *pos, + "%s", keys[key].name); else if (want && len != want) - mandoc_vmsg(MANDOCERR_TBLOPT_ARGSZ, - tbl->parse, ln, *pos, "%s want %d have %d", - keys[key].name, want, len); + mandoc_msg(MANDOCERR_TBLOPT_ARGSZ, ln, *pos, + "%s want %d have %d", keys[key].name, want, len); *pos += len; if (p[*pos] == ')') @@ -141,8 +141,8 @@ tbl_option(struct tbl_node *tbl, int ln, const char *p, int *offs) len++; if (len == 0) { - mandoc_vmsg(MANDOCERR_TBLOPT_ALPHA, - tbl->parse, ln, pos, "%c", p[pos]); + mandoc_msg(MANDOCERR_TBLOPT_ALPHA, + ln, pos, "%c", p[pos]); pos++; continue; } @@ -156,7 +156,7 @@ tbl_option(struct tbl_node *tbl, int ln, const char *p, int *offs) i++; if (i == KEY_MAXKEYS) { - mandoc_vmsg(MANDOCERR_TBLOPT_BAD, tbl->parse, + mandoc_msg(MANDOCERR_TBLOPT_BAD, ln, pos, "%.*s", len, p + pos); pos += len; continue; diff --git a/usr/src/cmd/mandoc/tbl_parse.h b/usr/src/cmd/mandoc/tbl_parse.h new file mode 100644 index 0000000000..bb65536f28 --- /dev/null +++ b/usr/src/cmd/mandoc/tbl_parse.h @@ -0,0 +1,30 @@ +/* $Id: tbl_parse.h,v 1.2 2018/12/14 06:33:14 schwarze Exp $ */ +/* + * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2011, 2017 Ingo Schwarze <schwarze@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * External interface of the tbl(7) parser. + * For use in the roff(7) and tbl(7) parsers only. + */ + +struct tbl_node; +struct tbl_span; + +struct tbl_node *tbl_alloc(int, int, struct tbl_node *); +int tbl_end(struct tbl_node *, int); +void tbl_free(struct tbl_node *); +void tbl_read(struct tbl_node *, int, const char *, int); +void tbl_restart(int, int, struct tbl_node *); +struct tbl_span *tbl_span(struct tbl_node *); diff --git a/usr/src/cmd/mandoc/tbl_term.c b/usr/src/cmd/mandoc/tbl_term.c index c154a0e9b9..a411107bd1 100644 --- a/usr/src/cmd/mandoc/tbl_term.c +++ b/usr/src/cmd/mandoc/tbl_term.c @@ -1,7 +1,7 @@ -/* $Id: tbl_term.c,v 1.57 2017/07/31 16:14:10 schwarze Exp $ */ +/* $Id: tbl_term.c,v 1.68 2019/02/09 21:02:47 schwarze Exp $ */ /* * Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2011,2012,2014,2015,2017 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2011-2019 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 @@ -20,34 +20,121 @@ #include <sys/types.h> #include <assert.h> +#include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "mandoc.h" +#include "tbl.h" #include "out.h" #include "term.h" #define IS_HORIZ(cp) ((cp)->pos == TBL_CELL_HORIZ || \ (cp)->pos == TBL_CELL_DHORIZ) + static size_t term_tbl_len(size_t, void *); static size_t term_tbl_strlen(const char *, void *); static size_t term_tbl_sulen(const struct roffsu *, void *); -static void tbl_char(struct termp *, char, size_t); static void tbl_data(struct termp *, const struct tbl_opts *, const struct tbl_cell *, const struct tbl_dat *, const struct roffcol *); +static void tbl_direct_border(struct termp *, int, size_t); +static void tbl_fill_border(struct termp *, int, size_t); +static void tbl_fill_char(struct termp *, char, size_t); +static void tbl_fill_string(struct termp *, const char *, size_t); +static void tbl_hrule(struct termp *, const struct tbl_span *, + const struct tbl_span *, int); static void tbl_literal(struct termp *, const struct tbl_dat *, const struct roffcol *); static void tbl_number(struct termp *, const struct tbl_opts *, const struct tbl_dat *, const struct roffcol *); -static void tbl_hrule(struct termp *, const struct tbl_span *, int); static void tbl_word(struct termp *, const struct tbl_dat *); +/* + * The following border-character tables are indexed + * by ternary (3-based) numbers, as opposed to binary or decimal. + * Each ternary digit describes the line width in one direction: + * 0 means no line, 1 single or light line, 2 double or heavy line. + */ + +/* Positional values of the four directions. */ +#define BRIGHT 1 +#define BDOWN 3 +#define BLEFT (3 * 3) +#define BUP (3 * 3 * 3) +#define BHORIZ (BLEFT + BRIGHT) + +/* Code points to use for each combination of widths. */ +static const int borders_utf8[81] = { + 0x0020, 0x2576, 0x257a, /* 000 right */ + 0x2577, 0x250c, 0x250d, /* 001 down */ + 0x257b, 0x250e, 0x250f, /* 002 */ + 0x2574, 0x2500, 0x257c, /* 010 left */ + 0x2510, 0x252c, 0x252e, /* 011 left down */ + 0x2512, 0x2530, 0x2532, /* 012 */ + 0x2578, 0x257e, 0x2501, /* 020 left */ + 0x2511, 0x252d, 0x252f, /* 021 left down */ + 0x2513, 0x2531, 0x2533, /* 022 */ + 0x2575, 0x2514, 0x2515, /* 100 up */ + 0x2502, 0x251c, 0x251d, /* 101 up down */ + 0x257d, 0x251f, 0x2522, /* 102 */ + 0x2518, 0x2534, 0x2536, /* 110 up left */ + 0x2524, 0x253c, 0x253e, /* 111 all */ + 0x2527, 0x2541, 0x2546, /* 112 */ + 0x2519, 0x2535, 0x2537, /* 120 up left */ + 0x2525, 0x253d, 0x253f, /* 121 all */ + 0x252a, 0x2545, 0x2548, /* 122 */ + 0x2579, 0x2516, 0x2517, /* 200 up */ + 0x257f, 0x251e, 0x2521, /* 201 up down */ + 0x2503, 0x2520, 0x2523, /* 202 */ + 0x251a, 0x2538, 0x253a, /* 210 up left */ + 0x2526, 0x2540, 0x2544, /* 211 all */ + 0x2528, 0x2542, 0x254a, /* 212 */ + 0x251b, 0x2539, 0x253b, /* 220 up left */ + 0x2529, 0x2543, 0x2547, /* 221 all */ + 0x252b, 0x2549, 0x254b, /* 222 */ +}; + +/* ASCII approximations for these code points, compatible with groff. */ +static const int borders_ascii[81] = { + ' ', '-', '=', /* 000 right */ + '|', '+', '+', /* 001 down */ + '|', '+', '+', /* 002 */ + '-', '-', '=', /* 010 left */ + '+', '+', '+', /* 011 left down */ + '+', '+', '+', /* 012 */ + '=', '=', '=', /* 020 left */ + '+', '+', '+', /* 021 left down */ + '+', '+', '+', /* 022 */ + '|', '+', '+', /* 100 up */ + '|', '+', '+', /* 101 up down */ + '|', '+', '+', /* 102 */ + '+', '+', '+', /* 110 up left */ + '+', '+', '+', /* 111 all */ + '+', '+', '+', /* 112 */ + '+', '+', '+', /* 120 up left */ + '+', '+', '+', /* 121 all */ + '+', '+', '+', /* 122 */ + '|', '+', '+', /* 200 up */ + '|', '+', '+', /* 201 up down */ + '|', '+', '+', /* 202 */ + '+', '+', '+', /* 210 up left */ + '+', '+', '+', /* 211 all */ + '+', '+', '+', /* 212 */ + '+', '+', '+', /* 220 up left */ + '+', '+', '+', /* 221 all */ + '+', '+', '+', /* 222 */ +}; + +/* Either of the above according to the selected output encoding. */ +static const int *borders_locale; + + static size_t term_tbl_sulen(const struct roffsu *su, void *arg) { @@ -69,19 +156,22 @@ term_tbl_len(size_t sz, void *arg) return term_len((const struct termp *)arg, sz); } + void term_tbl(struct termp *tp, const struct tbl_span *sp) { - const struct tbl_cell *cp, *cpn, *cpp; + const struct tbl_cell *cp, *cpn, *cpp, *cps; const struct tbl_dat *dp; static size_t offset; + size_t save_offset; size_t coloff, tsz; - int ic, horiz, spans, vert, more; - char fc; + int hspans, ic, more; + int dvert, fc, horiz, lhori, rhori, uvert; /* Inhibit printing of spaces: we do padding ourselves. */ tp->flags |= TERMP_NOSPACE | TERMP_NONOSPACE; + save_offset = tp->tcol->offset; /* * The first time we're invoked for a given table block, @@ -89,6 +179,9 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) */ if (tp->tbl.cols == NULL) { + borders_locale = tp->enc == TERMENC_UTF8 ? + borders_utf8 : borders_ascii; + tp->tbl.len = term_tbl_len; tp->tbl.slen = term_tbl_strlen; tp->tbl.sulen = term_tbl_sulen; @@ -120,21 +213,24 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) tsz += tp->tbl.cols[sp->opts->cols - 1].width; if (offset + tsz > tp->tcol->rmargin) tsz -= 1; - tp->tcol->offset = offset + tp->tcol->rmargin > tsz ? + offset = offset + tp->tcol->rmargin > tsz ? (offset + tp->tcol->rmargin - tsz) / 2 : 0; + tp->tcol->offset = offset; } /* Horizontal frame at the start of boxed tables. */ - if (sp->opts->opts & TBL_OPT_DBOX) - tbl_hrule(tp, sp, 3); + if (tp->enc == TERMENC_ASCII && + sp->opts->opts & TBL_OPT_DBOX) + tbl_hrule(tp, NULL, sp, TBL_OPT_DBOX); if (sp->opts->opts & (TBL_OPT_DBOX | TBL_OPT_BOX)) - tbl_hrule(tp, sp, 2); + tbl_hrule(tp, NULL, sp, TBL_OPT_BOX); } /* Set up the columns. */ tp->flags |= TERMP_MULTICOL; + tp->tcol->offset = offset; horiz = 0; switch (sp->pos) { case TBL_SPAN_HORIZ: @@ -156,9 +252,9 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) /* Set up the data columns. */ dp = sp->first; - spans = 0; + hspans = 0; for (ic = 0; ic < sp->opts->cols; ic++) { - if (spans == 0) { + if (hspans == 0) { tp->tcol++; tp->tcol->offset = coloff; } @@ -166,13 +262,13 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) tp->tcol->rmargin = coloff; if (ic + 1 < sp->opts->cols) coloff += tp->tbl.cols[ic].spacing; - if (spans) { - spans--; + if (hspans) { + hspans--; continue; } if (dp == NULL) continue; - spans = dp->spans; + hspans = dp->hspans; if (ic || sp->layout->first->pos != TBL_CELL_SPAN) dp = dp->next; } @@ -192,14 +288,14 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) tp->tcol = tp->tcols; cp = cpn = sp->layout->first; dp = sp->first; - spans = 0; + hspans = 0; for (ic = 0; ic < sp->opts->cols; ic++) { if (cpn != NULL) { cp = cpn; cpn = cpn->next; } - if (spans) { - spans--; + if (hspans) { + hspans--; continue; } tp->tcol++; @@ -207,7 +303,7 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) tbl_data(tp, sp->opts, cp, dp, tp->tbl.cols + ic); if (dp == NULL) continue; - spans = dp->spans; + hspans = dp->hspans; if (cp->pos != TBL_CELL_SPAN) dp = dp->next; } @@ -218,37 +314,43 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) /* Print the vertical frame at the start of each row. */ tp->tcol = tp->tcols; - fc = '\0'; - if (sp->layout->vert || - (sp->next != NULL && sp->next->layout->vert && - sp->next->pos == TBL_SPAN_DATA) || - (sp->prev != NULL && sp->prev->layout->vert && - (horiz || (IS_HORIZ(sp->layout->first) && - !IS_HORIZ(sp->prev->layout->first)))) || - sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX)) - fc = horiz || IS_HORIZ(sp->layout->first) ? '+' : '|'; - else if (horiz && sp->opts->lvert) - fc = '-'; - if (fc != '\0') { + uvert = dvert = sp->opts->opts & TBL_OPT_DBOX ? 2 : + sp->opts->opts & TBL_OPT_BOX ? 1 : 0; + if (sp->pos == TBL_SPAN_DATA && uvert < sp->layout->vert) + uvert = dvert = sp->layout->vert; + if (sp->next != NULL && sp->next->pos == TBL_SPAN_DATA && + dvert < sp->next->layout->vert) + dvert = sp->next->layout->vert; + if (sp->prev != NULL && uvert < sp->prev->layout->vert && + (horiz || (IS_HORIZ(sp->layout->first) && + !IS_HORIZ(sp->prev->layout->first)))) + uvert = sp->prev->layout->vert; + rhori = sp->pos == TBL_SPAN_DHORIZ || + (sp->first != NULL && sp->first->pos == TBL_DATA_DHORIZ) || + sp->layout->first->pos == TBL_CELL_DHORIZ ? 2 : + sp->pos == TBL_SPAN_HORIZ || + (sp->first != NULL && sp->first->pos == TBL_DATA_HORIZ) || + sp->layout->first->pos == TBL_CELL_HORIZ ? 1 : 0; + fc = BUP * uvert + BDOWN * dvert + BRIGHT * rhori; + if (uvert > 0 || dvert > 0 || (horiz && sp->opts->lvert)) { (*tp->advance)(tp, tp->tcols->offset); - (*tp->letter)(tp, fc); - tp->viscol = tp->tcol->offset + 1; + tp->viscol = tp->tcol->offset; + tbl_direct_border(tp, fc, 1); } /* Print the data cells. */ more = 0; - if (horiz) { - tbl_hrule(tp, sp, 0); - term_flushln(tp); - } else { + if (horiz) + tbl_hrule(tp, sp->prev, sp, 0); + else { cp = sp->layout->first; cpn = sp->next == NULL ? NULL : sp->next->layout->first; cpp = sp->prev == NULL ? NULL : sp->prev->layout->first; dp = sp->first; - spans = 0; + hspans = 0; for (ic = 0; ic < sp->opts->cols; ic++) { /* @@ -257,25 +359,27 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) * and advance to next layout cell. */ + uvert = dvert = fc = 0; if (cp != NULL) { - vert = cp->vert; + cps = cp; + while (cps->next != NULL && + cps->next->pos == TBL_CELL_SPAN) + cps = cps->next; + if (sp->pos == TBL_SPAN_DATA) + uvert = dvert = cps->vert; switch (cp->pos) { case TBL_CELL_HORIZ: - fc = '-'; + fc = BHORIZ; break; case TBL_CELL_DHORIZ: - fc = '='; + fc = BHORIZ * 2; break; default: - fc = ' '; break; } - } else { - vert = 0; - fc = ' '; } if (cpp != NULL) { - if (vert == 0 && + if (uvert < cpp->vert && cp != NULL && ((IS_HORIZ(cp) && !IS_HORIZ(cpp)) || @@ -283,19 +387,31 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) cpp->next != NULL && IS_HORIZ(cp->next) && !IS_HORIZ(cpp->next)))) - vert = cpp->vert; + uvert = cpp->vert; cpp = cpp->next; } - if (vert == 0 && - sp->opts->opts & TBL_OPT_ALLBOX) - vert = 1; + if (sp->opts->opts & TBL_OPT_ALLBOX) { + if (uvert == 0) + uvert = 1; + if (dvert == 0) + dvert = 1; + } if (cpn != NULL) { - if (vert == 0) - vert = cpn->vert; + if (dvert == 0 || + (dvert < cpn->vert && + tp->enc == TERMENC_UTF8)) + dvert = cpn->vert; cpn = cpn->next; } - if (cp != NULL) - cp = cp->next; + + lhori = (cp != NULL && + cp->pos == TBL_CELL_DHORIZ) || + (dp != NULL && + dp->pos == TBL_DATA_DHORIZ) ? 2 : + (cp != NULL && + cp->pos == TBL_CELL_HORIZ) || + (dp != NULL && + dp->pos == TBL_DATA_HORIZ) ? 1 : 0; /* * Skip later cells in a span, @@ -303,12 +419,13 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) * and advance to next data cell. */ - if (spans) { - spans--; + if (hspans) { + hspans--; + cp = cp->next; continue; } if (dp != NULL) { - spans = dp->spans; + hspans = dp->hspans; if (ic || sp->layout->first->pos != TBL_CELL_SPAN) dp = dp->next; @@ -330,10 +447,16 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) * but not after the last column. */ - if (fc == ' ' && ((vert == 0 && - (cp == NULL || !IS_HORIZ(cp))) || - tp->tcol + 1 == tp->tcols + tp->lasttcol)) + if (fc == 0 && + ((uvert == 0 && dvert == 0 && + cp != NULL && (cp->next == NULL || + !IS_HORIZ(cp->next))) || + tp->tcol + 1 == + tp->tcols + tp->lasttcol)) { + if (cp != NULL) + cp = cp->next; continue; + } if (tp->viscol < tp->tcol->rmargin) { (*tp->advance)(tp, tp->tcol->rmargin @@ -341,77 +464,83 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) tp->viscol = tp->tcol->rmargin; } while (tp->viscol < tp->tcol->rmargin + - tp->tbl.cols[ic].spacing / 2) { - (*tp->letter)(tp, fc); - tp->viscol++; - } + tp->tbl.cols[ic].spacing / 2) + tbl_direct_border(tp, + BHORIZ * lhori, 1); if (tp->tcol + 1 == tp->tcols + tp->lasttcol) continue; - if (fc == ' ' && cp != NULL) { - switch (cp->pos) { - case TBL_CELL_HORIZ: - fc = '-'; - break; - case TBL_CELL_DHORIZ: - fc = '='; - break; - default: - break; - } - } - if (tp->tbl.cols[ic].spacing) { - (*tp->letter)(tp, fc == ' ' ? '|' : - vert ? '+' : fc); - tp->viscol++; - } + if (cp != NULL) + cp = cp->next; + + rhori = (cp != NULL && + cp->pos == TBL_CELL_DHORIZ) || + (dp != NULL && + dp->pos == TBL_DATA_DHORIZ) ? 2 : + (cp != NULL && + cp->pos == TBL_CELL_HORIZ) || + (dp != NULL && + dp->pos == TBL_DATA_HORIZ) ? 1 : 0; + + if (tp->tbl.cols[ic].spacing) + tbl_direct_border(tp, + BLEFT * lhori + BRIGHT * rhori + + BUP * uvert + BDOWN * dvert, 1); + + if (tp->enc == TERMENC_UTF8) + uvert = dvert = 0; - if (fc != ' ') { - if (cp != NULL && - cp->pos == TBL_CELL_HORIZ) - fc = '-'; - else if (cp != NULL && - cp->pos == TBL_CELL_DHORIZ) - fc = '='; - else - fc = ' '; - } if (tp->tbl.cols[ic].spacing > 2 && - (vert > 1 || fc != ' ')) { - (*tp->letter)(tp, fc == ' ' ? '|' : - vert > 1 ? '+' : fc); - tp->viscol++; - } + (uvert > 1 || dvert > 1 || rhori)) + tbl_direct_border(tp, + BHORIZ * rhori + + BUP * (uvert > 1) + + BDOWN * (dvert > 1), 1); } } /* Print the vertical frame at the end of each row. */ - fc = '\0'; - if ((sp->layout->last->vert && - sp->layout->last->col + 1 == sp->opts->cols) || - (sp->next != NULL && - sp->next->layout->last->vert && - sp->next->layout->last->col + 1 == sp->opts->cols) || - (sp->prev != NULL && - sp->prev->layout->last->vert && - sp->prev->layout->last->col + 1 == sp->opts->cols && - (horiz || (IS_HORIZ(sp->layout->last) && - !IS_HORIZ(sp->prev->layout->last)))) || - (sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX))) - fc = horiz || IS_HORIZ(sp->layout->last) ? '+' : '|'; - else if (horiz && sp->opts->rvert) - fc = '-'; - if (fc != '\0') { + uvert = dvert = sp->opts->opts & TBL_OPT_DBOX ? 2 : + sp->opts->opts & TBL_OPT_BOX ? 1 : 0; + if (sp->pos == TBL_SPAN_DATA && + uvert < sp->layout->last->vert && + sp->layout->last->col + 1 == sp->opts->cols) + uvert = dvert = sp->layout->last->vert; + if (sp->next != NULL && + dvert < sp->next->layout->last->vert && + sp->next->layout->last->col + 1 == sp->opts->cols) + dvert = sp->next->layout->last->vert; + if (sp->prev != NULL && + uvert < sp->prev->layout->last->vert && + sp->prev->layout->last->col + 1 == sp->opts->cols && + (horiz || (IS_HORIZ(sp->layout->last) && + !IS_HORIZ(sp->prev->layout->last)))) + uvert = sp->prev->layout->last->vert; + lhori = sp->pos == TBL_SPAN_DHORIZ || + (sp->last != NULL && + sp->last->pos == TBL_DATA_DHORIZ && + sp->last->layout->col + 1 == sp->opts->cols) || + (sp->layout->last->pos == TBL_CELL_DHORIZ && + sp->layout->last->col + 1 == sp->opts->cols) ? 2 : + sp->pos == TBL_SPAN_HORIZ || + (sp->last != NULL && + sp->last->pos == TBL_DATA_HORIZ && + sp->last->layout->col + 1 == sp->opts->cols) || + (sp->layout->last->pos == TBL_CELL_HORIZ && + sp->layout->last->col + 1 == sp->opts->cols) ? 1 : 0; + fc = BUP * uvert + BDOWN * dvert + BLEFT * lhori; + if (uvert > 0 || dvert > 0 || (horiz && sp->opts->rvert)) { if (horiz == 0 && (IS_HORIZ(sp->layout->last) == 0 || sp->layout->last->col + 1 < sp->opts->cols)) { tp->tcol++; - (*tp->advance)(tp, - tp->tcol->offset > tp->viscol ? - tp->tcol->offset - tp->viscol : 1); + do { + tbl_direct_border(tp, + BHORIZ * lhori, 1); + } while (tp->viscol < tp->tcol->offset); } - (*tp->letter)(tp, fc); + tbl_direct_border(tp, fc, 1); } (*tp->endline)(tp); tp->viscol = 0; @@ -428,80 +557,156 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) tp->tcol->rmargin = tp->maxrmargin; if (sp->next == NULL) { if (sp->opts->opts & (TBL_OPT_DBOX | TBL_OPT_BOX)) { - tbl_hrule(tp, sp, 2); + tbl_hrule(tp, sp, NULL, TBL_OPT_BOX); tp->skipvsp = 1; } - if (sp->opts->opts & TBL_OPT_DBOX) { - tbl_hrule(tp, sp, 3); + if (tp->enc == TERMENC_ASCII && + sp->opts->opts & TBL_OPT_DBOX) { + tbl_hrule(tp, sp, NULL, TBL_OPT_DBOX); tp->skipvsp = 2; } assert(tp->tbl.cols); free(tp->tbl.cols); tp->tbl.cols = NULL; - tp->tcol->offset = offset; } else if (horiz == 0 && sp->opts->opts & TBL_OPT_ALLBOX && (sp->next == NULL || sp->next->pos == TBL_SPAN_DATA || sp->next->next != NULL)) - tbl_hrule(tp, sp, 1); + tbl_hrule(tp, sp, sp->next, TBL_OPT_ALLBOX); + tp->tcol->offset = save_offset; tp->flags &= ~TERMP_NONOSPACE; } -/* - * Kinds of horizontal rulers: - * 0: inside the table (single or double line with crossings) - * 1: inside the table (single or double line with crossings and ends) - * 2: inner frame (single line with crossings and ends) - * 3: outer frame (single line without crossings with ends) - */ static void -tbl_hrule(struct termp *tp, const struct tbl_span *sp, int kind) +tbl_hrule(struct termp *tp, const struct tbl_span *spp, + const struct tbl_span *spn, int flags) { - const struct tbl_cell *cp, *cpn, *cpp; - const struct roffcol *col; - int vert; - char line, cross; - - line = (kind < 2 && TBL_SPAN_DHORIZ == sp->pos) ? '=' : '-'; - cross = (kind < 3) ? '+' : '-'; - - if (kind) - term_word(tp, "+"); - cp = sp->layout->first; - cpp = kind || sp->prev == NULL ? NULL : sp->prev->layout->first; - if (cpp == cp) - cpp = NULL; - cpn = kind > 1 || sp->next == NULL ? NULL : sp->next->layout->first; - if (cpn == cp) - cpn = NULL; + const struct tbl_cell *cpp; /* Layout cell above this line. */ + const struct tbl_cell *cpn; /* Layout cell below this line. */ + const struct tbl_dat *dpn; /* Data cell below this line. */ + const struct roffcol *col; /* Contains width and spacing. */ + int opts; /* For the table as a whole. */ + int bw; /* Box line width. */ + int hw; /* Horizontal line width. */ + int lw, rw; /* Left and right line widths. */ + int uw, dw; /* Vertical line widths. */ + + cpp = spp == NULL ? NULL : spp->layout->first; + cpn = spn == NULL ? NULL : spn->layout->first; + dpn = NULL; + if (spn != NULL) { + if (spn->pos == TBL_SPAN_DATA) + dpn = spn->first; + else if (spn->next != NULL) + dpn = spn->next->first; + } + opts = spn == NULL ? spp->opts->opts : spn->opts->opts; + bw = opts & TBL_OPT_DBOX ? (tp->enc == TERMENC_UTF8 ? 2 : 1) : + opts & (TBL_OPT_BOX | TBL_OPT_ALLBOX) ? 1 : 0; + hw = flags == TBL_OPT_DBOX || flags == TBL_OPT_BOX ? bw : + spn->pos == TBL_SPAN_DHORIZ ? 2 : 1; + + /* Print the left end of the line. */ + + if (tp->viscol == 0) { + (*tp->advance)(tp, tp->tcols->offset); + tp->viscol = tp->tcols->offset; + } + if (flags != 0) + tbl_direct_border(tp, + (spp == NULL ? 0 : BUP * bw) + + (spn == NULL ? 0 : BDOWN * bw) + + (spp == NULL || cpn == NULL || + cpn->pos != TBL_CELL_DOWN ? BRIGHT * hw : 0), 1); + for (;;) { - col = tp->tbl.cols + cp->col; - tbl_char(tp, line, col->width + col->spacing / 2); - vert = cp->vert; - if ((cp = cp->next) == NULL) - break; + col = tp->tbl.cols + (cpn == NULL ? cpp->col : cpn->col); + + /* Print the horizontal line inside this column. */ + + lw = cpp == NULL || cpn == NULL || + (cpn->pos != TBL_CELL_DOWN && + (dpn == NULL || strcmp(dpn->string, "\\^") != 0)) + ? hw : 0; + tbl_direct_border(tp, BHORIZ * lw, + col->width + col->spacing / 2); + + /* + * Figure out whether a vertical line is crossing + * at the end of this column, + * and advance to the next column. + */ + + uw = dw = 0; if (cpp != NULL) { - if (vert < cpp->vert) - vert = cpp->vert; + if (flags != TBL_OPT_DBOX) { + uw = cpp->vert; + if (uw == 0 && opts & TBL_OPT_ALLBOX) + uw = 1; + } cpp = cpp->next; } if (cpn != NULL) { - if (vert < cpn->vert) - vert = cpn->vert; + if (flags != TBL_OPT_DBOX) { + dw = cpn->vert; + if (dw == 0 && opts & TBL_OPT_ALLBOX) + dw = 1; + } cpn = cpn->next; + while (dpn != NULL && dpn->layout != cpn) + dpn = dpn->next; } - if (sp->opts->opts & TBL_OPT_ALLBOX && !vert) - vert = 1; + if (cpp == NULL && cpn == NULL) + break; + + /* Vertical lines do not cross spanned cells. */ + + if (cpp != NULL && cpp->pos == TBL_CELL_SPAN) + uw = 0; + if (cpn != NULL && cpn->pos == TBL_CELL_SPAN) + dw = 0; + + /* The horizontal line inside the next column. */ + + rw = cpp == NULL || cpn == NULL || + (cpn->pos != TBL_CELL_DOWN && + (dpn == NULL || strcmp(dpn->string, "\\^") != 0)) + ? hw : 0; + + /* The line crossing at the end of this column. */ + if (col->spacing) - tbl_char(tp, vert ? cross : line, 1); + tbl_direct_border(tp, BLEFT * lw + + BRIGHT * rw + BUP * uw + BDOWN * dw, 1); + + /* + * In ASCII output, a crossing may print two characters. + */ + + if (tp->enc != TERMENC_ASCII || (uw < 2 && dw < 2)) + uw = dw = 0; if (col->spacing > 2) - tbl_char(tp, vert > 1 ? cross : line, 1); + tbl_direct_border(tp, + BHORIZ * rw + BUP * uw + BDOWN * dw, 1); + + /* Padding before the start of the next column. */ + if (col->spacing > 4) - tbl_char(tp, line, (col->spacing - 3) / 2); + tbl_direct_border(tp, + BHORIZ * rw, (col->spacing - 3) / 2); } - if (kind) { - term_word(tp, "+"); - term_flushln(tp); + + /* Print the right end of the line. */ + + if (flags != 0) { + tbl_direct_border(tp, + (spp == NULL ? 0 : BUP * bw) + + (spn == NULL ? 0 : BDOWN * bw) + + (spp == NULL || spn == NULL || + spn->layout->last->pos != TBL_CELL_DOWN ? + BLEFT * hw : 0), 1); + (*tp->endline)(tp); + tp->viscol = 0; } } @@ -512,10 +717,10 @@ tbl_data(struct termp *tp, const struct tbl_opts *opts, { switch (cp->pos) { case TBL_CELL_HORIZ: - tbl_char(tp, '-', col->width); + tbl_fill_border(tp, BHORIZ, col->width); return; case TBL_CELL_DHORIZ: - tbl_char(tp, '=', col->width); + tbl_fill_border(tp, BHORIZ * 2, col->width); return; default: break; @@ -529,11 +734,11 @@ tbl_data(struct termp *tp, const struct tbl_opts *opts, return; case TBL_DATA_HORIZ: case TBL_DATA_NHORIZ: - tbl_char(tp, '-', col->width); + tbl_fill_border(tp, BHORIZ, col->width); return; case TBL_DATA_NDHORIZ: case TBL_DATA_DHORIZ: - tbl_char(tp, '=', col->width); + tbl_fill_border(tp, BHORIZ * 2, col->width); return; default: break; @@ -558,18 +763,48 @@ tbl_data(struct termp *tp, const struct tbl_opts *opts, } static void -tbl_char(struct termp *tp, char c, size_t len) +tbl_fill_string(struct termp *tp, const char *cp, size_t len) { - size_t i, sz; - char cp[2]; + size_t i, sz; + + sz = term_strlen(tp, cp); + for (i = 0; i < len; i += sz) + term_word(tp, cp); +} + +static void +tbl_fill_char(struct termp *tp, char c, size_t len) +{ + char cp[2]; cp[0] = c; cp[1] = '\0'; + tbl_fill_string(tp, cp, len); +} - sz = term_strlen(tp, cp); +static void +tbl_fill_border(struct termp *tp, int c, size_t len) +{ + char buf[12]; - for (i = 0; i < len; i += sz) - term_word(tp, cp); + if ((c = borders_locale[c]) > 127) { + (void)snprintf(buf, sizeof(buf), "\\[u%04x]", c); + tbl_fill_string(tp, buf, len); + } else + tbl_fill_char(tp, c, len); +} + +static void +tbl_direct_border(struct termp *tp, int c, size_t len) +{ + size_t i, sz; + + c = borders_locale[c]; + sz = (*tp->width)(tp, c); + for (i = 0; i < len; i += sz) { + (*tp->letter)(tp, c); + tp->viscol += sz; + } } static void @@ -577,14 +812,14 @@ tbl_literal(struct termp *tp, const struct tbl_dat *dp, const struct roffcol *col) { size_t len, padl, padr, width; - int ic, spans; + int ic, hspans; assert(dp->string); len = term_strlen(tp, dp->string); width = col->width; ic = dp->layout->col; - spans = dp->spans; - while (spans--) + hspans = dp->hspans; + while (hspans--) width += tp->tbl.cols[++ic].width + 3; padr = width > len ? width - len : 0; @@ -609,9 +844,9 @@ tbl_literal(struct termp *tp, const struct tbl_dat *dp, break; } - tbl_char(tp, ASCII_NBRSP, padl); + tbl_fill_char(tp, ASCII_NBRSP, padl); tbl_word(tp, dp); - tbl_char(tp, ASCII_NBRSP, padr); + tbl_fill_char(tp, ASCII_NBRSP, padr); } static void @@ -619,44 +854,66 @@ tbl_number(struct termp *tp, const struct tbl_opts *opts, const struct tbl_dat *dp, const struct roffcol *col) { - char *cp; + const char *cp, *lastdigit, *lastpoint; + size_t intsz, padl, totsz; char buf[2]; - size_t sz, psz, ssz, d, padl; - int i; /* - * See calc_data_number(). Left-pad by taking the offset of our - * and the maximum decimal; right-pad by the remaining amount. + * Almost the same code as in tblcalc_number(): + * First find the position of the decimal point. */ assert(dp->string); + lastdigit = lastpoint = NULL; + for (cp = dp->string; cp[0] != '\0'; cp++) { + if (cp[0] == '\\' && cp[1] == '&') { + lastdigit = lastpoint = cp; + break; + } else if (cp[0] == opts->decimal && + (isdigit((unsigned char)cp[1]) || + (cp > dp->string && isdigit((unsigned char)cp[-1])))) + lastpoint = cp; + else if (isdigit((unsigned char)cp[0])) + lastdigit = cp; + } - sz = term_strlen(tp, dp->string); + /* Then measure both widths. */ - buf[0] = opts->decimal; - buf[1] = '\0'; + padl = 0; + totsz = term_strlen(tp, dp->string); + if (lastdigit != NULL) { + if (lastpoint == NULL) + lastpoint = lastdigit + 1; + intsz = 0; + buf[1] = '\0'; + for (cp = dp->string; cp < lastpoint; cp++) { + buf[0] = cp[0]; + intsz += term_strlen(tp, buf); + } - psz = term_strlen(tp, buf); + /* + * Pad left to match the decimal position, + * but avoid exceeding the total column width. + */ - if ((cp = strrchr(dp->string, opts->decimal)) != NULL) { - for (ssz = 0, i = 0; cp != &dp->string[i]; i++) { - buf[0] = dp->string[i]; - ssz += term_strlen(tp, buf); + if (col->decimal > intsz && col->width > totsz) { + padl = col->decimal - intsz; + if (padl + totsz > col->width) + padl = col->width - totsz; } - d = ssz + psz; - } else - d = sz + psz; - if (col->decimal > d && col->width > sz) { - padl = col->decimal - d; - if (padl + sz > col->width) - padl = col->width - sz; - tbl_char(tp, ASCII_NBRSP, padl); - } else - padl = 0; + /* If it is not a number, simply center the string. */ + + } else if (col->width > totsz) + padl = (col->width - totsz) / 2; + + tbl_fill_char(tp, ASCII_NBRSP, padl); tbl_word(tp, dp); - if (col->width > sz + padl) - tbl_char(tp, ASCII_NBRSP, col->width - sz - padl); + + /* Pad right to fill the column. */ + + if (col->width > padl + totsz) + tbl_fill_char(tp, ASCII_NBRSP, col->width - padl - totsz); } static void diff --git a/usr/src/cmd/mandoc/term.c b/usr/src/cmd/mandoc/term.c index f67fcf9d95..3b9277aaab 100644 --- a/usr/src/cmd/mandoc/term.c +++ b/usr/src/cmd/mandoc/term.c @@ -1,7 +1,7 @@ -/* $Id: term.c,v 1.274 2017/07/28 14:25:48 schwarze Exp $ */ +/* $Id: term.c,v 1.281 2019/06/03 20:23:41 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-2019 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,6 +21,7 @@ #include <assert.h> #include <ctype.h> +#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -37,6 +38,10 @@ static void bufferc(struct termp *, char); static void encode(struct termp *, const char *, size_t); static void encode1(struct termp *, int); static void endline(struct termp *); +static void term_field(struct termp *, size_t, size_t, + size_t, size_t); +static void term_fill(struct termp *, size_t *, size_t *, + size_t); void @@ -83,241 +88,327 @@ term_end(struct termp *p) * Flush a chunk of text. By default, break the output line each time * the right margin is reached, and continue output on the next line * at the same offset as the chunk itself. By default, also break the - * output line at the end of the chunk. - * The following flags may be specified: - * - * - TERMP_NOBREAK: Do not break the output line at the right margin, - * but only at the max right margin. Also, do not break the output - * line at the end of the chunk, such that the next call can pad to - * the next column. However, if less than p->trailspace blanks, - * which can be 0, 1, or 2, remain to the right margin, the line - * will be broken. - * - TERMP_BRTRSP: Consider trailing whitespace significant - * when deciding whether the chunk fits or not. - * - TERMP_BRIND: If the chunk does not fit and the output line has - * to be broken, start the next line at the right margin instead - * of at the offset. Used together with TERMP_NOBREAK for the tags - * in various kinds of tagged lists. - * - TERMP_HANG: Do not break the output line at the right margin, - * append the next chunk after it even if this one is too long. - * To be used together with TERMP_NOBREAK. - * - TERMP_NOPAD: Start writing at the current position, - * do not pad with blank characters up to the offset. + * output line at the end of the chunk. There are many flags modifying + * this behaviour, see the comments in the body of the function. */ void term_flushln(struct termp *p) { - size_t vis; /* current visual position on output */ - size_t vbl; /* number of blanks to prepend to output */ - size_t vend; /* end of word visual position on output */ - size_t bp; /* visual right border position */ - size_t dv; /* temporary for visual pos calculations */ - size_t j; /* temporary loop index for p->tcol->buf */ - size_t jhy; /* last hyph before overflow w/r/t j */ - size_t maxvis; /* output position of visible boundary */ - int ntab; /* number of tabs to prepend */ - int breakline; /* after this word */ + size_t vbl; /* Number of blanks to prepend to the output. */ + size_t vbr; /* Actual visual position of the end of field. */ + size_t vfield; /* Desired visual field width. */ + size_t vtarget; /* Desired visual position of the right margin. */ + size_t ic; /* Character position in the input buffer. */ + size_t nbr; /* Number of characters to print in this field. */ + + /* + * Normally, start writing at the left margin, but with the + * NOPAD flag, start writing at the current position instead. + */ vbl = (p->flags & TERMP_NOPAD) || p->tcol->offset < p->viscol ? 0 : p->tcol->offset - p->viscol; if (p->minbl && vbl < p->minbl) vbl = p->minbl; - maxvis = p->tcol->rmargin > p->viscol + vbl ? - p->tcol->rmargin - p->viscol - vbl : 0; - bp = !(p->flags & TERMP_NOBREAK) ? maxvis : - p->maxrmargin > p->viscol + vbl ? - p->maxrmargin - p->viscol - vbl : 0; - vis = vend = 0; if ((p->flags & TERMP_MULTICOL) == 0) p->tcol->col = 0; - while (p->tcol->col < p->tcol->lastcol) { + + /* Loop over output lines. */ + + for (;;) { + vfield = p->tcol->rmargin > p->viscol + vbl ? + p->tcol->rmargin - p->viscol - vbl : 0; /* - * Handle literal tab characters: collapse all - * subsequent tabs into a single huge set of spaces. + * Normally, break the line at the the right margin + * of the field, but with the NOBREAK flag, only + * break it at the max right margin of the screen, + * and with the BRNEVER flag, never break it at all. */ - ntab = 0; - while (p->tcol->col < p->tcol->lastcol && - p->tcol->buf[p->tcol->col] == '\t') { - vend = term_tab_next(vis); - vbl += vend - vis; - vis = vend; - ntab++; - p->tcol->col++; + vtarget = p->flags & TERMP_BRNEVER ? SIZE_MAX : + (p->flags & TERMP_NOBREAK) == 0 ? vfield : + p->maxrmargin > p->viscol + vbl ? + p->maxrmargin - p->viscol - vbl : 0; + + /* + * Figure out how much text will fit in the field. + * If there is whitespace only, print nothing. + */ + + term_fill(p, &nbr, &vbr, vtarget); + if (nbr == 0) + break; + + /* + * With the CENTER or RIGHT flag, increase the indentation + * to center the text between the left and right margins + * or to adjust it to the right margin, respectively. + */ + + if (vbr < vtarget) { + if (p->flags & TERMP_CENTER) + vbl += (vtarget - vbr) / 2; + else if (p->flags & TERMP_RIGHT) + vbl += vtarget - vbr; } + /* Finally, print the field content. */ + + term_field(p, vbl, nbr, vbr, vtarget); + /* - * Count up visible word characters. Control sequences - * (starting with the CSI) aren't counted. A space - * generates a non-printing word, which is valid (the - * space is printed according to regular spacing rules). + * If there is no text left in the field, exit the loop. + * If the BRTRSP flag is set, consider trailing + * whitespace significant when deciding whether + * the field fits or not. */ - jhy = 0; - breakline = 0; - for (j = p->tcol->col; j < p->tcol->lastcol; j++) { - if (p->tcol->buf[j] == '\n') { - if ((p->flags & TERMP_BRIND) == 0) - breakline = 1; + for (ic = p->tcol->col; ic < p->tcol->lastcol; ic++) { + switch (p->tcol->buf[ic]) { + case '\t': + if (p->flags & TERMP_BRTRSP) + vbr = term_tab_next(vbr); continue; - } - if (p->tcol->buf[j] == ' ' || p->tcol->buf[j] == '\t') - break; - - /* Back over the last printed character. */ - if (p->tcol->buf[j] == '\b') { - assert(j); - vend -= (*p->width)(p, p->tcol->buf[j - 1]); + case ' ': + if (p->flags & TERMP_BRTRSP) + vbr += (*p->width)(p, ' '); continue; + case '\n': + case ASCII_BREAK: + continue; + default: + break; } + break; + } + if (ic == p->tcol->lastcol) + break; - /* Regular word. */ - /* Break at the hyphen point if we overrun. */ - if (vend > vis && vend < bp && - (p->tcol->buf[j] == ASCII_HYPH|| - p->tcol->buf[j] == ASCII_BREAK)) - jhy = j; + /* + * At the location of an automtic line break, input + * space characters are consumed by the line break. + */ - /* - * Hyphenation now decided, put back a real - * hyphen such that we get the correct width. - */ - if (p->tcol->buf[j] == ASCII_HYPH) - p->tcol->buf[j] = '-'; + while (p->tcol->col < p->tcol->lastcol && + p->tcol->buf[p->tcol->col] == ' ') + p->tcol->col++; - vend += (*p->width)(p, p->tcol->buf[j]); - } + /* + * In multi-column mode, leave the rest of the text + * in the buffer to be handled by a subsequent + * invocation, such that the other columns of the + * table can be handled first. + * In single-column mode, simply break the line. + */ + + if (p->flags & TERMP_MULTICOL) + return; + + endline(p); + p->viscol = 0; /* - * Find out whether we would exceed the right margin. - * If so, break to the next line. + * Normally, start the next line at the same indentation + * as this one, but with the BRIND flag, start it at the + * right margin instead. This is used together with + * NOBREAK for the tags in various kinds of tagged lists. */ - if (vend > bp && jhy == 0 && vis > 0 && - (p->flags & TERMP_BRNEVER) == 0) { - if (p->flags & TERMP_MULTICOL) - return; + vbl = p->flags & TERMP_BRIND ? + p->tcol->rmargin : p->tcol->offset; + } - endline(p); - vend -= vis; + /* Reset output state in preparation for the next field. */ - /* Use pending tabs on the new line. */ + p->col = p->tcol->col = p->tcol->lastcol = 0; + p->minbl = p->trailspace; + p->flags &= ~(TERMP_BACKAFTER | TERMP_BACKBEFORE | TERMP_NOPAD); - vbl = 0; - while (ntab--) - vbl = term_tab_next(vbl); + if (p->flags & TERMP_MULTICOL) + return; - /* Re-establish indentation. */ + /* + * The HANG flag means that the next field + * always follows on the same line. + * The NOBREAK flag means that the next field + * follows on the same line unless the field was overrun. + * Normally, break the line at the end of each field. + */ - if (p->flags & TERMP_BRIND) - vbl += p->tcol->rmargin; - else - vbl += p->tcol->offset; - maxvis = p->tcol->rmargin > vbl ? - p->tcol->rmargin - vbl : 0; - bp = !(p->flags & TERMP_NOBREAK) ? maxvis : - p->maxrmargin > vbl ? p->maxrmargin - vbl : 0; - } + if ((p->flags & TERMP_HANG) == 0 && + ((p->flags & TERMP_NOBREAK) == 0 || + vbr + term_len(p, p->trailspace) > vfield)) + endline(p); +} - /* - * Write out the rest of the word. - */ +/* + * Store the number of input characters to print in this field in *nbr + * and their total visual width to print in *vbr. + * If there is only whitespace in the field, both remain zero. + * The desired visual width of the field is provided by vtarget. + * If the first word is longer, the field will be overrun. + */ +static void +term_fill(struct termp *p, size_t *nbr, size_t *vbr, size_t vtarget) +{ + size_t ic; /* Character position in the input buffer. */ + size_t vis; /* Visual position of the current character. */ + size_t vn; /* Visual position of the next character. */ + int breakline; /* Break at the end of this word. */ + int graph; /* Last character was non-blank. */ + + *nbr = *vbr = vis = 0; + breakline = graph = 0; + for (ic = p->tcol->col; ic < p->tcol->lastcol; ic++) { + switch (p->tcol->buf[ic]) { + case '\b': /* Escape \o (overstrike) or backspace markup. */ + assert(ic > 0); + vis -= (*p->width)(p, p->tcol->buf[ic - 1]); + continue; - for ( ; p->tcol->col < p->tcol->lastcol; p->tcol->col++) { - if (vend > bp && jhy > 0 && p->tcol->col > jhy) + case '\t': /* Normal ASCII whitespace. */ + case ' ': + case ASCII_BREAK: /* Escape \: (breakpoint). */ + switch (p->tcol->buf[ic]) { + case '\t': + vn = term_tab_next(vis); break; - if (p->tcol->buf[p->tcol->col] == '\n') - continue; - if (p->tcol->buf[p->tcol->col] == '\t') + case ' ': + vn = vis + (*p->width)(p, ' '); break; - if (p->tcol->buf[p->tcol->col] == ' ') { - j = p->tcol->col; - while (p->tcol->col < p->tcol->lastcol && - p->tcol->buf[p->tcol->col] == ' ') - p->tcol->col++; - dv = (p->tcol->col - j) * (*p->width)(p, ' '); - vbl += dv; - vend += dv; + case ASCII_BREAK: + vn = vis; break; + default: + abort(); } - if (p->tcol->buf[p->tcol->col] == ASCII_NBRSP) { - vbl += (*p->width)(p, ' '); - continue; + /* Can break at the end of a word. */ + if (breakline || vn > vtarget) + break; + if (graph) { + *nbr = ic; + *vbr = vis; + graph = 0; } - if (p->tcol->buf[p->tcol->col] == ASCII_BREAK) - continue; + vis = vn; + continue; + case '\n': /* Escape \p (break at the end of the word). */ + breakline = 1; + continue; + + case ASCII_HYPH: /* Breakable hyphen. */ + graph = 1; /* - * Now we definitely know there will be - * printable characters to output, - * so write preceding white space now. + * We are about to decide whether to break the + * line or not, so we no longer need this hyphen + * to be marked as breakable. Put back a real + * hyphen such that we get the correct width. */ - if (vbl) { - (*p->advance)(p, vbl); - p->viscol += vbl; - vbl = 0; + p->tcol->buf[ic] = '-'; + vis += (*p->width)(p, '-'); + if (vis > vtarget) { + ic++; + break; } - - (*p->letter)(p, p->tcol->buf[p->tcol->col]); - if (p->tcol->buf[p->tcol->col] == '\b') - p->viscol -= (*p->width)(p, - p->tcol->buf[p->tcol->col - 1]); - else - p->viscol += (*p->width)(p, - p->tcol->buf[p->tcol->col]); - } - vis = vend; - - if (breakline == 0) + *nbr = ic + 1; + *vbr = vis; continue; - /* Explicitly requested output line break. */ - - if (p->flags & TERMP_MULTICOL) - return; - - endline(p); - breakline = 0; - vis = vend = 0; - - /* Re-establish indentation. */ - - vbl = p->tcol->offset; - maxvis = p->tcol->rmargin > vbl ? - p->tcol->rmargin - vbl : 0; - bp = !(p->flags & TERMP_NOBREAK) ? maxvis : - p->maxrmargin > vbl ? p->maxrmargin - vbl : 0; + case ASCII_NBRSP: /* Non-breakable space. */ + p->tcol->buf[ic] = ' '; + /* FALLTHROUGH */ + default: /* Printable character. */ + graph = 1; + vis += (*p->width)(p, p->tcol->buf[ic]); + if (vis > vtarget && *nbr > 0) + return; + continue; + } + break; } /* - * If there was trailing white space, it was not printed; - * so reset the cursor position accordingly. + * If the last word extends to the end of the field without any + * trailing whitespace, the loop could not check yet whether it + * can remain on this line. So do the check now. */ - if (vis > vbl) - vis -= vbl; - else - vis = 0; + if (graph && (vis <= vtarget || *nbr == 0)) { + *nbr = ic; + *vbr = vis; + } +} - p->col = p->tcol->col = p->tcol->lastcol = 0; - p->minbl = p->trailspace; - p->flags &= ~(TERMP_BACKAFTER | TERMP_BACKBEFORE | TERMP_NOPAD); +/* + * Print the contents of one field + * with an indentation of vbl visual columns, + * an input string length of nbr characters, + * an output width of vbr visual columns, + * and a desired field width of vtarget visual columns. + */ +static void +term_field(struct termp *p, size_t vbl, size_t nbr, size_t vbr, size_t vtarget) +{ + size_t ic; /* Character position in the input buffer. */ + size_t vis; /* Visual position of the current character. */ + size_t dv; /* Visual width of the current character. */ + size_t vn; /* Visual position of the next character. */ - if (p->flags & TERMP_MULTICOL) - return; + vis = 0; + for (ic = p->tcol->col; ic < nbr; ic++) { + + /* + * To avoid the printing of trailing whitespace, + * do not print whitespace right away, only count it. + */ - /* Trailing whitespace is significant in some columns. */ + switch (p->tcol->buf[ic]) { + case '\n': + case ASCII_BREAK: + continue; + case '\t': + vn = term_tab_next(vis); + vbl += vn - vis; + vis = vn; + continue; + case ' ': + case ASCII_NBRSP: + dv = (*p->width)(p, ' '); + vbl += dv; + vis += dv; + continue; + default: + break; + } - if (vis && vbl && (TERMP_BRTRSP & p->flags)) - vis += vbl; + /* + * We found a non-blank character to print, + * so write preceding white space now. + */ - /* If the column was overrun, break the line. */ - if ((p->flags & TERMP_NOBREAK) == 0 || - ((p->flags & TERMP_HANG) == 0 && - vis + p->trailspace * (*p->width)(p, ' ') > maxvis)) - endline(p); + if (vbl > 0) { + (*p->advance)(p, vbl); + p->viscol += vbl; + vbl = 0; + } + + /* Print the character and adjust the visual position. */ + + (*p->letter)(p, p->tcol->buf[ic]); + if (p->tcol->buf[ic] == '\b') { + dv = (*p->width)(p, p->tcol->buf[ic - 1]); + p->viscol -= dv; + vis -= dv; + } else { + dv = (*p->width)(p, p->tcol->buf[ic]); + p->viscol += dv; + vis += dv; + } + } + p->tcol->col = nbr; } static void @@ -477,9 +568,6 @@ term_word(struct termp *p, const char *word) word++; esc = mandoc_escape(&word, &seq, &sz); - if (ESCAPE_ERROR == esc) - continue; - switch (esc) { case ESCAPE_UNICODE: uc = mchars_num2uc(seq + 1, sz - 1); @@ -500,6 +588,9 @@ term_word(struct termp *p, const char *word) encode1(p, uc); } continue; + case ESCAPE_UNDEF: + uc = *seq; + break; case ESCAPE_FONTBOLD: term_fontrepl(p, TERMFONT_BOLD); continue; @@ -510,6 +601,7 @@ term_word(struct termp *p, const char *word) term_fontrepl(p, TERMFONT_BI); continue; case ESCAPE_FONT: + case ESCAPE_FONTCW: case ESCAPE_FONTROMAN: term_fontrepl(p, TERMFONT_NONE); continue; @@ -525,6 +617,16 @@ term_word(struct termp *p, const char *word) else if (*word == '\0') p->flags |= (TERMP_NOSPACE | TERMP_NONEWLINE); continue; + case ESCAPE_DEVICE: + if (p->type == TERMTYPE_PDF) + encode(p, "pdf", 3); + else if (p->type == TERMTYPE_PS) + encode(p, "ps", 2); + else if (p->enc == TERMENC_ASCII) + encode(p, "ascii", 5); + else + encode(p, "utf8", 4); + continue; case ESCAPE_HORIZ: if (*seq == '|') { seq++; @@ -576,6 +678,9 @@ term_word(struct termp *p, const char *word) case ESCAPE_SPECIAL: uc = mchars_spec2cp(cp, sz); break; + case ESCAPE_UNDEF: + uc = *seq; + break; default: uc = -1; break; @@ -834,12 +939,8 @@ term_strlen(const struct termp *p, const char *cp) switch (*cp) { case '\\': cp++; - esc = mandoc_escape(&cp, &seq, &ssz); - if (ESCAPE_ERROR == esc) - continue; - rhs = NULL; - + esc = mandoc_escape(&cp, &seq, &ssz); switch (esc) { case ESCAPE_UNICODE: uc = mchars_num2uc(seq + 1, ssz - 1); @@ -860,6 +961,24 @@ term_strlen(const struct termp *p, const char *cp) sz += cond_width(p, uc, &skip); } continue; + case ESCAPE_UNDEF: + uc = *seq; + break; + case ESCAPE_DEVICE: + if (p->type == TERMTYPE_PDF) { + rhs = "pdf"; + rsz = 3; + } else if (p->type == TERMTYPE_PS) { + rhs = "ps"; + rsz = 2; + } else if (p->enc == TERMENC_ASCII) { + rhs = "ascii"; + rsz = 5; + } else { + rhs = "utf8"; + rsz = 4; + } + break; case ESCAPE_SKIPCHAR: skip = 1; continue; diff --git a/usr/src/cmd/mandoc/term.h b/usr/src/cmd/mandoc/term.h index 493191d7d3..f0a033a46f 100644 --- a/usr/src/cmd/mandoc/term.h +++ b/usr/src/cmd/mandoc/term.h @@ -1,7 +1,7 @@ -/* $Id: term.h,v 1.130 2017/07/08 14:51:05 schwarze Exp $ */ +/* $Id: term.h,v 1.131 2019/01/04 03:21:02 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2011-2015, 2017 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2011-2015, 2017, 2019 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 @@ -99,6 +99,8 @@ struct termp { #define TERMP_NEWMC (1 << 18) /* No .mc printed yet. */ #define TERMP_ENDMC (1 << 19) /* Next break ends .mc mode. */ #define TERMP_MULTICOL (1 << 20) /* Multiple column mode. */ +#define TERMP_CENTER (1 << 21) /* Center output lines. */ +#define TERMP_RIGHT (1 << 22) /* Adjust to the right margin. */ enum termtype type; /* Terminal, PS, or PDF. */ enum termenc enc; /* Type of encoding. */ enum termfont fontl; /* Last font set. */ diff --git a/usr/src/cmd/mandoc/term_ascii.c b/usr/src/cmd/mandoc/term_ascii.c index f47ffd75d9..368623cac1 100644 --- a/usr/src/cmd/mandoc/term_ascii.c +++ b/usr/src/cmd/mandoc/term_ascii.c @@ -1,4 +1,4 @@ -/* $Id: term_ascii.c,v 1.61 2018/05/20 21:37:34 schwarze Exp $ */ +/* $Id: term_ascii.c,v 1.64 2018/11/28 14:23:06 schwarze Exp $ */ /* * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2014, 2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org> @@ -90,7 +90,7 @@ ascii_init(enum termenc enc, const struct manoutput *outopts) p->width = ascii_width; #if HAVE_WCHAR - if (TERMENC_ASCII != enc) { + if (enc != TERMENC_ASCII) { /* * Do not change any of this to LC_ALL. It might break @@ -99,7 +99,7 @@ ascii_init(enum termenc enc, const struct manoutput *outopts) * worst case, it might even cause buffer overflows. */ - v = TERMENC_LOCALE == enc ? + v = enc == TERMENC_LOCALE ? setlocale(LC_CTYPE, "") : setlocale(LC_CTYPE, UTF8_LOCALE); @@ -113,7 +113,7 @@ ascii_init(enum termenc enc, const struct manoutput *outopts) v = setlocale(LC_CTYPE, "C"); if (v != NULL && MB_CUR_MAX > 1) { - p->enc = enc; + p->enc = TERMENC_UTF8; p->advance = locale_advance; p->endline = locale_endline; p->letter = locale_letter; @@ -196,8 +196,7 @@ terminal_sepline(void *arg) static size_t ascii_width(const struct termp *p, int c) { - - return 1; + return c != ASCII_BREAK; } void @@ -311,7 +310,7 @@ ascii_uc2str(int uc) "<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", "|", "<section>", + nbrsp, "!", "/\bc", "-\bL", "o\bx", "=\bY", "|", "<section>", "\"", "(C)", "_\ba", "<<", "~", "", "(R)", "-", "<degree>","+-","^2", "^3", "'","<micro>","<paragraph>",".", ",", "^1", "_\bo", ">>", "1/4", "1/2", "3/4", "?", diff --git a/usr/src/cmd/mandoc/term_tab.c b/usr/src/cmd/mandoc/term_tab.c index 5251a8425a..3343244f3c 100644 --- a/usr/src/cmd/mandoc/term_tab.c +++ b/usr/src/cmd/mandoc/term_tab.c @@ -1,4 +1,4 @@ -/* $OpenBSD: term.c,v 1.119 2017/01/08 18:08:44 schwarze Exp $ */ +/* $Id: term_tab.c,v 1.5 2018/12/16 00:21:05 schwarze Exp $ */ /* * Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org> * diff --git a/usr/src/cmd/mandoc/tree.c b/usr/src/cmd/mandoc/tree.c index b9774e1cd8..649c0804c8 100644 --- a/usr/src/cmd/mandoc/tree.c +++ b/usr/src/cmd/mandoc/tree.c @@ -1,7 +1,7 @@ -/* $Id: tree.c,v 1.78 2018/04/11 17:11:13 schwarze Exp $ */ +/* $Id: tree.c,v 1.84 2019/01/01 05:56:34 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2013,2014,2015,2017,2018 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2013-2015, 2017-2019 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 @@ -29,6 +29,8 @@ #include "roff.h" #include "mdoc.h" #include "man.h" +#include "tbl.h" +#include "eqn.h" #include "main.h" static void print_box(const struct eqn_box *, int); @@ -39,18 +41,18 @@ static void print_span(const struct tbl_span *, int); void -tree_mdoc(void *arg, const struct roff_man *mdoc) +tree_mdoc(void *arg, const struct roff_meta *mdoc) { - print_meta(&mdoc->meta); + print_meta(mdoc); putchar('\n'); print_mdoc(mdoc->first->child, 0); } void -tree_man(void *arg, const struct roff_man *man) +tree_man(void *arg, const struct roff_meta *man) { - print_meta(&man->meta); - if (man->meta.hasbody == 0) + print_meta(man); + if (man->hasbody == 0) puts("body = empty"); putchar('\n'); print_man(man->first->child, 0); @@ -187,20 +189,22 @@ print_mdoc(const struct roff_node *n, int indent) } putchar(' '); - if (NODE_DELIMO & n->flags) + if (n->flags & NODE_DELIMO) putchar('('); - if (NODE_LINE & n->flags) + if (n->flags & NODE_LINE) putchar('*'); printf("%d:%d", n->line, n->pos + 1); - if (NODE_DELIMC & n->flags) + if (n->flags & NODE_DELIMC) putchar(')'); - if (NODE_EOS & n->flags) + if (n->flags & NODE_EOS) putchar('.'); - if (NODE_BROKEN & n->flags) + if (n->flags & NODE_BROKEN) printf(" BROKEN"); - if (NODE_NOSRC & n->flags) + if (n->flags & NODE_NOFILL) + printf(" NOFILL"); + if (n->flags & NODE_NOSRC) printf(" NOSRC"); - if (NODE_NOPRT & n->flags) + if (n->flags & NODE_NOPRT) printf(" NOPRT"); putchar('\n'); } @@ -286,11 +290,15 @@ print_man(const struct roff_node *n, int indent) for (i = 0; i < indent; i++) putchar(' '); printf("%s (%s) ", p, t); - if (NODE_LINE & n->flags) + if (n->flags & NODE_LINE) putchar('*'); printf("%d:%d", n->line, n->pos + 1); - if (NODE_EOS & n->flags) + if (n->flags & NODE_DELIMC) + putchar(')'); + if (n->flags & NODE_EOS) putchar('.'); + if (n->flags & NODE_NOFILL) + printf(" NOFILL"); putchar('\n'); } @@ -377,35 +385,41 @@ print_span(const struct tbl_span *sp, int indent) switch (sp->pos) { case TBL_SPAN_HORIZ: putchar('-'); - return; + putchar(' '); + break; case TBL_SPAN_DHORIZ: putchar('='); - return; - default: + putchar(' '); break; - } - - for (dp = sp->first; dp; dp = dp->next) { - switch (dp->pos) { - case TBL_DATA_HORIZ: - case TBL_DATA_NHORIZ: - putchar('-'); - continue; - case TBL_DATA_DHORIZ: - case TBL_DATA_NDHORIZ: - putchar('='); - continue; - default: - break; + default: + for (dp = sp->first; dp; dp = dp->next) { + switch (dp->pos) { + case TBL_DATA_HORIZ: + case TBL_DATA_NHORIZ: + putchar('-'); + putchar(' '); + continue; + case TBL_DATA_DHORIZ: + case TBL_DATA_NDHORIZ: + putchar('='); + putchar(' '); + continue; + default: + break; + } + printf("[\"%s\"", dp->string ? dp->string : ""); + if (dp->hspans) + printf(">%d", dp->hspans); + if (dp->vspans) + printf("v%d", dp->vspans); + if (dp->layout == NULL) + putchar('*'); + else if (dp->layout->pos == TBL_CELL_DOWN) + putchar('^'); + putchar(']'); + putchar(' '); } - printf("[\"%s\"", dp->string ? dp->string : ""); - if (dp->spans) - printf("(%d)", dp->spans); - if (NULL == dp->layout) - putchar('*'); - putchar(']'); - putchar(' '); + break; } - printf("(tbl) %d:1\n", sp->line); } diff --git a/usr/src/cmd/mdb/common/modules/libc/libc.c b/usr/src/cmd/mdb/common/modules/libc/libc.c index b9de1dc936..165ebf1375 100644 --- a/usr/src/cmd/mdb/common/modules/libc/libc.c +++ b/usr/src/cmd/mdb/common/modules/libc/libc.c @@ -22,9 +22,9 @@ /* * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012 by Delphix. All rights reserved. - * Copyright 2019, Joyent, Inc. * Copyright (c) 2019 Carlos Neira <cneirabustos@gmail.com> * Copyright 2019 OmniOS Community Edition (OmniOSce) Association. + * Copyright 2019 Joyent, Inc. */ #include <sys/mdb_modapi.h> @@ -1423,6 +1423,43 @@ d_psinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) return (DCMD_OK); } +static int +d_errno(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +{ + mdb_libc_ulwp_t u; + uintptr_t ulwp_addr; + int error, errval; + + if (argc != 0 || (flags & DCMD_ADDRSPEC) == 0) + return (DCMD_USAGE); + + error = tid2ulwp_impl(addr, &ulwp_addr); + if (error != DCMD_OK) + return (error); + + /* + * For historical compatibility, thread 1's errno value is stored in + * a libc global variable 'errno', while each additional thread's + * errno value is stored in ulwp_t->ul_errno. In addition, + * ulwp_t->ul_errnop is set to the address of the thread's errno value, + * (i.e. for tid 1, curthead->ul_errnop = &errno, for tid > 1, + * curthread->ul_errnop = &curthread->ul_errno). + * + * Since errno itself uses *curthread->ul_errnop (see ___errno()) to + * return the thread's current errno value, we do the same. + */ + if (mdb_ctf_vread(&u, "ulwp_t", "mdb_libc_ulwp_t", ulwp_addr, 0) == -1) + return (DCMD_ERR); + + if (mdb_vread(&errval, sizeof (errval), (uintptr_t)u.ul_errnop) == -1) { + mdb_warn("cannot read error value at 0x%p", u.ul_errnop); + return (DCMD_ERR); + } + + mdb_printf("%d\n", errval); + return (DCMD_OK); +} + static const mdb_dcmd_t dcmds[] = { { "errno", "?", "print errno of a given TID", d_errno, NULL }, { "jmp_buf", ":", "print jmp_buf contents", d_jmp_buf, NULL }, diff --git a/usr/src/cmd/mdb/common/modules/zfs/zfs.c b/usr/src/cmd/mdb/common/modules/zfs/zfs.c index 6d89e2c797..271ce782ba 100644 --- a/usr/src/cmd/mdb/common/modules/zfs/zfs.c +++ b/usr/src/cmd/mdb/common/modules/zfs/zfs.c @@ -22,7 +22,7 @@ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2011 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2011, 2018 by Delphix. All rights reserved. - * Copyright (c) 2017, Joyent, Inc. All rights reserved. + * Copyright (c) 2019 Joyent, Inc. */ /* Portions Copyright 2010 Robert Milkowski */ @@ -1461,7 +1461,6 @@ typedef struct mdb_space_map_phys_t { typedef struct mdb_space_map { uint64_t sm_size; uint8_t sm_shift; - int64_t sm_alloc; uintptr_t sm_phys; } mdb_space_map_t; @@ -1505,6 +1504,7 @@ metaslab_stats(uintptr_t addr, int spa_flags) for (int m = 0; m < vdev.vdev_ms_count; m++) { mdb_metaslab_t ms; mdb_space_map_t sm = { 0 }; + mdb_space_map_phys_t smp; char free[MDB_NICENUM_BUFLEN]; if (mdb_ctf_vread(&ms, "metaslab_t", "mdb_metaslab_t", @@ -1516,7 +1516,13 @@ metaslab_stats(uintptr_t addr, int spa_flags) ms.ms_sm, 0) == -1) return (DCMD_ERR); - mdb_nicenum(ms.ms_size - sm.sm_alloc, free); + if (sm.sm_phys != 0) { + (void) mdb_ctf_vread(&smp, "space_map_phys_t", + "mdb_space_map_phys_t", sm.sm_phys, 0); + mdb_nicenum(ms.ms_size - smp.smp_alloc, free); + } else { + (void) mdb_snprintf(free, MDB_NICENUM_BUFLEN, "-"); + } mdb_printf("%0?p %6llu %20llx %10s ", vdev_ms[m], ms.ms_id, ms.ms_start, free); @@ -1526,14 +1532,9 @@ metaslab_stats(uintptr_t addr, int spa_flags) mdb_printf("%9llu%%\n", ms.ms_fragmentation); if ((spa_flags & SPA_FLAG_HISTOGRAMS) && ms.ms_sm != 0) { - mdb_space_map_phys_t smp; - if (sm.sm_phys == 0) continue; - (void) mdb_ctf_vread(&smp, "space_map_phys_t", - "mdb_space_map_phys_t", sm.sm_phys, 0); - dump_histogram(smp.smp_histogram, SPACE_MAP_HISTOGRAM_SIZE, sm.sm_shift); } @@ -2076,7 +2077,6 @@ typedef struct space_data { uint64_t ms_freed; uint64_t ms_allocatable; int64_t ms_deferspace; - uint64_t avail; uint64_t nowavail; } space_data_t; @@ -2135,7 +2135,6 @@ space_cb(uintptr_t addr, const void *unknown, void *arg) } sd->ms_deferspace += ms.ms_deferspace; - sd->avail += sm.sm_size - sm.sm_alloc; sd->nowavail += sm.sm_size - smp.smp_alloc; return (WALK_NEXT); @@ -2220,8 +2219,6 @@ spa_space(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) sd.ms_allocatable >> shift, suffix); mdb_printf("ms_deferspace = %llu%s\n", sd.ms_deferspace >> shift, suffix); - mdb_printf("last synced avail = %llu%s\n", - sd.avail >> shift, suffix); mdb_printf("current syncing avail = %llu%s\n", sd.nowavail >> shift, suffix); diff --git a/usr/src/cmd/zfs/zfs_main.c b/usr/src/cmd/zfs/zfs_main.c index 40dfe1cab7..ebb7a3c12d 100644 --- a/usr/src/cmd/zfs/zfs_main.c +++ b/usr/src/cmd/zfs/zfs_main.c @@ -890,10 +890,11 @@ zfs_do_create(int argc, char **argv) zpool_close(zpool_handle); goto error; } - zpool_close(zpool_handle); - volsize = zvol_volsize_to_reservation(volsize, real_props); + volsize = zvol_volsize_to_reservation(zpool_handle, volsize, + real_props); nvlist_free(real_props); + zpool_close(zpool_handle); if (nvlist_lookup_string(props, zfs_prop_to_name(resv_prop), &strval) != 0) { diff --git a/usr/src/lib/fm/topo/modules/common/shared/topo_sensor.c b/usr/src/lib/fm/topo/modules/common/shared/topo_sensor.c index 28fcf3e314..c9e56e9e1f 100644 --- a/usr/src/lib/fm/topo/modules/common/shared/topo_sensor.c +++ b/usr/src/lib/fm/topo/modules/common/shared/topo_sensor.c @@ -225,7 +225,8 @@ topo_sensor_create_temp_sensor(topo_mod_t *mod, tnode_t *pnode, } - if (topo_method_register(mod, fnode, topo_sensor_temp_fac_methods) < 0) { + if (topo_method_register(mod, fnode, topo_sensor_temp_fac_methods) < + 0) { topo_mod_dprintf(mod, "failed to register reading methods on " "%s", path); ret = -1; diff --git a/usr/src/lib/fm/topo/modules/i86pc/chip/Makefile b/usr/src/lib/fm/topo/modules/i86pc/chip/Makefile index f56686faf1..c6db9f09b6 100644 --- a/usr/src/lib/fm/topo/modules/i86pc/chip/Makefile +++ b/usr/src/lib/fm/topo/modules/i86pc/chip/Makefile @@ -29,7 +29,7 @@ ARCH = i86pc CLASS = arch SHAREDDIR = ../../common/shared/ -MODULESRCS = chip.c chip_label.c chip_subr.c chip_amd.c chip_intel.c\ +MODULESRCS = chip.c chip_label.c chip_subr.c chip_amd.c chip_intel.c \ chip_serial.c chip_smbios.c chip_temp.o MODULESRCS += topo_sensor.c diff --git a/usr/src/lib/libzfs/common/libzfs.h b/usr/src/lib/libzfs/common/libzfs.h index 35d0156b9c..3eb0e1b46b 100644 --- a/usr/src/lib/libzfs/common/libzfs.h +++ b/usr/src/lib/libzfs/common/libzfs.h @@ -673,7 +673,8 @@ extern int zfs_hold(zfs_handle_t *, const char *, const char *, extern int zfs_hold_nvl(zfs_handle_t *, int, nvlist_t *); extern int zfs_release(zfs_handle_t *, const char *, const char *, boolean_t); extern int zfs_get_holds(zfs_handle_t *, nvlist_t **); -extern uint64_t zvol_volsize_to_reservation(uint64_t, nvlist_t *); +extern uint64_t zvol_volsize_to_reservation(zpool_handle_t *, uint64_t, + nvlist_t *); typedef int (*zfs_userspace_cb_t)(void *arg, const char *domain, uid_t rid, uint64_t space); diff --git a/usr/src/lib/libzfs/common/libzfs_dataset.c b/usr/src/lib/libzfs/common/libzfs_dataset.c index d5af0574b8..6ad4ae8b38 100644 --- a/usr/src/lib/libzfs/common/libzfs_dataset.c +++ b/usr/src/lib/libzfs/common/libzfs_dataset.c @@ -21,7 +21,7 @@ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2018, Joyent, Inc. All rights reserved. + * Copyright 2019 Joyent, Inc. * Copyright (c) 2011, 2016 by Delphix. All rights reserved. * Copyright (c) 2012 DEY Storage Systems, Inc. All rights reserved. * Copyright (c) 2011-2012 Pawel Jakub Dawidek. All rights reserved. @@ -1518,6 +1518,7 @@ zfs_add_synthetic_resv(zfs_handle_t *zhp, nvlist_t *nvl) uint64_t new_reservation; zfs_prop_t resv_prop; nvlist_t *props; + zpool_handle_t *zph = zpool_handle(zhp); /* * If this is an existing volume, and someone is setting the volsize, @@ -1532,7 +1533,7 @@ zfs_add_synthetic_resv(zfs_handle_t *zhp, nvlist_t *nvl) fnvlist_add_uint64(props, zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), zfs_prop_get_int(zhp, ZFS_PROP_VOLBLOCKSIZE)); - if ((zvol_volsize_to_reservation(old_volsize, props) != + if ((zvol_volsize_to_reservation(zph, old_volsize, props) != old_reservation) || nvlist_exists(nvl, zfs_prop_to_name(resv_prop))) { fnvlist_free(props); @@ -1543,7 +1544,7 @@ zfs_add_synthetic_resv(zfs_handle_t *zhp, nvlist_t *nvl) fnvlist_free(props); return (-1); } - new_reservation = zvol_volsize_to_reservation(new_volsize, props); + new_reservation = zvol_volsize_to_reservation(zph, new_volsize, props); fnvlist_free(props); if (nvlist_add_uint64(nvl, zfs_prop_to_name(resv_prop), @@ -1598,7 +1599,8 @@ zfs_fix_auto_resv(zfs_handle_t *zhp, nvlist_t *nvl) volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); } - resvsize = zvol_volsize_to_reservation(volsize, props); + resvsize = zvol_volsize_to_reservation(zpool_handle(zhp), volsize, + props); fnvlist_free(props); (void) nvlist_remove_all(nvl, zfs_prop_to_name(prop)); @@ -5131,12 +5133,176 @@ zfs_get_holds(zfs_handle_t *zhp, nvlist_t **nvl) } /* - * Convert the zvol's volume size to an appropriate reservation. + * The theory of raidz space accounting + * + * The "referenced" property of RAIDZ vdevs is scaled such that a 128KB block + * will "reference" 128KB, even though it allocates more than that, to store the + * parity information (and perhaps skip sectors). This concept of the + * "referenced" (and other DMU space accounting) being lower than the allocated + * space by a constant factor is called "raidz deflation." + * + * As mentioned above, the constant factor for raidz deflation assumes a 128KB + * block size. However, zvols typically have a much smaller block size (default + * 8KB). These smaller blocks may require proportionally much more parity + * information (and perhaps skip sectors). In this case, the change to the + * "referenced" property may be much more than the logical block size. + * + * Suppose a raidz vdev has 5 disks with ashift=12. A 128k block may be written + * as follows. + * + * +-------+-------+-------+-------+-------+ + * | disk1 | disk2 | disk3 | disk4 | disk5 | + * +-------+-------+-------+-------+-------+ + * | P0 | D0 | D8 | D16 | D24 | + * | P1 | D1 | D9 | D17 | D25 | + * | P2 | D2 | D10 | D18 | D26 | + * | P3 | D3 | D11 | D19 | D27 | + * | P4 | D4 | D12 | D20 | D28 | + * | P5 | D5 | D13 | D21 | D29 | + * | P6 | D6 | D14 | D22 | D30 | + * | P7 | D7 | D15 | D23 | D31 | + * +-------+-------+-------+-------+-------+ + * + * Above, notice that 160k was allocated: 8 x 4k parity sectors + 32 x 4k data + * sectors. The dataset's referenced will increase by 128k and the pool's + * allocated and free properties will be adjusted by 160k. + * + * A 4k block written to the same raidz vdev will require two 4k sectors. The + * blank cells represent unallocated space. + * + * +-------+-------+-------+-------+-------+ + * | disk1 | disk2 | disk3 | disk4 | disk5 | + * +-------+-------+-------+-------+-------+ + * | P0 | D0 | | | | + * +-------+-------+-------+-------+-------+ + * + * Above, notice that the 4k block required one sector for parity and another + * for data. vdev_raidz_asize() will return 8k and as such the pool's allocated + * and free properties will be adjusted by 8k. The dataset will not be charged + * 8k. Rather, it will be charged a value that is scaled according to the + * overhead of the 128k block on the same vdev. This 8k allocation will be + * charged 8k * 128k / 160k. 128k is from SPA_OLD_MAXBLOCKSIZE and 160k is as + * calculated in the 128k block example above. + * + * Every raidz allocation is sized to be a multiple of nparity+1 sectors. That + * is, every raidz1 allocation will be a multiple of 2 sectors, raidz2 + * allocations are a multiple of 3 sectors, and raidz3 allocations are a + * multiple of of 4 sectors. When a block does not fill the required number of + * sectors, skip blocks (sectors) are used. + * + * An 8k block being written to a raidz vdev may be written as follows: + * + * +-------+-------+-------+-------+-------+ + * | disk1 | disk2 | disk3 | disk4 | disk5 | + * +-------+-------+-------+-------+-------+ + * | P0 | D0 | D1 | S0 | | + * +-------+-------+-------+-------+-------+ + * + * In order to maintain the nparity+1 allocation size, a skip block (S0) was + * added. For this 8k block, the pool's allocated and free properties are + * adjusted by 16k and the dataset's referenced is increased by 16k * 128k / + * 160k. Again, 128k is from SPA_OLD_MAXBLOCKSIZE and 160k is as calculated in + * the 128k block example above. + * + * Compression may lead to a variety of block sizes being written for the same + * volume or file. There is no clear way to reserve just the amount of space + * that will be required, so the worst case (no compression) is assumed. + * Note that metadata blocks will typically be compressed, so the reservation + * size returned by zvol_volsize_to_reservation() will generally be slightly + * larger than the maximum that the volume can reference. + */ + +/* + * Derived from function of same name in uts/common/fs/zfs/vdev_raidz.c. + * Returns the amount of space (in bytes) that will be allocated for the + * specified block size. Note that the "referenced" space accounted will be less + * than this, but not necessarily equal to "blksize", due to RAIDZ deflation. + */ +static uint64_t +vdev_raidz_asize(uint64_t ndisks, uint64_t nparity, uint64_t ashift, + uint64_t blksize) +{ + uint64_t asize, ndata; + + ASSERT3U(ndisks, >, nparity); + ndata = ndisks - nparity; + asize = ((blksize - 1) >> ashift) + 1; + asize += nparity * ((asize + ndata - 1) / ndata); + asize = roundup(asize, nparity + 1) << ashift; + + return (asize); +} + +/* + * Determine how much space will be allocated if it lands on the most space- + * inefficient top-level vdev. Returns the size in bytes required to store one + * copy of the volume data. See theory comment above. + */ +static uint64_t +volsize_from_vdevs(zpool_handle_t *zhp, uint64_t nblocks, uint64_t blksize) +{ + nvlist_t *config, *tree, **vdevs; + uint_t nvdevs, v; + uint64_t ret = 0; + + config = zpool_get_config(zhp, NULL); + if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &tree) != 0 || + nvlist_lookup_nvlist_array(tree, ZPOOL_CONFIG_CHILDREN, + &vdevs, &nvdevs) != 0) { + return (nblocks * blksize); + } + + for (v = 0; v < nvdevs; v++) { + char *type; + uint64_t nparity, ashift, asize, tsize; + nvlist_t **disks; + uint_t ndisks; + uint64_t volsize; + + if (nvlist_lookup_string(vdevs[v], ZPOOL_CONFIG_TYPE, + &type) != 0 || strcmp(type, VDEV_TYPE_RAIDZ) != 0 || + nvlist_lookup_uint64(vdevs[v], ZPOOL_CONFIG_NPARITY, + &nparity) != 0 || + nvlist_lookup_uint64(vdevs[v], ZPOOL_CONFIG_ASHIFT, + &ashift) != 0 || + nvlist_lookup_nvlist_array(vdevs[v], ZPOOL_CONFIG_CHILDREN, + &disks, &ndisks) != 0) { + continue; + } + + /* allocation size for the "typical" 128k block */ + tsize = vdev_raidz_asize(ndisks, nparity, ashift, + SPA_OLD_MAXBLOCKSIZE); + /* allocation size for the blksize block */ + asize = vdev_raidz_asize(ndisks, nparity, ashift, blksize); + + /* + * Scale this size down as a ratio of 128k / tsize. See theory + * statement above. + */ + volsize = nblocks * asize * SPA_OLD_MAXBLOCKSIZE / tsize; + if (volsize > ret) { + ret = volsize; + } + } + + if (ret == 0) { + ret = nblocks * blksize; + } + + return (ret); +} + +/* + * Convert the zvol's volume size to an appropriate reservation. See theory + * comment above. + * * Note: If this routine is updated, it is necessary to update the ZFS test - * suite's shell version in reservation.kshlib. + * suite's shell version in reservation.shlib. */ uint64_t -zvol_volsize_to_reservation(uint64_t volsize, nvlist_t *props) +zvol_volsize_to_reservation(zpool_handle_t *zph, uint64_t volsize, + nvlist_t *props) { uint64_t numdb; uint64_t nblocks, volblocksize; @@ -5152,7 +5318,14 @@ zvol_volsize_to_reservation(uint64_t volsize, nvlist_t *props) zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), &volblocksize) != 0) volblocksize = ZVOL_DEFAULT_BLOCKSIZE; - nblocks = volsize/volblocksize; + + nblocks = volsize / volblocksize; + /* + * Metadata defaults to using 128k blocks, not volblocksize blocks. For + * this reason, only the data blocks are scaled based on vdev config. + */ + volsize = volsize_from_vdevs(zph, nblocks, volblocksize); + /* start with metadnode L0-L6 */ numdb = 7; /* calculate number of indirects */ diff --git a/usr/src/lib/libzfs/common/libzfs_pool.c b/usr/src/lib/libzfs/common/libzfs_pool.c index 6cc8dce54b..0d87d9f2a8 100644 --- a/usr/src/lib/libzfs/common/libzfs_pool.c +++ b/usr/src/lib/libzfs/common/libzfs_pool.c @@ -22,7 +22,7 @@ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2011, 2017 by Delphix. All rights reserved. - * Copyright (c) 2018, Joyent, Inc. All rights reserved. + * Copyright 2019 Joyent, Inc. * Copyright 2016 Nexenta Systems, Inc. * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com> * Copyright (c) 2017 Datto Inc. @@ -1278,11 +1278,6 @@ zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot, "one or more devices is out of space")); return (zfs_error(hdl, EZFS_BADDEV, msg)); - case ENOTBLK: - zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, - "cache device must be a disk or disk slice")); - return (zfs_error(hdl, EZFS_BADDEV, msg)); - default: return (zpool_standard_error(hdl, errno, msg)); } @@ -1473,12 +1468,6 @@ zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot) (void) zfs_error(hdl, EZFS_POOL_NOTSUP, msg); break; - case ENOTBLK: - zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, - "cache device must be a disk or disk slice")); - (void) zfs_error(hdl, EZFS_BADDEV, msg); - break; - default: (void) zpool_standard_error(hdl, errno, msg); } diff --git a/usr/src/man/man1/mandoc.1 b/usr/src/man/man1/mandoc.1 index 07a1cf4650..f2765db33a 100644 --- a/usr/src/man/man1/mandoc.1 +++ b/usr/src/man/man1/mandoc.1 @@ -1,4 +1,4 @@ -.\" $Id: mandoc.1,v 1.226 2018/07/28 18:34:15 schwarze Exp $ +.\" $Id: mandoc.1,v 1.237 2019/02/23 18:53:54 schwarze Exp $ .\" .\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> .\" Copyright (c) 2012, 2014-2018 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 28 2018 $ +.Dd $Mdocdate: February 23 2019 $ .Dt MANDOC 1 .Os .Sh NAME @@ -256,10 +256,28 @@ and seven for .Xr man 5 . Increasing this is not recommended; it may result in degraded formatting, for example overfull lines or ugly line breaks. +This markup is typically converted to appropriate terminal sequences by +the pager or +.Xr ul 1 . +To remove the markup, pipe the output to +.Xr col 1 +.Fl b +instead. 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 +In particular, opening and closing +.Sq single quotes +are represented as characters number 0x60 and 0x27, respectively, +which agrees with all ASCII standards from 1965 to the latest +revision (2012) and which matches the traditional way in which +.Xr roff 7 +formatters represent single quotes in ASCII output. +This correct ASCII rendering may look strange with modern +Unicode-compatible fonts because contrary to ASCII, Unicode uses +the code point U+0060 for the grave accent only, never for an opening +quote. .Xr man 5 input files in .Xr mdoc 5 @@ -272,6 +290,26 @@ One useful application is for checking that output formats in the same way as the .Xr mdoc 5 source it was generated from. +.It Cm tag Ns Op = Ns Ar term +If the formatted manual page is opened in a pager, +go to the definition of the +.Ar term +rather than showing the manual page from the beginning. +If no +.Ar term +is specified, reuse the first command line argument that is not a +.Ar section +number. +If that argument is in +.Xr apropos 1 +.Ar key Ns = Ns Ar val +format, only the +.Ar val +is used rather than the argument as a whole. +This is useful for commands like +.Ql man -akO tag Ic=ulimit +to search for a keyword and jump right to its definition +in the matching manual pages. .It Cm width Ns = Ns Ar width The output width is set to .Ar width @@ -290,9 +328,9 @@ Equations rendered from .Xr eqn 5 blocks use MathML. .Pp -The +The file .Pa mandoc.css -file documents style-sheet classes available for customising output. +documents style-sheet classes available for customising output. If a style-sheet is not specified with .Fl O Cm style , .Fl T Cm html @@ -327,7 +365,7 @@ Instances of are replaced with the include filename. The default is not to present a hyperlink. -.It Cm man Ns = Ns Ar fmt +.It Cm man Ns = Ns Ar fmt Ns Op ; Ns Ar fmt The string .Ar fmt , for example, @@ -343,12 +381,19 @@ are replaced with the linked manual's name and section, respectively. If no section is included, section 1 is assumed. The default is not to present a hyperlink. +If two formats are given and a file +.Ar %N.%S +exists in the current directory, the first format is used; +otherwise, the second format is used. .It Cm style Ns = Ns Ar style.css The file .Ar style.css is used for an external style-sheet. This must be a valid absolute or relative URI. +.It Cm toc +If an input file contains at least two non-standard sections, +print a table of contents near the beginning of the output. .El .Ss Locale Output By default, @@ -626,7 +671,7 @@ To produce HTML manuals with .Pa mandoc.css as the style-sheet: .Pp -.Dl $ mandoc \-T html -Ostyle=mandoc.css mdoc.5 \*(Gt mdoc.5.html +.Dl $ mandoc \-T html -O style=mandoc.css mdoc.5 > mdoc.5.html .Pp To check over a large set of manuals: .Pp @@ -634,7 +679,7 @@ To check over a large set of manuals: .Pp To produce a series of PostScript manuals for A4 paper: .Pp -.Dl $ mandoc \-T ps \-O paper=a4 mdoc.5 man.5 \*(Gt manuals.ps +.Dl $ mandoc \-T ps \-O paper=a4 mdoc.5 man.5 > manuals.ps .Pp Convert a modern .Xr mdoc 5 @@ -644,20 +689,36 @@ format, for use on systems lacking an .Xr mdoc 5 parser: .Pp -.Dl $ mandoc \-T man foo.mdoc \*(Gt foo.man +.Dl $ mandoc \-T man foo.mdoc > foo.man .Sh DIAGNOSTICS Messages displayed by .Nm follow this format: .Bd -ragged -offset indent .Nm : -.Ar file : Ns Ar line : Ns Ar column : level : message : macro args +.Ar file : Ns Ar line : Ns Ar column : level : message : macro arguments .Pq Ar os .Ed .Pp -Line and column numbers start at 1. +The first three fields identify the +.Ar file +name, +.Ar line +number, and +.Ar column +number of the input file where the message was triggered. +The line and column numbers start at 1. Both are omitted for messages referring to an input file as a whole. -Macro names and arguments are omitted where meaningless. +All +.Ar level +and +.Ar message +strings are explained below. +The name of the +.Ar macro +triggering the message and its +.Ar arguments +are omitted where meaningless. The .Ar os operating system specifier is omitted for messages that are relevant @@ -1562,6 +1623,12 @@ An macro has an argument other than .Cm on or +.It Sy "argument contains two font escapes" +.Pq roff +The second argument of a +.Ic char +request contains more than one font escape sequence. +A wrong font may remain active after using the character. .Cm off . The invalid argument is moved out of the macro, which leaves the macro empty, causing it to toggle the spacing mode. @@ -1610,7 +1677,8 @@ Start it on a new input line to help formatters produce correct spacing. .It Sy "invalid escape sequence" .Pq roff An escape sequence has an invalid opening argument delimiter, lacks the -closing argument delimiter, or the argument has too few characters. +closing argument delimiter, the argument is of an invalid form, or it is +a character escape sequence with an invalid name. If the argument is incomplete, .Ic \e* and @@ -1623,6 +1691,12 @@ and .Ic \ew to the length of the incomplete argument. All other invalid escape sequences are ignored. +.It Sy "undefined escape, printing literally" +.Pq roff +In an escape sequence, the first character +right after the leading backslash is invalid. +That character is printed literally, +which is equivalent to ignoring the backslash. .It Sy "undefined string, using \(dq\(dq" .Pq roff If a string is used without being defined before, @@ -1766,6 +1840,13 @@ or macro. It may be mistyped or unsupported. The request or macro is discarded including its arguments. +.It Sy "skipping request outside macro" +.Pq roff +A +.Ic shift +or +.Ic return +request occurs outside any macro definition and has no effect. .It Sy "skipping insecure request" .Pq roff An input file attempted to run a shell command @@ -1875,6 +1956,14 @@ When parsing for a request or a user-defined macro name to be called, only the escape sequence is discarded. The characters preceding it are used as the request or macro name, the characters following it are used as the arguments to the request or macro. +.It Sy "using macro argument outside macro" +.Pq roff +The escape sequence \e$ occurs outside any macro definition +and expands to the empty string. +.It Sy "argument number is not numeric" +.Pq roff +The argument of the escape sequence \e$ is not a digit; +the escape sequence expands to the empty string. .It Sy "NOT IMPLEMENTED: Bd -file" .Pq mdoc For security reasons, the @@ -1903,6 +1992,13 @@ macro fails to specify the list type. The argument of a .Ic \&ce request is not a number. +.It Sy "argument is not a character" +.Pq roff +The first argument of a +.Ic char +request is neither a single ASCII character +nor a single character escape sequence. +The request is ignored including all its arguments. .It Sy "missing manual name, using \(dq\(dq" .Pq mdoc The first call to @@ -1937,6 +2033,13 @@ or .Ic \&gsize statement has a non-numeric or negative argument or no argument at all. The invalid request or statement is ignored. +.It Sy "excessive shift" +.Pq roff +The argument of a +.Ic shift +request is larger than the number of arguments of the macro that is +currently being executed. +All macro arguments are deleted and \en(.$ is set to zero. .It Sy "NOT IMPLEMENTED: .so with absolute path or \(dq..\(dq" .Pq roff For security reasons, @@ -2059,6 +2162,13 @@ implementations but not by .Nm was found in an input file. It is replaced by a question mark. +.It Sy "unsupported escape sequence" +.Pq roff +An input file contains an escape sequence supported by GNU troff +or Heirloom troff but not by +.Nm , +and it is likely that this will cause information loss +or considerable misformatting. .It Sy "unsupported roff request" .Pq roff An input file contains a diff --git a/usr/src/man/man5/mandoc_char.5 b/usr/src/man/man5/mandoc_char.5 index d1a8ac8bbc..b6b1d7848b 100644 --- a/usr/src/man/man5/mandoc_char.5 +++ b/usr/src/man/man5/mandoc_char.5 @@ -1,8 +1,8 @@ -.\" $Id: mandoc_char.7,v 1.72 2018/08/08 14:30:48 schwarze Exp $ +.\" $Id: mandoc_char.7,v 1.75 2018/12/15 19:30:26 schwarze Exp $ .\" .\" Copyright (c) 2003 Jason McIntyre <jmc@openbsd.org> .\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> -.\" Copyright (c) 2011, 2013, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org> +.\" Copyright (c) 2011,2013,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 @@ -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: August 8 2018 $ +.Dd $Mdocdate: December 15 2018 $ .Dt MANDOC_CHAR 5 .Os .Sh NAME @@ -266,11 +266,13 @@ Spacing: .It Em Input Ta Em Description .It Sq \e\ \& Ta unpaddable non-breaking space .It \e\(ti Ta paddable non-breaking space -.It \e0 Ta unpaddable, breaking digit-width space +.It \e0 Ta digit-width space allowing line break .It \e| Ta one-sixth \e(em narrow space, zero width in nroff mode .It \e^ Ta one-twelfth \e(em half-narrow space, zero width in nroff -.It \e& Ta zero-width space +.It \e& Ta zero-width non-breaking space +.It \e) Ta zero-width space transparent to end-of-sentence detection .It \e% Ta zero-width space allowing hyphenation +.It \e: Ta zero-width space allowing line break .El .Pp Lines: @@ -543,11 +545,13 @@ Accented letters: .It \e(\(aqI Ta \('I Ta acute I .It \e(\(aqO Ta \('O Ta acute O .It \e(\(aqU Ta \('U Ta acute U +.It \e(\(aqY Ta \('Y Ta acute Y .It \e(\(aqa Ta \('a Ta acute a .It \e(\(aqe Ta \('e Ta acute e .It \e(\(aqi Ta \('i Ta acute i .It \e(\(aqo Ta \('o Ta acute o .It \e(\(aqu Ta \('u Ta acute u +.It \e(\(aqy Ta \('y Ta acute y .It \e(\(gaA Ta \(`A Ta grave A .It \e(\(gaE Ta \(`E Ta grave E .It \e(\(gaI Ta \(`I Ta grave I @@ -761,14 +765,16 @@ For backward compatibility with existing manuals, .Xr mandoc 1 also supports the .Pp -.Dl \eN\(aq Ns Ar number Ns \(aq +.Dl \eN\(aq Ns Ar number Ns \(aq and \e[ Ns Cm char Ns Ar number ] .Pp -escape sequence, inserting the character +escape sequences, inserting the character .Ar number from the current character set into the output. Of course, this is inherently non-portable and is already marked -as deprecated in the Heirloom roff manual. -For example, do not use \eN\(aq34\(aq, use \e(dq, or even the plain +as deprecated in the Heirloom roff manual; +on top of that, the second form is a GNU extension. +For example, do not use \eN\(aq34\(aq or \e[char34], use \e(dq, +or even the plain .Sq \(dq character where possible. .Sh COMPATIBILITY diff --git a/usr/src/man/man5/mandoc_roff.5 b/usr/src/man/man5/mandoc_roff.5 index 7a78992ef5..0a9aa7cbd8 100644 --- a/usr/src/man/man5/mandoc_roff.5 +++ b/usr/src/man/man5/mandoc_roff.5 @@ -1,7 +1,7 @@ -.\" $Id: roff.7,v 1.96 2018/04/10 00:52:30 schwarze Exp $ +.\" $Id: roff.7,v 1.111 2019/01/01 03:45:29 schwarze Exp $ .\" .\" Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv> -.\" Copyright (c) 2010-2018 Ingo Schwarze <schwarze@openbsd.org> +.\" Copyright (c) 2010-2019 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: April 10 2018 $ +.Dd $Mdocdate: January 1 2019 $ .Dt ROFF 5 .Os .Sh NAME @@ -39,17 +39,15 @@ or code. To properly format such manuals, the .Xr mandoc 1 -utility supports a tiny subset of +utility supports a subset of .Nm requests and escapes. -Only these requests and escapes supported by +Even though this manual page lists all +.Nm +requests and escape sequences, it only contains partial information +about requests not supported by .Xr mandoc 1 -are documented in the present manual, -together with the basic language syntax shared by -.Nm , -.Xr mdoc 5 , -and -.Xr man 5 . +and about language features that do not matter for manual pages. For complete .Nm manuals, consult the @@ -86,14 +84,10 @@ character, and, in certain circumstances, the tab character. The backslash character .Sq \e indicates the start of an escape sequence, used for example for -.Sx Comments , -.Sx Special Characters , -.Sx Predefined Strings , +.Sx Comments and -user-defined strings defined using the -.Sx ds -request. -For a listing of escape sequences, consult the +.Sx Special Characters . +For a complete listing of escape sequences, consult the .Sx ESCAPE SEQUENCE REFERENCE below. .Ss Comments @@ -139,20 +133,73 @@ One-letter backslash escape. See .Xr mandoc_char 5 for a complete list. -.Ss Text Decoration -Terms may be text-decorated using the -.Sq \ef -escape followed by an indicator: B (bold), I (italic), R (regular), or P -(revert to previous mode). -A numerical representation 3, 2, or 1 (bold, italic, and regular, -respectively) may be used instead. -The indicator or numerical representative may be preceded by C -(constant-width), which is ignored. -.Pp -The two-character indicator -.Sq BI -requests a font that is both bold and italic. -It may not be portable to old roff implementations. +.Ss Font Selection +In +.Xr mdoc 5 +and +.Xr man 5 +documents, fonts are usually selected with macros. +The +.Ic \ef +escape sequence and the +.Ic \&ft +request can be used to manually change the font, +but this is not recommended in +.Xr mdoc 5 +documents. +Such manual font changes are overridden by many subsequent macros. +.Pp +The following fonts are supported: +.Pp +.Bl -tag -width CW -offset indent -compact +.It Cm B +Bold font. +.It Cm BI +A font that is both bold and italic. +.It Cm CB +Bold constant width font. +Same as +.Cm B +in terminal output. +.It Cm CI +Italic constant width font. +Same as +.Cm I +in terminal output. +.It Cm CR +Regular constant width font. +Same as +.Cm R +in terminal output. +.It Cm CW +An alias for +.Cm CR . +.It Cm I +Italic font. +.It Cm P +Return to the previous font. +If a macro caused a font change since the last +.Ic \ef +eascape sequence or +.Ic \&ft +request, this returns to the font before the last font change in +the macro rather than to the font before the last manual font change. +.It Cm R +Roman font. +This is the default font. +.It Cm 1 +An alias for +.Cm R . +.It Cm 2 +An alias for +.Cm I . +.It Cm 3 +An alias for +.Cm B . +.It Cm 4 +An alias for +.Cm BI . +.El .Pp Examples: .Bl -tag -width Ds -offset indent -compact @@ -163,40 +210,6 @@ Write in \fIitalic\fP, then return to previous font mode. .It Li \ef(BIbold italic\efP Write in \f(BIbold italic\fP, then return to previous font mode. .El -.Pp -Text decoration is -.Em not -recommended for -.Xr mdoc 5 , -which encourages semantic annotation. -.Ss Predefined Strings -Predefined strings, like -.Sx Special Characters , -mark special output glyphs. -Predefined strings are escaped with the slash-asterisk, -.Sq \e* : -single-character -.Sq \e*X , -two-character -.Sq \e*(XX , -and N-character -.Sq \e* Ns Bq N . -.Pp -Examples: -.Bl -tag -width Ds -offset indent -compact -.It Li \e*(Am -Two-letter ampersand predefined string. -.It Li \e*q -One-letter double-quote predefined string. -.El -.Pp -Predefined strings are not recommended for use, -as they differ across implementations. -Those supported by -.Xr mandoc 1 -are listed in -.Xr mandoc_char 5 . -Manuals using these predefined strings are almost certainly not portable. .Ss Whitespace Whitespace consists of the space character. In text lines, whitespace is preserved within a line. @@ -206,7 +219,7 @@ Unescaped trailing spaces are stripped from text line input unless in a literal context. In general, trailing whitespace on any input line is discouraged for reasons of portability. -In the rare case that a blank character is needed at the end of an +In the rare case that a space character is needed at the end of an input line, it may be forced by .Sq \e\ \e& . .Pp @@ -225,7 +238,6 @@ Many requests and macros support scaled widths for their arguments. The syntax for a scaled width is .Sq Li [+-]?[0-9]*.[0-9]*[:unit:] , where a decimal must be preceded or followed by at least one digit. -Negative numbers, while accepted, are truncated to zero. .Pp The following scaling units are accepted: .Pp @@ -235,9 +247,9 @@ centimetre .It i inch .It P -pica (~1/6 inch) +pica (1/6 inch) .It p -point (~1/72 inch) +point (1/72 inch) .It f scale .Sq u @@ -257,7 +269,7 @@ character .It u default horizontal span for the terminal .It M -mini-em (~1/100 em) +mini-em (1/100 em) .El .Pp Using anything other than @@ -341,7 +353,7 @@ Macros are provided by the and .Xr man 5 languages and can be defined by the -.Sx \&de +.Ic \&de request. When called, they follow the same syntax as requests, except that macro arguments may optionally be quoted by enclosing them @@ -447,7 +459,7 @@ compatibility mode at all, it handles this request as an alias for .It Ic \&as Ar stringname Op Ar string Append to a user-defined string. The syntax of this request is the same as that of -.Sx \&ds . +.Ic \&ds . If a user-defined string with the specified name does not yet exist, it is set to the empty string before appending. .It Ic \&as1 Ar stringname Op Ar string @@ -539,9 +551,16 @@ This is a groff extension and currently ignored. .It Ic \&ch Ar macroname Op Ar dist Change a trap location. Currently ignored. -.It Ic \&char Ar glyphname Op Ar string -Define a new glyph. -Currently unsupported. +.It Ic \&char Ar glyph Op Ar string +Define or redefine the ASCII character or character escape sequence +.Ar glyph +to be rendered as +.Ar string , +which can be empty. +Only partially supported in +.Xr mandoc 1 ; +may interact incorrectly with +.Ic \&tr . .It Ic \&chop Ar stringname Remove the last character from a macro, string, or diversion. Currently unsupported. @@ -622,7 +641,7 @@ macros, whichever applies to the document in question. .Pp Specifying a custom .Ar endmacro -macro works in the same way as for +works in the same way as for .Ic \&ig ; namely, the call to .Sq Pf . Ar endmacro @@ -665,7 +684,9 @@ produces .Pp in the input stream, and thus in the output: \fI\^XtFree\^\fP. Each occurrence of \e\e$* is replaced with all the arguments, -joined together with single blank characters. +joined together with single space characters. +The variant \e\e$@ is similar, except that each argument is +individually quoted. .Pp Since macros and user-defined strings share a common string table, defining a macro @@ -887,11 +908,23 @@ This is a Heirloom extension and currently ignored. Enable or disable an OpenType feature. This is a Heirloom extension and currently ignored. .It Ic \&fi -Switch to fill mode. -See -.Xr man 5 . -Ignored in -.Xr mdoc 5 . +Break the output line and switch to fill mode, +which is active by default but can be ended with the +.Ic \&nf +request. +In fill mode, input from subsequent input lines is added to +the same output line until the next word no longer fits, +at which point the output line is broken. +This request is implied by the +.Xr mdoc 5 +.Ic \&Sh +macro and by the +.Xr man 5 +.Ic \&SH , +.Ic \&SS , +and +.Ic \&EE +macros. .It Ic \&fkern Ar font minkern Control the use of kerning tables for a font. This is a Heirloom extension and currently ignored. @@ -917,27 +950,12 @@ This is a Heirloom extension and currently ignored. Conditionally define a special font. This is a groff extension and currently ignored. .It Ic \&ft Op Ar font -Change the font. -The following +Change the font; see +.Sx Font Selection . +The .Ar font -arguments are supported: -.Bl -tag -width 4n -offset indent -.It Cm B , BI , 3 , 4 -switches to -.Sy bold -font -.It Cm I , 2 -switches to -.Em underlined -font -.It Cm R , CW , 1 -switches to normal font -.It Cm P No "or no argument" -switches back to the previous font -.El -.Pp -This request takes effect only locally and may be overridden -by macros and escape sequences. +argument defaults to +.Cm P . .It Ic \&ftr Ar newname Op Ar oldname Translate font name. This is a groff extension and currently ignored. @@ -1037,13 +1055,13 @@ is or .Sq o .Pq odd page , -it evaluates to true. +it evaluates to true, and the +.Ar body +starts with the next character. .It If the first character of .Ar condition is -.Sq c -.Pq character available , .Sq e .Pq even page , .Sq t @@ -1051,7 +1069,20 @@ is or .Sq v .Pq vroff mode , -it evaluates to false. +it evaluates to false, and the +.Ar body +starts with the next character. +.It +If the first character of +.Ar condition +is +.Sq c +.Pq character available , +it evaluates to true if the following character is an ASCII character +or a valid character escape sequence, or to false otherwise. +The +.Ar body +starts with the character following that next character. .It If the first character of .Ar condition @@ -1219,7 +1250,7 @@ While evaluating the the unit suffixes described below .Sx Scaling Widths are ignored. -.It Ic \&it Ar expression macro +.It Ic \&itc Ar expression macro Set an input line trap, not counting lines ending with \ec. Currently unsupported. .It Ic \&IX Ar class keystring @@ -1328,11 +1359,22 @@ Declare the need for the specified minimum vertical space before the next trap or the bottom of the page. Currently ignored. .It Ic \&nf -Switch to no-fill mode. -See -.Xr man 5 . -Ignored by -.Xr mdoc 5 . +Break the output line and switch to no-fill mode. +Subsequent input lines are kept together on the same output line +even when exceeding the right margin, +and line breaks in subsequent input cause output line breaks. +This request is implied by the +.Xr mdoc 5 +.Ic \&Bd Fl unfilled +and +.Ic \&Bd Fl literal +macros and by the +.Xr man 5 +.Ic \&EX +macro. +The +.Ic \&fi +request switches back to the default fill mode. .It Ic \&nh Turn off automatic hyphenation mode. Currently ignored. @@ -1346,8 +1388,11 @@ Currently unsupported. Temporarily turn off line numbering. Currently unsupported. .It Ic \&nop Ar body -Execute the rest of the input line as a request or macro line. -Currently unsupported. +Execute the rest of the input line as a request, macro, or text line, +skipping the +.Ic \&nop +request and any space characters immediately following it. +This is mostly used to indent text lines inside macro definitions. .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, @@ -1486,8 +1531,8 @@ Currently ignored. Set the maximum stack depth for recursive macros. This is a Heirloom extension and currently ignored. .It Ic \&return Op Ar twice -Exit a macro and return to the caller. -Currently unsupported. +Exit the presently executed macro and return to the caller. +The argument is currently ignored. .It Ic \&rfschar Ar font glyph ... Remove font-specific fallback glyph definitions. Currently unsupported. @@ -1536,8 +1581,11 @@ This is a Heirloom extension and currently ignored. Change the soft hyphen character. Currently ignored. .It Ic \&shift Op Ar number -Shift macro arguments. -Currently unsupported. +Shift macro arguments +.Ar number +times, by default once: \e\e$i becomes what \e\e$i+number was. +Also decrement \en(.$ by +.Ar number . .It Ic \&sizes Ar size ... Define permissible point sizes. This is a groff extension and currently ignored. @@ -1602,7 +1650,7 @@ Ignored because insecure. Re-start a table layout, retaining the options of the prior table invocation. See -.Sx \&TS . +.Ic \&TS . .It Ic \&ta Op Ar width ... Op Cm T Ar width ... Set tab stops. Each @@ -1623,7 +1671,7 @@ Currently unsupported. .It Ic \&TE End a table context. See -.Sx \&TS . +.Ic \&TS . .It Ic \&ti Oo Cm + Ns | Ns Cm - Oc Ns Ar width Break the output line and indent the next output line by .Ar width . @@ -1726,8 +1774,12 @@ This is a Heirloom extension and currently ignored. Set a page location trap. Currently unsupported. .It Ic \&while Ar condition body -Repeated execution while a condition is true. -Currently unsupported. +Repeated execution while a +.Ar condition +is true, with syntax similar to +.Ic \&if . +Currently implemented with two restrictions: cannot nest, +and each loop must start and end in the same scope. .It Ic \&write Oo \(dq Oc Ns Ar string Write to an open file. Ignored because insecure. @@ -1743,10 +1795,10 @@ This is a Heirloom extension and currently ignored. .El .Ss Numerical expressions The -.Sx \&nr , -.Sx \&if , +.Ic \&nr , +.Ic \&if , and -.Sx \&ie +.Ic \&ie requests accept integer numerical expressions as arguments. These are always evaluated using the C .Vt int @@ -1821,10 +1873,6 @@ The .Xr mandoc 1 .Nm parser recognises the following escape sequences. -Note that the -.Nm -language defines more escape sequences not implemented in -.Xr mandoc 1 . In .Xr mdoc 5 and @@ -1836,228 +1884,315 @@ section above. .Pp A backslash followed by any character not listed here simply prints that character itself. -.Ss \e<newline> +.Bl -tag -width Ds +.It Ic \e<newline> A backslash at the end of an input line can be used to continue the logical input line on the next physical input line, joining the text on both lines together as if it were on a single input line. -.Ss \e<space> +.It Ic \e<space> The escape sequence backslash-space .Pq Sq \e\ \& is an unpaddable space-sized non-breaking space character; see -.Sx Whitespace . -.Ss \e\(dq +.Sx Whitespace +and +.Xr mandoc_char 5 . +.It Ic \e! +Embed text up to and including the end of the input line into the +current diversion or into intermediate output without interpreting +requests, macros, and escapes. +Currently unsupported. +.It Ic \e\(dq The rest of the input line is treated as .Sx Comments . -.Ss \e% +.It Ic \e# +Line continuation with comment. +Discard the rest of the physical input line and continue the logical +input line on the next physical input line, joining the text on +both lines together as if it were on a single input line. +This is a groff extension. +.It Ic \e$ Ns Ar arg +Macro argument expansion, see +.Ic \&de . +.It Ic \e% Hyphenation allowed at this point of the word; ignored by .Xr mandoc 1 . -.Ss \e& -Non-printing zero-width character; see -.Sx Whitespace . -.Ss \e\(aq +.It Ic \e& +Non-printing zero-width character, +often used for various kinds of escaping; see +.Sx Whitespace , +.Xr mandoc_char 5 , +and the +.Dq MACRO SYNTAX +and +.Dq Delimiters +sections in +.Xr mdoc 5 . +.It Ic \e\(aq Acute accent special character; use -.Sq \e(aa +.Ic \e(aa instead. -.Ss \e( Ns Ar cc +.It Ic \e( Ns Ar cc .Sx Special Characters with two-letter names, see .Xr mandoc_char 5 . -.Ss \e* Ns Bq Ar name +.It Ic \e) +Zero-width space transparent to end-of-sentence detection; +ignored by +.Xr mandoc 1 . +.It Ic \e*[ Ns Ar name Ns Ic \&] Interpolate the string with the -.Ar name ; -see -.Sx Predefined Strings -and -.Sx ds . +.Ar name . For short names, there are variants -.No \e* Ns Ar c +.Ic \e* Ns Ar c +and +.Ic \e*( Ns Ar cc . +.Pp +One string is predefined on the +.Nm +language level: +.Ic \e*(.T +expands to the name of the output device, +for example ascii, utf8, ps, pdf, html, or markdown. +.Pp +Macro sets traditionally predefine additional strings which are not +portable and differ across implementations. +Those supported by +.Xr mandoc 1 +are listed in +.Xr mandoc_char 5 . +.Pp +Strings can be defined, changed, and deleted with the +.Ic \&ds , +.Ic \&as , and -.No \e*( Ns Ar cc . -.Ss \e, +.Ic \&rm +requests. +.It Ic \e, Left italic correction (groff extension); ignored by .Xr mandoc 1 . -.Ss \e- +.It Ic \e- Special character -.Dq mathematical minus sign . -.Ss \e/ +.Dq mathematical minus sign ; +see +.Xr mandoc_char 5 +for details. +.It Ic \e/ Right italic correction (groff extension); ignored by .Xr mandoc 1 . -.Ss \e Ns Bq Ar name +.It Ic \e: +Breaking the line is allowed at this point of the word +without inserting a hyphen. +.It Ic \e? +Embed the text up to the next +.Ic \e? +into the current diversion without interpreting requests, macros, +and escapes. +This is a groff extension and currently unsupported. +.It Ic \e[ Ns Ar name Ns Ic \&] .Sx Special Characters with names of arbitrary length, see .Xr mandoc_char 5 . -.Ss \e^ +.It Ic \e^ One-twelfth em half-narrow space character, effectively zero-width in .Xr mandoc 1 . -.Ss \e` +.It Ic \e_ +Underline special character; use +.Ic \e(ul +instead. +.It Ic \e` Grave accent special character; use -.Sq \e(ga +.Ic \e(ga instead. -.Ss \e{ +.It Ic \e{ Begin conditional input; see -.Sx if . -.Ss \e\(ba +.Ic \&if . +.It Ic \e\(ba One-sixth em narrow space character, effectively zero-width in .Xr mandoc 1 . -.Ss \e} +.It Ic \e} End conditional input; see -.Sx if . -.Ss \e~ +.Ic \&if . +.It Ic \e~ Paddable non-breaking space character. -.Ss \e0 +.It Ic \e0 Digit width space character. -.Ss \eA\(aq Ns Ar string Ns \(aq +.It Ic \eA\(aq Ns Ar string Ns Ic \(aq Anchor definition; ignored by .Xr mandoc 1 . -.Ss \eB\(aq Ns Ar string Ns \(aq +.It Ic \ea +Leader character; ignored by +.Xr mandoc 1 . +.It Ic \eB\(aq Ns Ar string Ns Ic \(aq Interpolate .Sq 1 if .Ar string conforms to the syntax of .Sx Numerical expressions -explained above and +explained above or .Sq 0 otherwise. -.Ss \eb\(aq Ns Ar string Ns \(aq +.It Ic \eb\(aq Ns Ar string Ns Ic \(aq Bracket building function; ignored by .Xr mandoc 1 . -.Ss \eC\(aq Ns Ar name Ns \(aq +.It Ic \eC\(aq Ns Ar name Ns Ic \(aq .Sx Special Characters with names of arbitrary length. -.Ss \ec +.It Ic \ec When encountered at the end of an input text line, the next input text line is considered to continue that line, even if there are request or macro lines in between. No whitespace is inserted. -.Ss \eD\(aq Ns Ar string Ns \(aq +.It Ic \eD\(aq Ns Ar string Ns Ic \(aq Draw graphics function; ignored by .Xr mandoc 1 . -.Ss \ed +.It Ic \ed Move down by half a line; ignored by .Xr mandoc 1 . -.Ss \ee +.It Ic \eE +Escape character intended to not be interpreted in copy mode. +In +.Xr mandoc 1 , +it currently does the same as +.Ic \e +itself. +.It Ic \ee Backslash special character. -.Ss \eF Ns Bq Ar name +.It Ic \eF[ Ns Ar name Ns Ic \&] Switch font family (groff extension); ignored by .Xr mandoc 1 . For short names, there are variants -.No \eF Ns Ar c +.Ic \eF Ns Ar c and -.No \eF( Ns Ar cc . -.Ss \ef Ns Bq Ar name +.Ic \eF( Ns Ar cc . +.It Ic \ef[ Ns Ar name Ns Ic \&] Switch to the font .Ar name , see -.Sx Text Decoration . +.Sx Font Selection . For short names, there are variants -.No \ef Ns Ar c +.Ic \ef Ns Ar c and -.No \ef( Ns Ar cc . -.Ss \eg Ns Bq Ar name +.Ic \ef( Ns Ar cc . +An empty name +.Ic \ef[] +defaults to +.Ic \efP . +.It Ic \eg[ Ns Ar name Ns Ic \&] Interpolate the format of a number register; ignored by .Xr mandoc 1 . For short names, there are variants -.No \eg Ns Ar c +.Ic \eg Ns Ar c and -.No \eg( Ns Ar cc . -.Ss \eH\(aq Ns Oo +|- Oc Ns Ar number Ns \(aq +.Ic \eg( Ns Ar cc . +.It Ic \eH\(aq Ns Oo +|- Oc Ns Ar number Ns Ic \(aq Set the height of the current font; ignored by .Xr mandoc 1 . -.Ss \eh\(aq Ns Oo Cm \&| Oc Ns Ar width Ns \(aq +.It Ic \eh\(aq Ns Oo Cm \&| Oc Ns Ar width Ns Ic \(aq Horizontal motion. If the vertical bar is given, the motion is relative to the current indentation. Otherwise, it is relative to the current position. The default scaling unit is .Cm m . -.Ss \ek Ns Bq Ar name +.It Ic \ek[ Ns Ar name Ns Ic \&] Mark horizontal input place in register; ignored by .Xr mandoc 1 . For short names, there are variants -.No \ek Ns Ar c +.Ic \ek Ns Ar c and -.No \ek( Ns Ar cc . -.Ss \eL\(aq Ns Ar number Ns Oo Ar c Oc Ns \(aq +.Ic \ek( Ns Ar cc . +.It Ic \eL\(aq Ns Ar number Ns Oo Ar c Oc Ns Ic \(aq Vertical line drawing function; ignored by .Xr mandoc 1 . -.Ss \el\(aq Ns Ar width Ns Oo Ar c Oc Ns \(aq +.It Ic \el\(aq Ns Ar width Ns Oo Ar c Oc Ns Ic \(aq Draw a horizontal line of .Ar width using the glyph .Ar c . -.Ss \eM Ns Bq Ar name +.It Ic \eM[ Ns Ar name Ns Ic \&] Set fill (background) color (groff extension); ignored by .Xr mandoc 1 . For short names, there are variants -.No \eM Ns Ar c +.Ic \eM Ns Ar c and -.No \eM( Ns Ar cc . -.Ss \em Ns Bq Ar name +.Ic \eM( Ns Ar cc . +.It Ic \em[ Ns Ar name Ns Ic \&] Set glyph drawing color (groff extension); ignored by .Xr mandoc 1 . For short names, there are variants -.No \em Ns Ar c +.Ic \em Ns Ar c and -.No \em( Ns Ar cc . -.Ss \eN\(aq Ns Ar number Ns \(aq +.Ic \em( Ns Ar cc . +.It Ic \eN\(aq Ns Ar number Ns Ic \(aq Character .Ar number on the current font. -.Ss \en Ns Oo +|- Oc Ns Bq Ar name +.It Ic \en Ns Oo +|- Oc Ns Ic \&[ Ns Ar name Ns Ic \&] Interpolate the number register .Ar name . For short names, there are variants -.No \en Ns Ar c +.Ic \en Ns Ar c and -.No \en( Ns Ar cc . +.Ic \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 +.It Ic \eO Ns Ar digit , Ic \eO[5 Ns arguments Ns Ic \&] +Suppress output. +This is a groff extension and currently unsupported. +With an argument of +.Ic 1 , 2 , 3 , +or +.Ic 4 , +it is ignored. +.It Ic \eo\(aq Ns Ar string Ns Ic \(aq Overstrike, writing all the characters contained in the .Ar string to the same output position. In terminal and HTML output modes, only the last one of the characters is visible. -.Ss \ep +.It Ic \ep Break the output line at the end of the current word. -.Ss \eR\(aq Ns Ar name Oo +|- Oc Ns Ar number Ns \(aq +.It Ic \eR\(aq Ns Ar name Oo +|- Oc Ns Ar number Ns Ic \(aq Set number register; ignored by .Xr mandoc 1 . -.Ss \eS\(aq Ns Ar number Ns \(aq +.It Ic \er +Move up by one line; ignored by +.Xr mandoc 1 . +.It Ic \eS\(aq Ns Ar number Ns Ic \(aq Slant output; ignored by .Xr mandoc 1 . -.Ss \es\(aq Ns Oo +|- Oc Ns Ar number Ns \(aq +.It Ic \es\(aq Ns Oo +|- Oc Ns Ar number Ns Ic \(aq Change point size; ignored by .Xr mandoc 1 . Alternative forms -.No \es Ns Oo +|- Oc Ns Ar n , -.No \es Ns Oo +|- Oc Ns \(aq Ns Ar number Ns \(aq , -.No \es Ns Bq Oo +|- Oc Ns Ar number , +.Ic \es Ns Oo +|- Oc Ns Ar n , +.Ic \es Ns Oo +|- Oc Ns Ic \(aq Ns Ar number Ns Ic \(aq , +.Ic \es[ Ns Oo +|- Oc Ns Ar number Ns Ic \&] , and -.No \es Ns Oo +|- Oc Ns Bq Ar number +.Ic \es Ns Oo +|- Oc Ns Ic \&[ Ns Ar number Ns Ic \&] are also parsed and ignored. -.Ss \et +.It Ic \et Horizontal tab; ignored by .Xr mandoc 1 . -.Ss \eu +.It Ic \eu Move up by half a line; ignored by .Xr mandoc 1 . -.Ss \eV Ns Bq Ar name +.It Ic \eV[ Ns Ar name Ns Ic \&] Interpolate an environment variable; ignored by .Xr mandoc 1 . For short names, there are variants -.No \eV Ns Ar c +.Ic \eV Ns Ar c and -.No \eV( Ns Ar cc . -.Ss \ev\(aq Ns Ar number Ns \(aq +.Ic \eV( Ns Ar cc . +.It Ic \ev\(aq Ns Ar number Ns Ic \(aq Vertical motion; ignored by .Xr mandoc 1 . -.Ss \ew\(aq Ns Ar string Ns \(aq +.It Ic \ew\(aq Ns Ar string Ns Ic \(aq Interpolate the width of the .Ar string . The @@ -2066,49 +2201,49 @@ implementation assumes that after expansion of user-defined strings, the .Ar string only contains normal characters, no escape sequences, and that each character has a width of 24 basic units. -.Ss \eX\(aq Ns Ar string Ns \(aq +.It Ic \eX\(aq Ns Ar string Ns Ic \(aq Output .Ar string as device control function; ignored in nroff mode and by .Xr mandoc 1 . -.Ss \ex\(aq Ns Ar number Ns \(aq +.It Ic \ex\(aq Ns Ar number Ns Ic \(aq Extra line space function; ignored by .Xr mandoc 1 . -.Ss \eY Ns Bq Ar name +.It Ic \eY[ Ns Ar name Ns Ic \&] Output a string as a device control function; ignored in nroff mode and by .Xr mandoc 1 . For short names, there are variants -.No \eY Ns Ar c +.Ic \eY Ns Ar c and -.No \eY( Ns Ar cc . -.Ss \eZ\(aq Ns Ar string Ns \(aq +.Ic \eY( Ns Ar cc . +.It Ic \eZ\(aq Ns Ar string Ns Ic \(aq Print .Ar string with zero width and height; ignored by .Xr mandoc 1 . -.Ss \ez +.It Ic \ez Output the next character without advancing the cursor position. +.El .Sh COMPATIBILITY The .Xr mandoc 1 implementation of the .Nm -language is intentionally incomplete. -Unimplemented features include: +language is incomplete. +Major unimplemented features include: .Pp .Bl -dash -compact .It For security reasons, .Xr mandoc 1 never reads or writes external files except via -.Sx \&so +.Ic \&so requests with safe relative paths. .It There is no automatic hyphenation, no adjustment to the right margin, -and no centering; the output is always set flush-left. +and very limited support for centering; the output is always set flush-left. .It -Support for setting tabulator positions -and tabulator and leader characters is missing, +Support for setting tabulator and leader characters is missing, and support for manually changing indentation is limited. .It The @@ -2119,14 +2254,14 @@ output media. .It Width measurements are implemented in a crude way and often yield wrong results. -Explicit movement requests and escapes are ignored. +Support for explicit movement requests and escapes is limited. .It There is no concept of output pages, no support for floats, graphics drawing, and picture inclusion; terminal output is always continuous. .It -Requests regarding color, font families, and glyph manipulation -are ignored. +Requests regarding color, font families, font sizes, +and glyph manipulation are ignored. Font support is very limited. Kerning is not implemented, and no ligatures are produced. .It @@ -2134,17 +2269,17 @@ The .Qq \(aq macro control character does not suppress output line breaks. .It -Diversions are not implemented, +Diversions and environments are not implemented, and support for traps is very incomplete. .It -While recursion is supported, -.Sx \&while -loops are not. +Use of macros is not supported inside +.Xr tbl 5 +code. .El .Pp The special semantics of the .Cm nS -number register is an idiosyncracy of +number register is an idiosyncrasy of .Ox manuals and not supported by other .Xr mdoc 5 diff --git a/usr/src/man/man5/mdoc.5 b/usr/src/man/man5/mdoc.5 index 4bddad05a1..603755894e 100644 --- a/usr/src/man/man5/mdoc.5 +++ b/usr/src/man/man5/mdoc.5 @@ -1,4 +1,4 @@ -.\" $Id: mdoc.7,v 1.271 2018/07/28 18:34:15 schwarze Exp $ +.\" $Id: mdoc.7,v 1.276 2019/02/07 15:45:53 schwarze Exp $ .\" .\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> .\" Copyright (c) 2010, 2011, 2013-2018 Ingo Schwarze <schwarze@openbsd.org> @@ -19,7 +19,7 @@ .\" Copyright 2014 Garrett D'Amore <garrett@damore.org> .\" Copyright 2018 Nexenta Systems, Inc. .\" -.Dd $Mdocdate: July 28 2018 $ +.Dd $Mdocdate: February 7 2019 $ .Dt MDOC 5 .Os .Sh NAME @@ -98,18 +98,18 @@ document consists of a document prologue followed by one or more sections. .Pp The prologue, which consists of the -.Sx \&Dd , -.Sx \&Dt , +.Ic \&Dd , +.Ic \&Dt , and -.Sx \&Os +.Ic \&Os macros in that order, is required for every document. .Pp The first section (sections are denoted by -.Sx \&Sh ) +.Ic \&Sh ) must be the NAME section, consisting of at least one -.Sx \&Nm +.Ic \&Nm followed by -.Sx \&Nd . +.Ic \&Nd . .Pp Following that, convention dictates specifying at least the .Em SYNOPSIS @@ -188,15 +188,15 @@ Multiple names should be separated by commas. .Pp The -.Sx \&Nm +.Ic \&Nm macro(s) must precede the -.Sx \&Nd +.Ic \&Nd macro. .Pp See -.Sx \&Nm +.Ic \&Nm and -.Sx \&Nd . +.Ic \&Nd . .It Em LIBRARY The name of the library containing the documented material, which is assumed to be a function in a section 2, 3, or 9 manual. @@ -206,7 +206,7 @@ The syntax for this is as follows: .Ed .Pp See -.Sx \&Lb . +.Ic \&Lb . .It Em SYNOPSIS Documents the utility invocation syntax, function call syntax, or device configuration. @@ -237,11 +237,11 @@ For the second, function calls (sections 2, 3, 7I, 7P, 9): .Ed .Pp Ordering of -.Sx \&In , -.Sx \&Vt , -.Sx \&Fn , +.Ic \&In , +.Ic \&Vt , +.Ic \&Fn , and -.Sx \&Fo +.Ic \&Fo macros should follow C header-file conventions. .Pp And for the third, configurations (section 7D): @@ -255,40 +255,40 @@ Manuals not in these sections generally don't need a Some macros are displayed differently in the .Em SYNOPSIS section, particularly -.Sx \&Nm , -.Sx \&Cd , -.Sx \&Fd , -.Sx \&Fn , -.Sx \&Fo , -.Sx \&In , -.Sx \&Vt , +.Ic \&Nm , +.Ic \&Cd , +.Ic \&Fd , +.Ic \&Fn , +.Ic \&Fo , +.Ic \&In , +.Ic \&Vt , and -.Sx \&Ft . +.Ic \&Ft . All of these macros are output on their own line. If two such dissimilar macros are pairwise invoked (except for -.Sx \&Ft +.Ic \&Ft before -.Sx \&Fo +.Ic \&Fo or -.Sx \&Fn ) , +.Ic \&Fn ) , they are separated by a vertical space, unless in the case of -.Sx \&Fo , -.Sx \&Fn , +.Ic \&Fo , +.Ic \&Fn , and -.Sx \&Ft , +.Ic \&Ft , which are always separated by vertical space. .Pp When text and macros following an -.Sx \&Nm +.Ic \&Nm macro starting an input line span multiple output lines, all output lines but the first will be indented to align with the text immediately following the -.Sx \&Nm +.Ic \&Nm macro, up to the next -.Sx \&Nm , -.Sx \&Sh , +.Ic \&Nm , +.Ic \&Sh , or -.Sx \&Ss +.Ic \&Ss macro or the end of an enclosing block, whichever comes first. .It Em DESCRIPTION This begins with an expansion of the brief, one line description in @@ -320,12 +320,12 @@ Since the .Em DESCRIPTION section usually contains most of the text of a manual, longer manuals often use the -.Sx \&Ss +.Ic \&Ss macro to form subsections. In very long manuals, the .Em DESCRIPTION may be split into multiple sections, each started by an -.Sx \&Sh +.Ic \&Sh macro followed by a non-standard section name, and each having several subsections, like in the present .Nm @@ -339,7 +339,7 @@ This section documents the return values of functions in sections 2, 3, and 9. .Pp See -.Sx \&Rv . +.Ic \&Rv . .It Em CONTEXT This section lists the contexts in which functions can be called in section 9. The contexts are user, kernel, or interrupt. @@ -351,14 +351,14 @@ The manual provides examples of typical content and formatting. .Pp See -.Sx \&Ev . +.Ic \&Ev . .It Em FILES Documents files used. It's helpful to document both the file name and a short description of how the file is used (created, modified, etc.). .Pp See -.Sx \&Pa . +.Ic \&Pa . .It Em EXIT STATUS This section documents the command exit status for sections 1 and 1M. @@ -367,7 +367,7 @@ Historically, this information was described in a practise that is now discouraged. .Pp See -.Sx \&Ex . +.Ic \&Ex . .It Em EXAMPLES Example usages. This often contains snippets of well-formed, well-tested invocations. @@ -382,13 +382,13 @@ and sections. .Pp See -.Sx \&Bl +.Ic \&Bl .Fl diag . .It Em ERRORS Documents error handling in sections 2, 3, and 9. .Pp See -.Sx \&Er . +.Ic \&Er . .It Em ARCHITECTURE This section is usually absent, but will be present when the interface is specific to one or more architectures. @@ -527,9 +527,9 @@ for example authoritative books or journal articles, may also be provided in this section. .Pp See -.Sx \&Rs +.Ic \&Rs and -.Sx \&Xr . +.Ic \&Xr . .It Em STANDARDS References any standards implemented or used. If not adhering to any standards, the @@ -537,7 +537,7 @@ If not adhering to any standards, the section should be used instead. .Pp See -.Sx \&St . +.Ic \&St . .It Em HISTORY A brief history of the subject, including where it was first implemented, and when it was ported to or reimplemented for the operating system at hand. @@ -546,7 +546,7 @@ Credits to the person or persons who wrote the code and/or documentation. Authors should generally be noted by both name and email address. .Pp See -.Sx \&An . +.Ic \&An . .It Em CAVEATS Common misuses and misunderstandings should be explained in this section. @@ -562,208 +562,201 @@ in the alphabetical .Sx MACRO REFERENCE . .Ss Document preamble and NAME section macros .Bl -column "Brq, Bro, Brc" description -.It Sx \&Dd Ta document date: Ar month day , year -.It Sx \&Dt Ta document title: Ar TITLE SECTION Op Ar arch +.It Sx \&Dd Ta document date: Cm $\&Mdocdate$ | Ar month day , year +.It Sx \&Dt Ta document title: Ar TITLE section Op Ar arch .It Sx \&Os Ta operating system version: Op Ar system Op Ar version .It Sx \&Nm Ta document name (one argument) .It Sx \&Nd Ta document description (one line) .El .Ss Sections and cross references .Bl -column "Brq, Bro, Brc" description -.It Sx \&Sh Ta section header (one line) -.It Sx \&Ss Ta subsection header (one line) -.It Sx \&Sx Ta internal cross reference to a section or subsection -.It Sx \&Xr Ta cross reference to another manual page: Ar name section -.It Sx \&Pp , \&Lp Ta start a text paragraph (no arguments) +.It Ic \&Sh Ta section header (one line) +.It Ic \&Ss Ta subsection header (one line) +.It Ic \&Sx Ta internal cross reference to a section or subsection +.It Ic \&Xr Ta cross reference to another manual page: Ar name section +.It Ic \&Pp Ta start a text paragraph (no arguments) .El .Ss Displays and lists .Bl -column "Brq, Bro, Brc" description -.It Sx \&Bd , \&Ed Ta display block: +.It Ic \&Bd , \&Ed Ta display block: .Fl Ar type .Op Fl offset Ar width .Op Fl compact -.It Sx \&D1 Ta indented display (one line) -.It Sx \&Dl Ta indented literal display (one line) -.It Sx \&Ql Ta in-line literal display: Ql text -.It Sx \&Bl , \&El Ta list block: +.It Ic \&D1 Ta indented display (one line) +.It Ic \&Dl Ta indented literal display (one line) +.It Ic \&Ql Ta in-line literal display: Ql text +.It Ic \&Bl , \&El Ta list block: .Fl Ar type .Op Fl width Ar val .Op Fl offset Ar val .Op Fl compact -.It Sx \&It Ta list item (syntax depends on Fl Ar type ) -.It Sx \&Ta Ta table cell separator in Sx \&Bl Fl column No lists -.It Sx \&Rs , \&%* , \&Re Ta bibliographic block (references) +.It Ic \&It Ta list item (syntax depends on Fl Ar type ) +.It Ic \&Ta Ta table cell separator in Ic \&Bl Fl column No lists +.It Ic \&Rs , \&%* , \&Re Ta bibliographic block (references) .El .Ss Spacing control .Bl -column "Brq, Bro, Brc" description -.It Sx \&Pf Ta prefix, no following horizontal space (one argument) -.It Sx \&Ns Ta roman font, no preceding horizontal space (no arguments) -.It Sx \&Ap Ta apostrophe without surrounding whitespace (no arguments) -.It Sx \&Sm Ta switch horizontal spacing mode: Op Cm on | off -.It Sx \&Bk , \&Ek Ta keep block: Fl words +.It Ic \&Pf Ta prefix, no following horizontal space (one argument) +.It Ic \&Ns Ta roman font, no preceding horizontal space (no arguments) +.It Ic \&Ap Ta apostrophe without surrounding whitespace (no arguments) +.It Ic \&Sm Ta switch horizontal spacing mode: Op Cm on | off +.It Ic \&Bk , \&Ek Ta keep block: Fl words .El .Ss Semantic markup for command line utilities .Bl -column "Brq, Bro, Brc" description -.It Sx \&Nm Ta start a SYNOPSIS block with the name of a utility -.It Sx \&Fl Ta command line options (flags) (>=0 arguments) -.It Sx \&Cm Ta command modifier (>0 arguments) -.It Sx \&Ar Ta command arguments (>=0 arguments) -.It Sx \&Op , \&Oo , \&Oc Ta optional syntax elements (enclosure) -.It Sx \&Ic Ta internal or interactive command (>0 arguments) -.It Sx \&Ev Ta environmental variable (>0 arguments) -.It Sx \&Pa Ta file system path (>=0 arguments) +.It Ic \&Nm Ta start a SYNOPSIS block with the name of a utility +.It Ic \&Fl Ta command line options (flags) (>=0 arguments) +.It Ic \&Cm Ta command modifier (>0 arguments) +.It Ic \&Ar Ta command arguments (>=0 arguments) +.It Ic \&Op , \&Oo , \&Oc Ta optional syntax elements (enclosure) +.It Ic \&Ic Ta internal or interactive command (>0 arguments) +.It Ic \&Ev Ta environmental variable (>0 arguments) +.It Ic \&Pa Ta file system path (>=0 arguments) .El .Ss Semantic markup for function libraries .Bl -column "Brq, Bro, Brc" description -.It Sx \&Lb Ta function library (one argument) -.It Sx \&In Ta include file (one argument) -.It Sx \&Fd Ta other preprocessor directive (>0 arguments) -.It Sx \&Ft Ta function type (>0 arguments) -.It Sx \&Fo , \&Fc Ta function block: Ar funcname -.It Sx \&Fn Ta function name: -.Op Ar functype -.Ar funcname -.Oo -.Op Ar argtype -.Ar argname -.Oc -.It Sx \&Fa Ta function argument (>0 arguments) -.It Sx \&Vt Ta variable type (>0 arguments) -.It Sx \&Va Ta variable name (>0 arguments) -.It Sx \&Dv Ta defined variable or preprocessor constant (>0 arguments) -.It Sx \&Er Ta error constant (>0 arguments) -.It Sx \&Ev Ta environmental variable (>0 arguments) +.It Ic \&Lb Ta function library (one argument) +.It Ic \&In Ta include file (one argument) +.It Ic \&Fd Ta other preprocessor directive (>0 arguments) +.It Ic \&Ft Ta function type (>0 arguments) +.It Ic \&Fo , \&Fc Ta function block: Ar funcname +.It Ic \&Fn Ta function name: Ar funcname Op Ar argument ... +.It Ic \&Fa Ta function argument (>0 arguments) +.It Ic \&Vt Ta variable type (>0 arguments) +.It Ic \&Va Ta variable name (>0 arguments) +.It Ic \&Dv Ta defined variable or preprocessor constant (>0 arguments) +.It Ic \&Er Ta error constant (>0 arguments) +.It Ic \&Ev Ta environmental variable (>0 arguments) .El .Ss Various semantic markup .Bl -column "Brq, Bro, Brc" description -.It Sx \&An Ta author name (>0 arguments) -.It Sx \&Lk Ta hyperlink: Ar uri Op Ar name -.It Sx \&Mt Ta Do mailto Dc hyperlink: Ar address -.It Sx \&Cd Ta kernel configuration declaration (>0 arguments) -.It Sx \&Ad Ta memory address (>0 arguments) -.It Sx \&Ms Ta mathematical symbol (>0 arguments) +.It Ic \&An Ta author name (>0 arguments) +.It Ic \&Lk Ta hyperlink: Ar uri Op Ar display_name +.It Ic \&Mt Ta Do mailto Dc hyperlink: Ar localpart Ns @ Ns Ar domain +.It Ic \&Cd Ta kernel configuration declaration (>0 arguments) +.It Ic \&Ad Ta memory address (>0 arguments) +.It Ic \&Ms Ta mathematical symbol (>0 arguments) .El .Ss Physical markup .Bl -column "Brq, Bro, Brc" description -.It Sx \&Em Ta italic font or underline (emphasis) (>0 arguments) -.It Sx \&Sy Ta boldface font (symbolic) (>0 arguments) -.It Sx \&Li Ta typewriter font (literal) (>0 arguments) -.It Sx \&No Ta return to roman font (normal) (no arguments) -.It Sx \&Bf , \&Ef Ta font block: -.Op Fl Ar type | Cm \&Em | \&Li | \&Sy +.It Ic \&Em Ta italic font or underline (emphasis) (>0 arguments) +.It Ic \&Sy Ta boldface font (symbolic) (>0 arguments) +.It Ic \&No Ta return to roman font (normal) (>0 arguments) +.It Ic \&Bf , \&Ef Ta font block: Fl Ar type | Cm \&Em | \&Li | \&Sy .El .Ss Physical enclosures .Bl -column "Brq, Bro, Brc" description -.It Sx \&Dq , \&Do , \&Dc Ta enclose in typographic double quotes: Dq text -.It Sx \&Qq , \&Qo , \&Qc Ta enclose in typewriter double quotes: Qq text -.It Sx \&Sq , \&So , \&Sc Ta enclose in single quotes: Sq text -.It Sx \&Pq , \&Po , \&Pc Ta enclose in parentheses: Pq text -.It Sx \&Bq , \&Bo , \&Bc Ta enclose in square brackets: Bq text -.It Sx \&Brq , \&Bro , \&Brc Ta enclose in curly braces: Brq text -.It Sx \&Aq , \&Ao , \&Ac Ta enclose in angle brackets: Aq text -.It Sx \&Eo , \&Ec Ta generic enclosure +.It Ic \&Dq , \&Do , \&Dc Ta enclose in typographic double quotes: Dq text +.It Ic \&Qq , \&Qo , \&Qc Ta enclose in typewriter double quotes: Qq text +.It Ic \&Sq , \&So , \&Sc Ta enclose in single quotes: Sq text +.It Ic \&Pq , \&Po , \&Pc Ta enclose in parentheses: Pq text +.It Ic \&Bq , \&Bo , \&Bc Ta enclose in square brackets: Bq text +.It Ic \&Brq , \&Bro , \&Brc Ta enclose in curly braces: Brq text +.It Ic \&Aq , \&Ao , \&Ac Ta enclose in angle brackets: Aq text +.It Ic \&Eo , \&Ec Ta generic enclosure .El .Ss Text production .Bl -column "Brq, Bro, Brc" description -.It Sx \&Ex Fl std Ta standard command exit values: Op Ar utility ... -.It Sx \&Rv Fl std Ta standard function return values: Op Ar function ... -.It Sx \&St Ta reference to a standards document (one argument) -.It Sx \&At Ta At -.It Sx \&Bx Ta Bx -.It Sx \&Bsx Ta Bsx -.It Sx \&Nx Ta Nx -.It Sx \&Fx Ta Fx -.It Sx \&Ox Ta Ox -.It Sx \&Dx Ta Dx +.It Ic \&Ex Fl std Ta standard command exit values: Op Ar utility ... +.It Ic \&Rv Fl std Ta standard function return values: Op Ar function ... +.It Ic \&St Ta reference to a standards document (one argument) +.It Ic \&At Ta At +.It Ic \&Bx Ta Bx +.It Ic \&Bsx Ta Bsx +.It Ic \&Nx Ta Nx +.It Ic \&Fx Ta Fx +.It Ic \&Ox Ta Ox +.It Ic \&Dx Ta Dx .El .Sh MACRO REFERENCE This section is a canonical reference of all macros, arranged alphabetically. For the scoping of individual macros, see .Sx MACRO SYNTAX . -.Ss \&%A +.Bl -tag -width 3n +.It Ic \&%A Ar first_name ... last_name Author name of an -.Sx \&Rs +.Ic \&Rs block. Multiple authors should each be accorded their own -.Sx \%%A +.Ic \%%A line. Author names should be ordered with full or abbreviated forename(s) first, then full surname. -.Ss \&%B +.It Ic \&%B Ar title Book title of an -.Sx \&Rs +.Ic \&Rs block. This macro may also be used in a non-bibliographic context when referring to book titles. -.Ss \&%C +.It Ic \&%C Ar location Publication city or location of an -.Sx \&Rs +.Ic \&Rs block. -.Ss \&%D +.It Ic \&%D Oo Ar month day , Oc Ar year Publication date of an -.Sx \&Rs +.Ic \&Rs block. -Recommended formats of arguments are -.Ar month day , year -or just +Provide the full English name of the +.Ar month +and all four digits of the .Ar year . -.Ss \&%I +.It Ic \&%I Ar name Publisher or issuer name of an -.Sx \&Rs +.Ic \&Rs block. -.Ss \&%J +.It Ic \&%J Ar name Journal name of an -.Sx \&Rs +.Ic \&Rs block. -.Ss \&%N +.It Ic \&%N Ar number Issue number (usually for journals) of an -.Sx \&Rs +.Ic \&Rs block. -.Ss \&%O +.It Ic \&%O Ar line Optional information of an -.Sx \&Rs +.Ic \&Rs block. -.Ss \&%P +.It Ic \&%P Ar number Book or journal page number of an -.Sx \&Rs +.Ic \&Rs block. -.Ss \&%Q +.It Ic \&%Q Ar name Institutional author (school, government, etc.) of an -.Sx \&Rs +.Ic \&Rs block. Multiple institutional authors should each be accorded their own -.Sx \&%Q +.Ic \&%Q line. -.Ss \&%R +.It Ic \&%R Ar name Technical report name of an -.Sx \&Rs +.Ic \&Rs block. -.Ss \&%T +.It Ic \&%T Ar title Article title of an -.Sx \&Rs +.Ic \&Rs block. This macro may also be used in a non-bibliographical context when referring to article titles. -.Ss \&%U +.It Ic \&%U Ar protocol Ns :// Ns Ar path URI of reference document. -.Ss \&%V +.It Ic \&%V Ar number Volume number of an -.Sx \&Rs +.Ic \&Rs block. -.Ss \&Ac +.It Ic \&Ac Close an -.Sx \&Ao +.Ic \&Ao block. Does not have any tail arguments. -.Ss \&Ad +.It Ic \&Ad Ar address Memory address. Do not use this for postal addresses. .Pp Examples: .Dl \&.Ad [0,$] .Dl \&.Ad 0x00000000 -.Ss \&An +.It Ic \&An Fl split | nosplit | Ar first_name ... last_name Author name. Can be used both for the authors of the program, function, or driver documented in the manual, or for the authors of the manual itself. @@ -772,7 +765,7 @@ Requires either the name of an author or one of the following arguments: .Bl -tag -width "-nosplitX" -offset indent -compact .It Fl split Start a new output line before each subsequent invocation of -.Sx \&An . +.Ic \&An . .It Fl nosplit The opposite of .Fl split . @@ -796,25 +789,25 @@ for all other author listings. Examples: .Dl \&.An -nosplit .Dl \&.An Kristaps Dzonsons \&Aq \&Mt kristaps@bsd.lv -.Ss \&Ao +.It Ic \&Ao Ar block Begin a block enclosed by angle brackets. Does not have any head arguments. This macro is almost never useful. See -.Sx \&Aq +.Ic \&Aq for more details. -.Ss \&Ap +.It Ic \&Ap Inserts an apostrophe without any surrounding whitespace. This is generally used as a grammatical device when referring to the verb form of a function. .Pp Examples: .Dl \&.Fn execve \&Ap d -.Ss \&Aq -Encloses its arguments in angle brackets. +.It Ic \&Aq Ar line +Enclose the rest of the input line in angle brackets. The only important use case is for email addresses. See -.Sx \&Mt +.Ic \&Mt for an example. .Pp Occasionally, it is used for names of characters and keys, for example: @@ -825,19 +818,19 @@ key to ... .Ed .Pp For URIs, use -.Sx \&Lk +.Ic \&Lk instead, and -.Sx \&In +.Ic \&In for .Dq #include directives. Never wrap -.Sx \&Ar +.Ic \&Ar in -.Sx \&Aq . +.Ic \&Aq . .Pp Since -.Sx \&Aq +.Ic \&Aq usually renders with non-ASCII characters in non-ASCII output modes, do not use it where the ASCII characters .Sq < @@ -846,15 +839,15 @@ and are required as syntax elements. Instead, use these characters directly in such cases, combining them with the macros -.Sx \&Pf , -.Sx \&Ns , +.Ic \&Pf , +.Ic \&Ns , or -.Sx \&Eo +.Ic \&Eo as needed. .Pp See also -.Sx \&Ao . -.Ss \&Ar +.Ic \&Ao . +.It Ic \&Ar Op Ar placeholder ... Command arguments. If an argument is not provided, the string .Dq file ...\& @@ -866,13 +859,13 @@ Examples: .Dl ".Ar arg1 , arg2 ." .Pp The arguments to the -.Sx \&Ar +.Ic \&Ar macro are names and placeholders for command arguments; for fixed strings to be passed verbatim as arguments, use -.Sx \&Fl +.Ic \&Fl or -.Sx \&Cm . -.Ss \&At +.Ic \&Cm . +.It Ic \&At Op Ar version Formats an .At version. @@ -897,28 +890,20 @@ Examples: .Dl \&.At V.1 .Pp See also -.Sx \&Bsx , -.Sx \&Bx , -.Sx \&Dx , -.Sx \&Fx , -.Sx \&Nx , +.Ic \&Bsx , +.Ic \&Bx , +.Ic \&Dx , +.Ic \&Fx , +.Ic \&Nx , and -.Sx \&Ox . -.Ss \&Bc +.Ic \&Ox . +.It Ic \&Bc Close a -.Sx \&Bo +.Ic \&Bo block. Does not have any tail arguments. -.Ss \&Bd +.It Ic \&Bd Fl Ns Ar type Oo Fl offset Ar width Oc Op Fl compact Begin a display block. -Its syntax is as follows: -.Bd -ragged -offset indent -.Pf \. Sx \&Bd -.Fl Ns Ar type -.Op Fl offset Ar width -.Op Fl compact -.Ed -.Pp Display blocks are used to select a different indentation and justification than the one used by the surrounding text. They may contain both macro lines and text lines. @@ -1004,20 +989,11 @@ Examples: .Ed .Pp See also -.Sx \&D1 +.Ic \&D1 and -.Sx \&Dl . -.Ss \&Bf +.Ic \&Dl . +.It Ic \&Bf Fl emphasis | literal | symbolic | Cm \&Em | \&Li | \&Sy Change the font mode for a scoped block of text. -Its syntax is as follows: -.Bd -ragged -offset indent -.Pf \. Sx \&Bf -.Oo -.Fl emphasis | literal | symbolic | -.Cm \&Em | \&Li | \&Sy -.Oc -.Ed -.Pp The .Fl emphasis and @@ -1033,30 +1009,27 @@ and Without an argument, this macro does nothing. The font mode continues until broken by a new font mode in a nested scope or -.Sx \&Ef +.Ic \&Ef is encountered. .Pp See also -.Sx \&Li , -.Sx \&Ef , -.Sx \&Em , +.Ic \&Li , +.Ic \&Ef , +.Ic \&Em , and -.Sx \&Sy . -.Ss \&Bk +.Ic \&Sy . +.It Ic \&Bk Fl words For each macro, keep its output together on the same output line, until the end of the macro or the end of the input line is reached, whichever comes first. Line breaks in text lines are unaffected. -The syntax is as follows: -.Pp -.D1 Pf \. Sx \&Bk Fl words .Pp The .Fl words argument is required; additional arguments are ignored. .Pp The following example will not break within each -.Sx \&Op +.Ic \&Op macro line: .Bd -literal -offset indent \&.Bk \-words @@ -1067,20 +1040,18 @@ macro line: .Pp Be careful in using over-long lines within a keep block! Doing so will clobber the right margin. -.Ss \&Bl -Begin a list. -Lists consist of items specified using the -.Sx \&It -macro, containing a head or a body or both. -The list syntax is as follows: -.Bd -ragged -offset indent -.Pf \. Sx \&Bl +.It Xo +.Ic \&Bl .Fl Ns Ar type .Op Fl width Ar val .Op Fl offset Ar val .Op Fl compact -.Op HEAD ... -.Ed +.Op Ar col ... +.Xc +Begin a list. +Lists consist of items specified using the +.Ic \&It +macro, containing a head or a body or both. .Pp The list .Ar type @@ -1090,7 +1061,7 @@ The and .Fl offset arguments accept macro names as described for -.Sx \&Bd +.Ic \&Bd .Fl offset , scaling widths as described in .Xr mandoc_roff 5 , @@ -1126,14 +1097,14 @@ specifies the width of one column. If the first line of the body of a .Fl column list is not an -.Sx \&It +.Ic \&It macro line, -.Sx \&It +.Ic \&It contexts spanning one input line each are implied until an -.Sx \&It +.Ic \&It macro line is encountered, at which point items start being interpreted as described in the -.Sx \&It +.Ic \&It documentation. .It Fl dash Like @@ -1196,10 +1167,10 @@ and lists may not be portable. .Pp See also -.Sx \&El +.Ic \&El and -.Sx \&It . -.Ss \&Bo +.Ic \&It . +.It Ic \&Bo Ar block Begin a block enclosed by square brackets. Does not have any head arguments. .Pp @@ -1210,8 +1181,8 @@ Examples: .Ed .Pp See also -.Sx \&Bq . -.Ss \&Bq +.Ic \&Bq . +.It Ic \&Bq Ar line Encloses its arguments in square brackets. .Pp Examples: @@ -1220,19 +1191,19 @@ Examples: .Em Remarks : this macro is sometimes abused to emulate optional arguments for commands; the correct macros to use for this purpose are -.Sx \&Op , -.Sx \&Oo , +.Ic \&Op , +.Ic \&Oo , and -.Sx \&Oc . +.Ic \&Oc . .Pp See also -.Sx \&Bo . -.Ss \&Brc +.Ic \&Bo . +.It Ic \&Brc Close a -.Sx \&Bro +.Ic \&Bro block. Does not have any tail arguments. -.Ss \&Bro +.It Ic \&Bro Ar block Begin a block enclosed by curly braces. Does not have any head arguments. .Pp @@ -1243,16 +1214,16 @@ Examples: .Ed .Pp See also -.Sx \&Brq . -.Ss \&Brq +.Ic \&Brq . +.It Ic \&Brq Ar line Encloses its arguments in curly braces. .Pp Examples: .Dl \&.Brq 1 , ... , \&Va n .Pp See also -.Sx \&Bro . -.Ss \&Bsx +.Ic \&Bro . +.It Ic \&Bsx Op Ar version Format the .Bsx version provided as an argument, or a default value if @@ -1263,18 +1234,18 @@ Examples: .Dl \&.Bsx .Pp See also -.Sx \&At , -.Sx \&Bx , -.Sx \&Dx , -.Sx \&Fx , -.Sx \&Nx , +.Ic \&At , +.Ic \&Bx , +.Ic \&Dx , +.Ic \&Fx , +.Ic \&Nx , and -.Sx \&Ox . -.Ss \&Bt +.Ic \&Ox . +.It Ic \&Bt Supported only for compatibility, do not use this in new manuals. Prints .Dq is currently in beta test. -.Ss \&Bx +.It Ic \&Bx Op Ar version Op Ar variant Format the .Bx version provided as an argument, or a default value if no @@ -1286,14 +1257,14 @@ Examples: .Dl \&.Bx .Pp See also -.Sx \&At , -.Sx \&Bsx , -.Sx \&Dx , -.Sx \&Fx , -.Sx \&Nx , +.Ic \&At , +.Ic \&Bsx , +.Ic \&Dx , +.Ic \&Fx , +.Ic \&Nx , and -.Sx \&Ox . -.Ss \&Cd +.Ic \&Ox . +.It Ic \&Cd Ar line Kernel configuration declaration. It is found in pages for .Bx @@ -1305,13 +1276,13 @@ Examples: .Em Remarks : this macro is commonly abused by using quoted literals to retain whitespace and align consecutive -.Sx \&Cd +.Ic \&Cd declarations. This practise is discouraged. -.Ss \&Cm +.It Ic \&Cm Ar keyword ... Command modifiers. Typically used for fixed strings passed as arguments, unless -.Sx \&Fl +.Ic \&Fl is more appropriate. Also useful when specifying configuration options or keys. .Pp @@ -1321,7 +1292,7 @@ Examples: .Dl ".Nm dd Cm if= Ns Ar file1 Cm of= Ns Ar file2" .Dl ".Cm IdentityFile Pa ~/.ssh/id_rsa" .Dl ".Cm LogLevel Dv DEBUG" -.Ss \&D1 +.It Ic \&D1 Ar line One-line indented display. This is formatted by the default rules and is useful for simple indented statements. @@ -1331,29 +1302,26 @@ Examples: .Dl \&.D1 \&Fl abcdefgh .Pp See also -.Sx \&Bd +.Ic \&Bd and -.Sx \&Dl . -.Ss \&Db +.Ic \&Dl . +.It Ic \&Db This macro is obsolete. No replacement is needed. It is ignored by .Xr mandoc 1 and groff including its arguments. It was formerly used to toggle a debugging mode. -.Ss \&Dc +.It Ic \&Dc Close a -.Sx \&Do +.Ic \&Do block. Does not have any tail arguments. -.Ss \&Dd +.It Ic \&Dd Cm $\&Mdocdate$ | Ar month day , year Document date for display in the page footer. This is the mandatory first macro of any .Nm manual. -Its syntax is as follows: -.Pp -.D1 Pf \. Sx \&Dd Ar month day , year .Pp The .Ar month @@ -1393,10 +1361,10 @@ Examples: .Dl \&.Dd July 2, 2018 .Pp See also -.Sx \&Dt +.Ic \&Dt and -.Sx \&Os . -.Ss \&Dl +.Ic \&Os . +.It Ic \&Dl Ar line One-line indented display. This is formatted as literal text and is useful for commands and invocations. @@ -1406,12 +1374,11 @@ Examples: .Dl \&.Dl % mandoc mdoc.5 \e(ba less .Pp See also -.Sx \&Ql , -.Sx \&Bd -.Fl literal , +.Ic \&Ql , +.Ic \&Bd Fl literal , and -.Sx \&D1 . -.Ss \&Do +.Ic \&D1 . +.It Ic \&Do Ar block Begin a block enclosed by double quotes. Does not have any head arguments. .Pp @@ -1424,8 +1391,8 @@ April is the cruellest month .Ed .Pp See also -.Sx \&Dq . -.Ss \&Dq +.Ic \&Dq . +.It Ic \&Dq Ar line Encloses its arguments in .Dq typographic double-quotes. @@ -1437,22 +1404,15 @@ Examples: .Ed .Pp See also -.Sx \&Qq , -.Sx \&Sq , +.Ic \&Qq , +.Ic \&Sq , and -.Sx \&Do . -.Ss \&Dt +.Ic \&Do . +.It Ic \&Dt Ar TITLE section Op Ar arch Document title for display in the page header. This is the mandatory second macro of any .Nm file. -Its syntax is as follows: -.Bd -ragged -offset indent -.Pf \. Sx \&Dt -.Ar TITLE -.Ar section -.Op Ar arch -.Ed .Pp Its arguments are as follows: .Bl -tag -width section -offset 2n @@ -1473,7 +1433,7 @@ it should by convention be all caps. This specifies the machine architecture a manual page applies to, where relevant. .El -.Ss \&Dv +.It Ic \&Dv Defined variables such as preprocessor constants, constant symbols, enumeration values, and so on. .Pp @@ -1483,16 +1443,16 @@ Examples: .Dl \&.Dv STDOUT_FILENO .Pp See also -.Sx \&Er +.Ic \&Er and -.Sx \&Ev +.Ic \&Ev for special-purpose constants, -.Sx \&Va +.Ic \&Va for variable symbols, and -.Sx \&Fd +.Ic \&Fd for listing preprocessor variable definitions in the .Em SYNOPSIS . -.Ss \&Dx +.It Ic \&Dx Op Ar version Format the .Dx version provided as an argument, or a default @@ -1503,55 +1463,49 @@ Examples: .Dl \&.Dx .Pp See also -.Sx \&At , -.Sx \&Bsx , -.Sx \&Bx , -.Sx \&Fx , -.Sx \&Nx , +.Ic \&At , +.Ic \&Bsx , +.Ic \&Bx , +.Ic \&Fx , +.Ic \&Nx , and -.Sx \&Ox . -.Ss \&Ec +.Ic \&Ox . +.It Ic \&Ec Op Ar closing_delimiter Close a scope started by -.Sx \&Eo . -Its syntax is as follows: -.Pp -.D1 Pf \. Sx \&Ec Op Ar TERM +.Ic \&Eo . .Pp The -.Ar TERM +.Ar closing_delimiter argument is used as the enclosure tail, for example, specifying \e(rq will emulate -.Sx \&Dc . -.Ss \&Ed +.Ic \&Dc . +.It Ic \&Ed End a display context started by -.Sx \&Bd . -.Ss \&Ef +.Ic \&Bd . +.It Ic \&Ef End a font mode context started by -.Sx \&Bf . -.Ss \&Ek +.Ic \&Bf . +.It Ic \&Ek End a keep context started by -.Sx \&Bk . -.Ss \&El +.Ic \&Bk . +.It Ic \&El End a list context started by -.Sx \&Bl . -.Pp +.Ic \&Bl . See also -.Sx \&Bl -and -.Sx \&It . -.Ss \&Em +.Ic \&It . +.It Ic \&Em Ar word ... Request an italic font. If the output device does not provide that, underline. .Pp This is most often used for stress emphasis (not to be confused with importance, see -.Sx \&Sy ) . +.Ic \&Sy ) . In the rare cases where none of the semantic markup macros fit, it can also be used for technical terms and placeholders, except that for syntax elements, -.Sx \&Sy +.Ic \&Sy and -.Sx \&Ar +.Ic \&Ar are preferred, respectively. .Pp Examples: @@ -1565,32 +1519,27 @@ to save the pattern space for subsequent retrieval. .Ed .Pp See also -.Sx \&Bf , -.Sx \&Li , -.Sx \&No , +.Ic \&No , +.Ic \&Ql , and -.Sx \&Sy . -.Ss \&En +.Ic \&Sy . +.It Ic \&En Ar word ... This macro is obsolete. Use -.Sx \&Eo +.Ic \&Eo or any of the other enclosure macros. .Pp It encloses its argument in the delimiters specified by the last -.Sx \&Es +.Ic \&Es macro. -.Ss \&Eo +.It Ic \&Eo Op Ar opening_delimiter An arbitrary enclosure. -Its syntax is as follows: -.Pp -.D1 Pf \. Sx \&Eo Op Ar TERM -.Pp The -.Ar TERM +.Ar opening_delimiter argument is used as the enclosure head, for example, specifying \e(lq will emulate -.Sx \&Do . -.Ss \&Er +.Ic \&Do . +.It Ic \&Er Ar identifier ... Error constants for definitions of the .Va errno libc global variable. @@ -1601,18 +1550,18 @@ Examples: .Dl \&.Er ENOENT .Pp See also -.Sx \&Dv +.Ic \&Dv for general constants. -.Ss \&Es +.It Ic \&Es Ar opening_delimiter closing_delimiter This macro is obsolete. Use -.Sx \&Eo +.Ic \&Eo or any of the other enclosure macros. .Pp It takes two arguments, defining the delimiters to be used by subsequent -.Sx \&En +.Ic \&En macros. -.Ss \&Ev +.It Ic \&Ev Ar identifier ... Environmental variables such as those specified in .Xr environ 5 . .Pp @@ -1621,38 +1570,26 @@ Examples: .Dl \&.Ev PATH .Pp See also -.Sx \&Dv +.Ic \&Dv for general constants. -.Ss \&Ex +.It Ic \&Ex Fl std Op Ar utility ... Insert a standard sentence regarding command exit values of 0 on success and >0 on failure. This is most often used in section 1 and 1M manual pages. -Its syntax is as follows: -.Pp -.D1 Pf \. Sx \&Ex Fl std Op Ar utility ... .Pp If .Ar utility is not specified, the document's name set by -.Sx \&Nm +.Ic \&Nm is used. Multiple .Ar utility arguments are treated as separate utilities. .Pp See also -.Sx \&Rv . -.Ss \&Fa +.Ic \&Rv . +.It Ic \&Fa Ar argument ... Function argument or parameter. -Its syntax is as follows: -.Bd -ragged -offset indent -.Pf \. Sx \&Fa -.Qo -.Op Ar argtype -.Op Ar argname -.Qc Ar \&... -.Ed -.Pp Each argument may be a name and a type (recommended for the .Em SYNOPSIS section), a name alone (for function invocations), @@ -1660,22 +1597,22 @@ or a type alone (for function prototypes). If both a type and a name are given or if the type consists of multiple words, all words belonging to the same function argument have to be given in a single argument to the -.Sx \&Fa +.Ic \&Fa macro. .Pp This macro is also used to specify the field name of a structure. .Pp Most often, the -.Sx \&Fa +.Ic \&Fa macro is used in the .Em SYNOPSIS within -.Sx \&Fo +.Ic \&Fo blocks when documenting multi-line function prototypes. If invoked with multiple arguments, the arguments are separated by a comma. Furthermore, if the following macro is another -.Sx \&Fa , +.Ic \&Fa , the last argument will also have a trailing comma. .Pp Examples: @@ -1684,23 +1621,16 @@ Examples: .Dl \&.Fa \(dqchar *\(dq size_t .Pp See also -.Sx \&Fo . -.Ss \&Fc +.Ic \&Fo . +.It Ic \&Fc End a function context started by -.Sx \&Fo . -.Ss \&Fd +.Ic \&Fo . +.It Ic \&Fd Pf # Ar directive Op Ar argument ... Preprocessor directive, in particular for listing it in the .Em SYNOPSIS . Historically, it was also used to document include files. The latter usage has been deprecated in favour of -.Sx \&In . -.Pp -Its syntax is as follows: -.Bd -ragged -offset indent -.Pf \. Sx \&Fd -.Li # Ns Ar directive -.Op Ar argument ... -.Ed +.Ic \&In . .Pp Examples: .Dl \&.Fd #define sa_handler __sigaction_u.__sa_handler @@ -1712,10 +1642,10 @@ Examples: .Pp See also .Sx MANUAL STRUCTURE , -.Sx \&In , +.Ic \&In , and -.Sx \&Dv . -.Ss \&Fl +.Ic \&Dv . +.It Ic \&Fl Op Ar word ... Command-line flag or option. Used when listing arguments to command-line utilities. Prints a fixed-width hyphen @@ -1733,16 +1663,9 @@ Examples: .Dl ".Fl o Fl" .Pp See also -.Sx \&Cm . -.Ss \&Fn +.Ic \&Cm . +.It Ic \&Fn Ar funcname Op Ar argument ... A function name. -Its syntax is as follows: -.Bd -ragged -offset indent -.Pf . Sx \&Fn -.Op Ar functype -.Ar funcname -.Op Oo Ar argtype Oc Ar argname -.Ed .Pp Function arguments are surrounded in parenthesis and are delimited by commas. @@ -1756,62 +1679,55 @@ Examples: .Dl \&.Fn \(dqint funcname\(dq \(dqint arg0\(dq \(dqint arg1\(dq .Dl \&.Fn funcname \(dqint arg0\(dq .Dl \&.Fn funcname arg0 -.Pp -.Bd -literal -offset indent -compact +.Bd -literal -offset indent \&.Ft functype \&.Fn funcname .Ed .Pp When referring to a function documented in another manual page, use -.Sx \&Xr +.Ic \&Xr instead. See also .Sx MANUAL STRUCTURE , -.Sx \&Fo , +.Ic \&Fo , and -.Sx \&Ft . -.Ss \&Fo +.Ic \&Ft . +.It Ic \&Fo Ar funcname Begin a function block. This is a multi-line version of -.Sx \&Fn . -Its syntax is as follows: -.Pp -.D1 Pf \. Sx \&Fo Ar funcname +.Ic \&Fn . .Pp Invocations usually occur in the following context: .Bd -ragged -offset indent -.Pf \. Sx \&Ft Ar functype +.Pf \. Ic \&Ft Ar functype .br -.Pf \. Sx \&Fo Ar funcname +.Pf \. Ic \&Fo Ar funcname .br -.Pf \. Sx \&Fa Qq Ar argtype Ar argname +.Pf \. Ic \&Fa Qq Ar argtype Ar argname .br \&.\.\. .br -.Pf \. Sx \&Fc +.Pf \. Ic \&Fc .Ed .Pp A -.Sx \&Fo +.Ic \&Fo scope is closed by -.Sx \&Fc . +.Ic \&Fc . .Pp See also .Sx MANUAL STRUCTURE , -.Sx \&Fa , -.Sx \&Fc , +.Ic \&Fa , +.Ic \&Fc , and -.Sx \&Ft . -.Ss \&Fr +.Ic \&Ft . +.It Ic \&Fr Ar number This macro is obsolete. No replacement markup is needed. .Pp It was used to show numerical function return values in an italic font. -.Ss \&Ft +.It Ic \&Ft Ar functype A function type. -Its syntax is as follows: -.Pp -.D1 Pf \. Sx \&Ft Ar functype .Pp In the .Em SYNOPSIS @@ -1826,10 +1742,10 @@ Examples: .Pp See also .Sx MANUAL STRUCTURE , -.Sx \&Fn , +.Ic \&Fn , and -.Sx \&Fo . -.Ss \&Fx +.Ic \&Fo . +.It Ic \&Fx Op Ar version Format the .Fx version provided as an argument, or a default value @@ -1840,25 +1756,21 @@ Examples: .Dl \&.Fx .Pp See also -.Sx \&At , -.Sx \&Bsx , -.Sx \&Bx , -.Sx \&Dx , -.Sx \&Nx , +.Ic \&At , +.Ic \&Bsx , +.Ic \&Bx , +.Ic \&Dx , +.Ic \&Nx , and -.Sx \&Ox . -.Ss \&Hf +.Ic \&Ox . +.It Ic \&Hf Ar filename This macro is not implemented in .Xr mandoc 1 . -.Pp It was used to include the contents of a (header) file literally. -The syntax was: -.Pp -.Dl Pf . Sx \&Hf Ar filename -.Ss \&Ic +.It Ic \&Ic Ar keyword ... Designate an internal or interactive command. This is similar to -.Sx \&Cm +.Ic \&Cm but used for instructions rather than values. .Pp Examples: @@ -1867,13 +1779,14 @@ Examples: .Dl \&.Ic alias .Pp Note that using -.Sx \&Bd Fl literal +.Ic \&Ql , +.Ic \&Dl , or -.Sx \&D1 -is preferred for displaying code; the -.Sx \&Ic -macro is used when referring to specific instructions. -.Ss \&In +.Ic \&Bd Fl literal +is preferred for displaying code samples; the +.Ic \&Ic +macro is used when referring to an individual command name. +.It Ic \&In Ar filename The name of an include file. This macro is most often used in section 2, 3, and 9 manual pages. .Pp @@ -1892,7 +1805,7 @@ Examples: .Pp See also .Sx MANUAL STRUCTURE . -.Ss \&It +.It Ic \&It Op Ar head A list item. The syntax of this macro depends on the list type. .Pp @@ -1905,7 +1818,7 @@ and .Fl diag have the following syntax: .Pp -.D1 Pf \. Sx \&It Ar args +.D1 Pf \. Ic \&It Ar args .Pp Lists of type .Fl bullet , @@ -1916,20 +1829,20 @@ and .Fl item have the following syntax: .Pp -.D1 Pf \. Sx \&It +.D1 Pf \. Ic \&It .Pp with subsequent lines interpreted within the scope of the -.Sx \&It +.Ic \&It until either a closing -.Sx \&El +.Ic \&El or another -.Sx \&It . +.Ic \&It . .Pp The .Fl tag list has the following syntax: .Pp -.D1 Pf \. Sx \&It Op Cm args +.D1 Pf \. Ic \&It Op Cm args .Pp Subsequent lines are interpreted as with .Fl bullet @@ -1942,13 +1855,13 @@ The list is the most complicated. Its syntax is as follows: .Pp -.D1 Pf \. Sx \&It Ar cell Op Sx \&Ta Ar cell ... -.D1 Pf \. Sx \&It Ar cell Op <TAB> Ar cell ... +.D1 Pf \. Ic \&It Ar cell Op Ic \&Ta Ar cell ... +.D1 Pf \. Ic \&It Ar cell Op <TAB> Ar cell ... .Pp The arguments consist of one or more lines of text and macros representing a complete table line. Cells within the line are delimited by the special -.Sx \&Ta +.Ic \&Ta block macro or by literal tab characters. .Pp Using literal tabs is strongly discouraged because they are very @@ -1962,16 +1875,16 @@ that word is never interpreted as a macro call, but always output literally. .Pp The tab cell delimiter may only be used within the -.Sx \&It +.Ic \&It line itself; on following lines, only the -.Sx \&Ta +.Ic \&Ta macro can be used to delimit cells, and portability requires that -.Sx \&Ta +.Ic \&Ta is called by other macros: some parsers do not recognize it when it appears as the first macro on a line. .Pp Note that quoted strings may span tab-delimited cells on an -.Sx \&It +.Ic \&It line. For example, .Pp @@ -1981,19 +1894,16 @@ will preserve the whitespace before both commas, but not the whitespace before the semicolon. .Pp See also -.Sx \&Bl . -.Ss \&Lb +.Ic \&Bl . +.It Ic \&Lb Cm lib Ns Ar name Specify a library. -The syntax is as follows: -.Pp -.D1 Pf \. Sx \&Lb Ar library .Pp The -.Ar library +.Ar name parameter may be a system library, such as -.Cm libz +.Cm z or -.Cm libpam , +.Cm pam , in which case a small library description is printed next to the linker invocation; or a custom library, in which case the library name is printed in quotes. @@ -2005,71 +1915,56 @@ section as described in Examples: .Dl \&.Lb libz .Dl \&.Lb mdoc -.Ss \&Li -Denotes text that should be in a -.Li literal -font mode. -Note that this is a presentation term and should not be used for -stylistically decorating technical terms. -.Pp -On terminal output devices, this is often indistinguishable from -normal text. -.Pp -See also -.Sx \&Bf , -.Sx \&Em , -.Sx \&No , -and -.Sx \&Sy . -.Ss \&Lk +.It Ic \&Li Ar word ... +Request a typewriter (literal) font. +Deprecated because on terminal output devices, this is usually +indistinguishable from normal text. +For literal displays, use +.Ic \&Ql Pq in-line , +.Ic \&Dl Pq single line , +or +.Ic \&Bd Fl literal Pq multi-line +instead. +.It Ic \&Lk Ar uri Op Ar display_name Format a hyperlink. -Its syntax is as follows: -.Pp -.D1 Pf \. Sx \&Lk Ar uri Op Ar name .Pp Examples: .Dl \&.Lk http://bsd.lv \(dqThe BSD.lv Project\(dq .Dl \&.Lk http://bsd.lv .Pp See also -.Sx \&Mt . -.Ss \&Lp -Synonym for -.Sx \&Pp . -.Ss \&Ms +.Ic \&Mt . +.It Ic \&Lp +Deprecated synonym for +.Ic \&Pp . +.It Ic \&Ms Ar name Display a mathematical symbol. -Its syntax is as follows: -.Pp -.D1 Pf \. Sx \&Ms Ar symbol .Pp Examples: .Dl \&.Ms sigma .Dl \&.Ms aleph -.Ss \&Mt +.It Ic \&Mt Ar localpart Ns @ Ns Ar domain Format a .Dq mailto: hyperlink. -Its syntax is as follows: -.Pp -.D1 Pf \. Sx \&Mt Ar address .Pp Examples: .Dl \&.Mt discuss@manpages.bsd.lv .Dl \&.An Kristaps Dzonsons \&Aq \&Mt kristaps@bsd.lv -.Ss \&Nd +.It Ic \&Nd Ar line A one line description of the manual's content. This is the mandatory last macro of the .Em NAME section and not appropriate for other sections. .Pp Examples: -.Dl Pf . Sx \&Nd mdoc language reference -.Dl Pf . Sx \&Nd format and display UNIX manuals +.Dl Pf . Ic \&Nd mdoc language reference +.Dl Pf . Ic \&Nd format and display UNIX manuals .Pp The -.Sx \&Nd +.Ic \&Nd macro technically accepts child macros and terminates with a subsequent -.Sx \&Sh +.Ic \&Sh invocation. Do not assume this behaviour: some .Xr whatis 1 @@ -2077,13 +1972,13 @@ database generators are not smart enough to parse more than the line arguments and will display macros verbatim. .Pp See also -.Sx \&Nm . -.Ss \&Nm +.Ic \&Nm . +.It Ic \&Nm Op Ar name The name of the manual page, or \(em in particular in section 1 pages \(em of an additional command or feature documented in the manual page. When first invoked, the -.Sx \&Nm +.Ic \&Nm macro expects a single argument, the name of the manual page. Usually, the first invocation happens in the .Em NAME @@ -2091,7 +1986,7 @@ section of the page. The specified name will be remembered and used whenever the macro is called again without arguments later in the page. The -.Sx \&Nm +.Ic \&Nm macro uses .Sx Block full-implicit semantics when invoked as the first macro on an input line in the @@ -2111,41 +2006,40 @@ Examples: In the .Em SYNOPSIS of section 2, 3 and 9 manual pages, use the -.Sx \&Fn +.Ic \&Fn macro rather than -.Sx \&Nm +.Ic \&Nm to mark up the name of the manual page. -.Ss \&No +.It Ic \&No Ar word ... Normal text. Closes the scope of any preceding in-line macro. When used after physical formatting macros like -.Sx \&Em +.Ic \&Em or -.Sx \&Sy , +.Ic \&Sy , switches back to the standard font face and weight. Can also be used to embed plain text strings in macro lines using semantic annotation macros. .Pp Examples: .Dl ".Em italic , Sy bold , No and roman" -.Pp -.Bd -literal -offset indent -compact +.Bd -literal -offset indent \&.Sm off \&.Cm :C No / Ar pattern No / Ar replacement No / \&.Sm on .Ed .Pp See also -.Sx \&Em , -.Sx \&Li , +.Ic \&Em , +.Ic \&Ql , and -.Sx \&Sy . -.Ss \&Ns +.Ic \&Sy . +.It Ic \&Ns Suppress a space between the output of the preceding macro and the following text or macro. Following invocation, input is interpreted as normal text just like after an -.Sx \&No +.Ic \&No macro. .Pp This has no effect when invoked at the start of a macro line. @@ -2156,10 +2050,10 @@ Examples: .Dl ".Fl o Ns Ar output" .Pp See also -.Sx \&No +.Ic \&No and -.Sx \&Sm . -.Ss \&Nx +.Ic \&Sm . +.It Ic \&Nx Op Ar version Format the .Nx version provided as an argument, or a default value if @@ -2170,20 +2064,20 @@ Examples: .Dl \&.Nx .Pp See also -.Sx \&At , -.Sx \&Bsx , -.Sx \&Bx , -.Sx \&Dx , -.Sx \&Fx , +.Ic \&At , +.Ic \&Bsx , +.Ic \&Bx , +.Ic \&Dx , +.Ic \&Fx , and -.Sx \&Ox . -.Ss \&Oc +.Ic \&Ox . +.It Ic \&Oc Close multi-line -.Sx \&Oo +.Ic \&Oo context. -.Ss \&Oo +.It Ic \&Oo Ar block Multi-line version of -.Sx \&Op . +.Ic \&Op . .Pp Examples: .Bd -literal -offset indent -compact @@ -2191,7 +2085,7 @@ Examples: \&.Op Fl flag Ns Ar value \&.Oc .Ed -.Ss \&Op +.It Ic \&Op Ar line Optional part of a command line. Prints the argument(s) in brackets. This is most often used in the @@ -2203,16 +2097,13 @@ Examples: .Dl \&.Op \&Ar a | b .Pp See also -.Sx \&Oo . -.Ss \&Os +.Ic \&Oo . +.It Ic \&Os Op Ar system Op Ar version Operating system version for display in the page footer. This is the mandatory third macro of any .Nm file. -Its syntax is as follows: -.Pp -.D1 Pf \. Sx \&Os Op Ar system Op Ar version .Pp The optional .Ar system @@ -2234,13 +2125,13 @@ Examples: .Dl \&.Os BSD 4.3 .Pp See also -.Sx \&Dd +.Ic \&Dd and -.Sx \&Dt . -.Ss \&Ot +.Ic \&Dt . +.It Ic \&Ot Ar functype This macro is obsolete. Use -.Sx \&Ft +.Ic \&Ft instead; with .Xr mandoc 1 , both have the same effect. @@ -2249,7 +2140,7 @@ Historical .Nm packages described it as .Dq "old function type (FORTRAN)" . -.Ss \&Ox +.It Ic \&Ox Op Ar version Format the .Ox version provided as an argument, or a default value @@ -2260,14 +2151,14 @@ Examples: .Dl \&.Ox .Pp See also -.Sx \&At , -.Sx \&Bsx , -.Sx \&Bx , -.Sx \&Dx , -.Sx \&Fx , +.Ic \&At , +.Ic \&Bsx , +.Ic \&Bx , +.Ic \&Dx , +.Ic \&Fx , and -.Sx \&Nx . -.Ss \&Pa +.Ic \&Nx . +.It Ic \&Pa Ar name ... An absolute or relative file system path, or a file or directory name. If an argument is not provided, the character .Sq \(ti @@ -2278,19 +2169,15 @@ Examples: .Dl \&.Pa /usr/share/man/man5/mdoc.5 .Pp See also -.Sx \&Lk . -.Ss \&Pc +.Ic \&Lk . +.It Ic \&Pc Close parenthesised context opened by -.Sx \&Po . -.Ss \&Pf +.Ic \&Po . +.It Ic \&Pf Ar prefix macro Op Ar argument ... Removes the space between its argument and the following macro. -Its syntax is as follows: -.Pp -.D1 .Pf Ar prefix macro arguments ... -.Pp -This is equivalent to: +It is equivalent to: .Pp -.D1 .No \e& Ns Ar prefix No \&Ns Ar macro arguments ... +.D1 Ic \&No Pf \e& Ar prefix Ic \&Ns Ar macro Op Ar argument ... .Pp The .Ar prefix @@ -2303,93 +2190,87 @@ Examples: .Dl ".Pf 0x Ar hex_digits" .Pp See also -.Sx \&Ns +.Ic \&Ns and -.Sx \&Sm . -.Ss \&Po +.Ic \&Sm . +.It Ic \&Po Ar block Multi-line version of -.Sx \&Pq . -.Ss \&Pp +.Ic \&Pq . +.It Ic \&Pp Break a paragraph. This will assert vertical space between prior and subsequent macros and/or text. .Pp Paragraph breaks are not needed before or after -.Sx \&Sh +.Ic \&Sh or -.Sx \&Ss +.Ic \&Ss macros or before displays -.Pq Sx \&Bd +.Pq Ic \&Bd Ar line or lists -.Pq Sx \&Bl +.Pq Ic \&Bl unless the .Fl compact flag is given. -.Ss \&Pq +.It Ic \&Pq Ar line Parenthesised enclosure. .Pp See also -.Sx \&Po . -.Ss \&Qc +.Ic \&Po . +.It Ic \&Qc Close quoted context opened by -.Sx \&Qo . -.Ss \&Ql +.Ic \&Qo . +.It Ic \&Ql Ar line In-line literal display. -This can for example be used for complete command invocations and -for multi-word code fragments when more specific markup is not -appropriate and an indented display is not desired. -While -.Xr mandoc 1 -always encloses the arguments in single quotes, other formatters -usually omit the quotes on non-terminal output devices when the -arguments have three or more characters. +This can be used for complete command invocations and for multi-word +code examples when an indented display is not desired. .Pp See also -.Sx \&Dl +.Ic \&Dl and -.Sx \&Bd +.Ic \&Bd .Fl literal . -.Ss \&Qo +.It Ic \&Qo Ar block Multi-line version of -.Sx \&Qq . -.Ss \&Qq +.Ic \&Qq . +.It Ic \&Qq Ar line Encloses its arguments in .Qq typewriter double-quotes. Consider using -.Sx \&Dq . +.Ic \&Dq . .Pp See also -.Sx \&Dq , -.Sx \&Sq , +.Ic \&Dq , +.Ic \&Sq , and -.Sx \&Qo . -.Ss \&Re +.Ic \&Qo . +.It Ic \&Re Close an -.Sx \&Rs +.Ic \&Rs block. Does not have any tail arguments. -.Ss \&Rs +.It Ic \&Rs Begin a bibliographic .Pq Dq reference block. Does not have any head arguments. The block macro may only contain -.Sx \&%A , -.Sx \&%B , -.Sx \&%C , -.Sx \&%D , -.Sx \&%I , -.Sx \&%J , -.Sx \&%N , -.Sx \&%O , -.Sx \&%P , -.Sx \&%Q , -.Sx \&%R , -.Sx \&%T , -.Sx \&%U , +.Ic \&%A , +.Ic \&%B , +.Ic \&%C , +.Ic \&%D , +.Ic \&%I , +.Ic \&%J , +.Ic \&%N , +.Ic \&%O , +.Ic \&%P , +.Ic \&%Q , +.Ic \&%R , +.Ic \&%T , +.Ic \&%U , and -.Sx \&%V +.Ic \&%V child macros (at least one must be specified). .Pp Examples: @@ -2405,34 +2286,31 @@ Examples: .Ed .Pp If an -.Sx \&Rs +.Ic \&Rs block is used within a SEE ALSO section, a vertical space is asserted before the rendered output, else the block continues on the current line. -.Ss \&Rv +.It Ic \&Rv Fl std Op Ar function ... Insert a standard sentence regarding a function call's return value of 0 on success and \-1 on error, with the .Va errno libc global variable set on error. -Its syntax is as follows: -.Pp -.D1 Pf \. Sx \&Rv Fl std Op Ar function ... .Pp If .Ar function is not specified, the document's name set by -.Sx \&Nm +.Ic \&Nm is used. Multiple .Ar function arguments are treated as separate functions. .Pp See also -.Sx \&Ex . -.Ss \&Sc +.Ic \&Ex . +.It Ic \&Sc Close single-quoted context opened by -.Sx \&So . -.Ss \&Sh +.Ic \&So . +.It Ic \&Sh Ar TITLE LINE Begin a new section. For a list of conventional manual sections, see .Sx MANUAL STRUCTURE . @@ -2440,21 +2318,18 @@ 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 -.Sx \&Sx . +.Ic \&Sx . Although this macro is parsed, it should not consist of child node or it may not be linked with -.Sx \&Sx . +.Ic \&Sx . .Pp See also -.Sx \&Pp , -.Sx \&Ss , +.Ic \&Pp , +.Ic \&Ss , and -.Sx \&Sx . -.Ss \&Sm +.Ic \&Sx . +.It Ic \&Sm Op Cm on | off Switches the spacing mode for output generated from macros. -Its syntax is as follows: -.Pp -.D1 Pf \. Sx \&Sm Op Cm on | off .Pp By default, spacing is .Cm on . @@ -2465,26 +2340,26 @@ output generated from adjacent macros, but text lines still get normal spacing between words and sentences. .Pp When called without an argument, the -.Sx \&Sm +.Ic \&Sm macro toggles the spacing mode. Using this is not recommended because it makes the code harder to read. -.Ss \&So +.It Ic \&So Ar block Multi-line version of -.Sx \&Sq . -.Ss \&Sq +.Ic \&Sq . +.It Ic \&Sq Ar line Encloses its arguments in .Sq typewriter single-quotes. .Pp See also -.Sx \&Dq , -.Sx \&Qq , +.Ic \&Dq , +.Ic \&Qq , and -.Sx \&So . -.Ss \&Ss +.Ic \&So . +.It Ic \&Ss Ar Title line Begin a new subsection. Unlike with -.Sx \&Sh , +.Ic \&Sh , there is no convention for the naming of subsections. Except .Em DESCRIPTION , @@ -2493,17 +2368,17 @@ the conventional sections described in rarely have subsections. .Pp Sub-section names should be unique so that they may be keyed by -.Sx \&Sx . +.Ic \&Sx . Although this macro is parsed, it should not consist of child node or it may not be linked with -.Sx \&Sx . +.Ic \&Sx . .Pp See also -.Sx \&Pp , -.Sx \&Sh , +.Ic \&Pp , +.Ic \&Sh , and -.Sx \&Sx . -.Ss \&St +.Ic \&Sx . +.It Ic \&St Fl Ns Ar abbreviation Replace an abbreviation for a standard with the full form. The following standards are recognised. Where multiple lines are given without a blank line in between, @@ -2713,7 +2588,7 @@ Ethernet local area networks. .St -ieee1275-94 .El .El -.Ss \&Sx +.It Ic \&Sx Ar Title line Reference a section or subsection in the same manual page. The referenced section or subsection name must be identical to the enclosed argument, including whitespace. @@ -2722,15 +2597,15 @@ Examples: .Dl \&.Sx MANUAL STRUCTURE .Pp See also -.Sx \&Sh +.Ic \&Sh and -.Sx \&Ss . -.Ss \&Sy +.Ic \&Ss . +.It Ic \&Sy Ar word ... Request a boldface font. .Pp This is most often used to indicate importance or seriousness (not to be confused with stress emphasis, see -.Sx \&Em ) . +.Ic \&Em ) . When none of the semantic macros fit, it is also adequate for syntax elements that have to be given or that appear verbatim. .Pp @@ -2746,31 +2621,30 @@ program. .Ed .Pp See also -.Sx \&Bf , -.Sx \&Em , -.Sx \&Li , +.Ic \&Em , +.Ic \&No , and -.Sx \&No . -.Ss \&Ta +.Ic \&Ql . +.It Ic \&Ta Table cell separator in -.Sx \&Bl Fl column +.Ic \&Bl Fl column lists; can only be used below -.Sx \&It . -.Ss \&Tn +.Ic \&It . +.It Ic \&Tn Ar word ... Supported only for compatibility, do not use this in new manuals. Even though the macro name .Pq Dq tradename suggests a semantic function, historic usage is inconsistent, mostly using it as a presentation-level macro to request a small caps font. -.Ss \&Ud +.It Ic \&Ud Supported only for compatibility, do not use this in new manuals. Prints out .Dq currently under development. -.Ss \&Ux +.It Ic \&Ux Supported only for compatibility, do not use this in new manuals. Prints out .Dq Ux . -.Ss \&Va +.It Ic \&Va Oo Ar type Oc Ar identifier ... A variable name. .Pp Examples: @@ -2778,13 +2652,13 @@ Examples: .Dl \&.Va const char *bar ; .Pp For function arguments and parameters, use -.Sx \&Fa +.Ic \&Fa instead. For declarations of global variables in the .Em SYNOPSIS section, use -.Sx \&Vt . -.Ss \&Vt +.Ic \&Vt . +.It Ic \&Vt Ar type Op Ar identifier A variable type. .Pp This is also used for indicating global variables in the @@ -2806,33 +2680,30 @@ Examples: .Dl \&.Vt extern const char * const sys_signame[] \&; .Pp For parameters in function prototypes, use -.Sx \&Fa +.Ic \&Fa instead, for function return types -.Sx \&Ft , +.Ic \&Ft , and for variable names outside the .Em SYNOPSIS section -.Sx \&Va , +.Ic \&Va , even when including a type with the name. See also .Sx MANUAL STRUCTURE . -.Ss \&Xc +.It Ic \&Xc Close a scope opened by -.Sx \&Xo . -.Ss \&Xo +.Ic \&Xo . +.It Ic \&Xo Ar block Extend the header of an -.Sx \&It +.Ic \&It macro or the body of a partial-implicit block macro beyond the end of the input line. This macro originally existed to work around the 9-argument limit of historic .Xr mandoc_roff 5 . -.Ss \&Xr +.It Ic \&Xr Ar name section Link to another manual .Pq Qq cross-reference . -Its syntax is as follows: -.Pp -.D1 Pf \. Sx \&Xr Ar name section .Pp Cross reference the .Ar name @@ -2844,6 +2715,7 @@ Examples: .Dl \&.Xr mandoc 1 .Dl \&.Xr mandoc 1 \&; .Dl \&.Xr mandoc 1 \&Ns s behaviour +.El .Sh MACRO SYNTAX The syntax of a macro depends on its classification. In this section, @@ -2891,10 +2763,10 @@ column, if applicable, describes closure rules. .Ss Block full-explicit Multi-line scope closed by an explicit closing macro. All macros contains bodies; only -.Sx \&Bf +.Ic \s&Bf and .Pq optionally -.Sx \&Bl +.Ic \&Bl contain a head. .Bd -literal -offset indent \&.Yo \(lB\-arg \(lBparm...\(rB\(rB \(lBhead...\(rB @@ -2903,20 +2775,20 @@ contain a head. .Ed .Bl -column "MacroX" "CallableX" "ParsedX" "closed by XXX" -offset indent .It Em Macro Ta Em Callable Ta Em Parsed Ta Em Scope -.It Sx \&Bd Ta \&No Ta \&No Ta closed by Sx \&Ed -.It Sx \&Bf Ta \&No Ta \&No Ta closed by Sx \&Ef -.It Sx \&Bk Ta \&No Ta \&No Ta closed by Sx \&Ek -.It Sx \&Bl Ta \&No Ta \&No Ta closed by Sx \&El -.It Sx \&Ed Ta \&No Ta \&No Ta opened by Sx \&Bd -.It Sx \&Ef Ta \&No Ta \&No Ta opened by Sx \&Bf -.It Sx \&Ek Ta \&No Ta \&No Ta opened by Sx \&Bk -.It Sx \&El Ta \&No Ta \&No Ta opened by Sx \&Bl +.It Ic \&Bd Ta \&No Ta \&No Ta closed by Ic \&Ed +.It Ic \&Bf Ta \&No Ta \&No Ta closed by Ic \&Ef +.It Ic \&Bk Ta \&No Ta \&No Ta closed by Ic \&Ek +.It Ic \&Bl Ta \&No Ta \&No Ta closed by Ic \&El +.It Ic \&Ed Ta \&No Ta \&No Ta opened by Ic \&Bd +.It Ic \&Ef Ta \&No Ta \&No Ta opened by Ic \&Bf +.It Ic \&Ek Ta \&No Ta \&No Ta opened by Ic \&Bk +.It Ic \&El Ta \&No Ta \&No Ta opened by Ic \&Bl .El .Ss Block full-implicit Multi-line scope closed by end-of-file or implicitly by another macro. All macros have bodies; some .Po -.Sx \&It Fl bullet , +.Ic \&It Fl bullet , .Fl hyphen , .Fl dash , .Fl enum , @@ -2924,9 +2796,9 @@ All macros have bodies; some .Pc don't have heads; only one .Po -.Sx \&It +.Ic \&It in -.Sx \&Bl Fl column +.Ic \&Bl Fl column .Pc has multiple heads. .Bd -literal -offset indent @@ -2935,15 +2807,15 @@ has multiple heads. .Ed .Bl -column "MacroX" "CallableX" "ParsedX" "closed by XXXXXXXXXXX" -offset indent .It Em Macro Ta Em Callable Ta Em Parsed Ta Em Scope -.It Sx \&It Ta \&No Ta Yes Ta closed by Sx \&It , Sx \&El -.It Sx \&Nd Ta \&No Ta \&No Ta closed by Sx \&Sh -.It Sx \&Nm Ta \&No Ta Yes Ta closed by Sx \&Nm , Sx \&Sh , Sx \&Ss -.It Sx \&Sh Ta \&No Ta Yes Ta closed by Sx \&Sh -.It Sx \&Ss Ta \&No Ta Yes Ta closed by Sx \&Sh , Sx \&Ss +.It Ic \&It Ta \&No Ta Yes Ta closed by Ic \&It , Ic \&El +.It Ic \&Nd Ta \&No Ta \&No Ta closed by Ic \&Sh +.It Ic \&Nm Ta \&No Ta Yes Ta closed by Ic \&Nm , Ic \&Sh , Ic \&Ss +.It Ic \&Sh Ta \&No Ta Yes Ta closed by Ic \&Sh +.It Ic \&Ss Ta \&No Ta Yes Ta closed by Ic \&Sh , Ic \&Ss .El .Pp Note that the -.Sx \&Nm +.Ic \&Nm macro is a .Sx Block full-implicit macro only when invoked as the first macro @@ -2955,11 +2827,11 @@ section line, else it is Like block full-explicit, but also with single-line scope. Each has at least a body and, in limited circumstances, a head .Po -.Sx \&Fo , -.Sx \&Eo +.Ic \&Fo , +.Ic \&Eo .Pc and/or tail -.Pq Sx \&Ec . +.Pq Ic \&Ec . .Bd -literal -offset indent \&.Yo \(lB\-arg \(lBparm...\(rB\(rB \(lBhead...\(rB \(lBbody...\(rB @@ -2970,30 +2842,30 @@ and/or tail .Ed .Bl -column "MacroX" "CallableX" "ParsedX" "closed by XXXX" -offset indent .It Em Macro Ta Em Callable Ta Em Parsed Ta Em Scope -.It Sx \&Ac Ta Yes Ta Yes Ta opened by Sx \&Ao -.It Sx \&Ao Ta Yes Ta Yes Ta closed by Sx \&Ac -.It Sx \&Bc Ta Yes Ta Yes Ta closed by Sx \&Bo -.It Sx \&Bo Ta Yes Ta Yes Ta opened by Sx \&Bc -.It Sx \&Brc Ta Yes Ta Yes Ta opened by Sx \&Bro -.It Sx \&Bro Ta Yes Ta Yes Ta closed by Sx \&Brc -.It Sx \&Dc Ta Yes Ta Yes Ta opened by Sx \&Do -.It Sx \&Do Ta Yes Ta Yes Ta closed by Sx \&Dc -.It Sx \&Ec Ta Yes Ta Yes Ta opened by Sx \&Eo -.It Sx \&Eo Ta Yes Ta Yes Ta closed by Sx \&Ec -.It Sx \&Fc Ta Yes Ta Yes Ta opened by Sx \&Fo -.It Sx \&Fo Ta \&No Ta \&No Ta closed by Sx \&Fc -.It Sx \&Oc Ta Yes Ta Yes Ta closed by Sx \&Oo -.It Sx \&Oo Ta Yes Ta Yes Ta opened by Sx \&Oc -.It Sx \&Pc Ta Yes Ta Yes Ta closed by Sx \&Po -.It Sx \&Po Ta Yes Ta Yes Ta opened by Sx \&Pc -.It Sx \&Qc Ta Yes Ta Yes Ta opened by Sx \&Oo -.It Sx \&Qo Ta Yes Ta Yes Ta closed by Sx \&Oc -.It Sx \&Re Ta \&No Ta \&No Ta opened by Sx \&Rs -.It Sx \&Rs Ta \&No Ta \&No Ta closed by Sx \&Re -.It Sx \&Sc Ta Yes Ta Yes Ta opened by Sx \&So -.It Sx \&So Ta Yes Ta Yes Ta closed by Sx \&Sc -.It Sx \&Xc Ta Yes Ta Yes Ta opened by Sx \&Xo -.It Sx \&Xo Ta Yes Ta Yes Ta closed by Sx \&Xc +.It Ic \&Ac Ta Yes Ta Yes Ta opened by Ic \&Ao +.It Ic \&Ao Ta Yes Ta Yes Ta closed by Ic \&Ac +.It Ic \&Bc Ta Yes Ta Yes Ta closed by Ic \&Bo +.It Ic \&Bo Ta Yes Ta Yes Ta opened by Ic \&Bc +.It Ic \&Brc Ta Yes Ta Yes Ta opened by Ic \&Bro +.It Ic \&Bro Ta Yes Ta Yes Ta closed by Ic \&Brc +.It Ic \&Dc Ta Yes Ta Yes Ta opened by Ic \&Do +.It Ic \&Do Ta Yes Ta Yes Ta closed by Ic \&Dc +.It Ic \&Ec Ta Yes Ta Yes Ta opened by Ic \&Eo +.It Ic \&Eo Ta Yes Ta Yes Ta closed by Ic \&Ec +.It Ic \&Fc Ta Yes Ta Yes Ta opened by Ic \&Fo +.It Ic \&Fo Ta \&No Ta \&No Ta closed by Ic \&Fc +.It Ic \&Oc Ta Yes Ta Yes Ta closed by Ic \&Oo +.It Ic \&Oo Ta Yes Ta Yes Ta opened by Ic \&Oc +.It Ic \&Pc Ta Yes Ta Yes Ta closed by Ic \&Po +.It Ic \&Po Ta Yes Ta Yes Ta opened by Ic \&Pc +.It Ic \&Qc Ta Yes Ta Yes Ta opened by Ic \&Oo +.It Ic \&Qo Ta Yes Ta Yes Ta closed by Ic \&Oc +.It Ic \&Re Ta \&No Ta \&No Ta opened by Ic \&Rs +.It Ic \&Rs Ta \&No Ta \&No Ta closed by Ic \&Re +.It Ic \&Sc Ta Yes Ta Yes Ta opened by Ic \&So +.It Ic \&So Ta Yes Ta Yes Ta closed by Ic \&Sc +.It Ic \&Xc Ta Yes Ta Yes Ta opened by Ic \&Xo +.It Ic \&Xo Ta Yes Ta Yes Ta closed by Ic \&Xc .El .Ss Block partial-implicit Like block full-implicit, but with single-line scope closed by the @@ -3003,23 +2875,23 @@ end of the line. .Ed .Bl -column "MacroX" "CallableX" "ParsedX" -offset indent .It Em Macro Ta Em Callable Ta Em Parsed -.It Sx \&Aq Ta Yes Ta Yes -.It Sx \&Bq Ta Yes Ta Yes -.It Sx \&Brq Ta Yes Ta Yes -.It Sx \&D1 Ta \&No Ta \&Yes -.It Sx \&Dl Ta \&No Ta Yes -.It Sx \&Dq Ta Yes Ta Yes -.It Sx \&En Ta Yes Ta Yes -.It Sx \&Op Ta Yes Ta Yes -.It Sx \&Pq Ta Yes Ta Yes -.It Sx \&Ql Ta Yes Ta Yes -.It Sx \&Qq Ta Yes Ta Yes -.It Sx \&Sq Ta Yes Ta Yes -.It Sx \&Vt Ta Yes Ta Yes +.It Ic \&Aq Ta Yes Ta Yes +.It Ic \&Bq Ta Yes Ta Yes +.It Ic \&Brq Ta Yes Ta Yes +.It Ic \&D1 Ta \&No Ta \&Yes +.It Ic \&Dl Ta \&No Ta Yes +.It Ic \&Dq Ta Yes Ta Yes +.It Ic \&En Ta Yes Ta Yes +.It Ic \&Op Ta Yes Ta Yes +.It Ic \&Pq Ta Yes Ta Yes +.It Ic \&Ql Ta Yes Ta Yes +.It Ic \&Qq Ta Yes Ta Yes +.It Ic \&Sq Ta Yes Ta Yes +.It Ic \&Vt Ta Yes Ta Yes .El .Pp Note that the -.Sx \&Vt +.Ic \&Vt macro is a .Sx Block partial-implicit only when invoked as the first macro @@ -3029,17 +2901,17 @@ section line, else it is .Sx In-line . .Ss Special block macro The -.Sx \&Ta +.Ic \&Ta macro can only be used below -.Sx \&It +.Ic \&It in -.Sx \&Bl Fl column +.Ic \&Bl Fl column lists. It delimits blocks representing table cells; these blocks have bodies, but no heads. .Bl -column "MacroX" "CallableX" "ParsedX" "closed by XXXX" -offset indent .It Em Macro Ta Em Callable Ta Em Parsed Ta Em Scope -.It Sx \&Ta Ta Yes Ta Yes Ta closed by Sx \&Ta , Sx \&It +.It Ic \&Ta Ta Yes Ta Yes Ta closed by Ic \&Ta , Ic \&It .El .Ss In-line Closed by the end of the line, fixed argument lengths, @@ -3057,77 +2929,77 @@ then the macro accepts an arbitrary number of arguments. .Ed .Bl -column "MacroX" "CallableX" "ParsedX" "Arguments" -offset indent .It Em Macro Ta Em Callable Ta Em Parsed Ta Em Arguments -.It Sx \&%A Ta \&No Ta \&No Ta >0 -.It Sx \&%B Ta \&No Ta \&No Ta >0 -.It Sx \&%C Ta \&No Ta \&No Ta >0 -.It Sx \&%D Ta \&No Ta \&No Ta >0 -.It Sx \&%I Ta \&No Ta \&No Ta >0 -.It Sx \&%J Ta \&No Ta \&No Ta >0 -.It Sx \&%N Ta \&No Ta \&No Ta >0 -.It Sx \&%O Ta \&No Ta \&No Ta >0 -.It Sx \&%P Ta \&No Ta \&No Ta >0 -.It Sx \&%Q Ta \&No Ta \&No Ta >0 -.It Sx \&%R Ta \&No Ta \&No Ta >0 -.It Sx \&%T Ta \&No Ta \&No Ta >0 -.It Sx \&%U Ta \&No Ta \&No Ta >0 -.It Sx \&%V Ta \&No Ta \&No Ta >0 -.It Sx \&Ad Ta Yes Ta Yes Ta >0 -.It Sx \&An Ta Yes Ta Yes Ta >0 -.It Sx \&Ap Ta Yes Ta Yes Ta 0 -.It Sx \&Ar Ta Yes Ta Yes Ta n -.It Sx \&At Ta Yes Ta Yes Ta 1 -.It Sx \&Bsx Ta Yes Ta Yes Ta n -.It Sx \&Bt Ta \&No Ta \&No Ta 0 -.It Sx \&Bx Ta Yes Ta Yes Ta n -.It Sx \&Cd Ta Yes Ta Yes Ta >0 -.It Sx \&Cm Ta Yes Ta Yes Ta >0 -.It Sx \&Db Ta \&No Ta \&No Ta 1 -.It Sx \&Dd Ta \&No Ta \&No Ta n -.It Sx \&Dt Ta \&No Ta \&No Ta n -.It Sx \&Dv Ta Yes Ta Yes Ta >0 -.It Sx \&Dx Ta Yes Ta Yes Ta n -.It Sx \&Em Ta Yes Ta Yes Ta >0 -.It Sx \&Er Ta Yes Ta Yes Ta >0 -.It Sx \&Es Ta Yes Ta Yes Ta 2 -.It Sx \&Ev Ta Yes Ta Yes Ta >0 -.It Sx \&Ex Ta \&No Ta \&No Ta n -.It Sx \&Fa Ta Yes Ta Yes Ta >0 -.It Sx \&Fd Ta \&No Ta \&No Ta >0 -.It Sx \&Fl Ta Yes Ta Yes Ta n -.It Sx \&Fn Ta Yes Ta Yes Ta >0 -.It Sx \&Fr Ta Yes Ta Yes Ta >0 -.It Sx \&Ft Ta Yes Ta Yes Ta >0 -.It Sx \&Fx Ta Yes Ta Yes Ta n -.It Sx \&Hf Ta \&No Ta \&No Ta n -.It Sx \&Ic Ta Yes Ta Yes Ta >0 -.It Sx \&In Ta \&No Ta \&No Ta 1 -.It Sx \&Lb Ta \&No Ta \&No Ta 1 -.It Sx \&Li Ta Yes Ta Yes Ta >0 -.It Sx \&Lk Ta Yes Ta Yes Ta >0 -.It Sx \&Lp Ta \&No Ta \&No Ta 0 -.It Sx \&Ms Ta Yes Ta Yes Ta >0 -.It Sx \&Mt Ta Yes Ta Yes Ta >0 -.It Sx \&Nm Ta Yes Ta Yes Ta n -.It Sx \&No Ta Yes Ta Yes Ta 0 -.It Sx \&Ns Ta Yes Ta Yes Ta 0 -.It Sx \&Nx Ta Yes Ta Yes Ta n -.It Sx \&Os Ta \&No Ta \&No Ta n -.It Sx \&Ot Ta Yes Ta Yes Ta >0 -.It Sx \&Ox Ta Yes Ta Yes Ta n -.It Sx \&Pa Ta Yes Ta Yes Ta n -.It Sx \&Pf Ta Yes Ta Yes Ta 1 -.It Sx \&Pp Ta \&No Ta \&No Ta 0 -.It Sx \&Rv Ta \&No Ta \&No Ta n -.It Sx \&Sm Ta \&No Ta \&No Ta <2 -.It Sx \&St Ta \&No Ta Yes Ta 1 -.It Sx \&Sx Ta Yes Ta Yes Ta >0 -.It Sx \&Sy Ta Yes Ta Yes Ta >0 -.It Sx \&Tn Ta Yes Ta Yes Ta >0 -.It Sx \&Ud Ta \&No Ta \&No Ta 0 -.It Sx \&Ux Ta Yes Ta Yes Ta n -.It Sx \&Va Ta Yes Ta Yes Ta n -.It Sx \&Vt Ta Yes Ta Yes Ta >0 -.It Sx \&Xr Ta Yes Ta Yes Ta 2 +.It Ic \&%A Ta \&No Ta \&No Ta >0 +.It Ic \&%B Ta \&No Ta \&No Ta >0 +.It Ic \&%C Ta \&No Ta \&No Ta >0 +.It Ic \&%D Ta \&No Ta \&No Ta >0 +.It Ic \&%I Ta \&No Ta \&No Ta >0 +.It Ic \&%J Ta \&No Ta \&No Ta >0 +.It Ic \&%N Ta \&No Ta \&No Ta >0 +.It Ic \&%O Ta \&No Ta \&No Ta >0 +.It Ic \&%P Ta \&No Ta \&No Ta >0 +.It Ic \&%Q Ta \&No Ta \&No Ta >0 +.It Ic \&%R Ta \&No Ta \&No Ta >0 +.It Ic \&%T Ta \&No Ta \&No Ta >0 +.It Ic \&%U Ta \&No Ta \&No Ta >0 +.It Ic \&%V Ta \&No Ta \&No Ta >0 +.It Ic \&Ad Ta Yes Ta Yes Ta >0 +.It Ic \&An Ta Yes Ta Yes Ta >0 +.It Ic \&Ap Ta Yes Ta Yes Ta 0 +.It Ic \&Ar Ta Yes Ta Yes Ta n +.It Ic \&At Ta Yes Ta Yes Ta 1 +.It Ic \&Bsx Ta Yes Ta Yes Ta n +.It Ic \&Bt Ta \&No Ta \&No Ta 0 +.It Ic \&Bx Ta Yes Ta Yes Ta n +.It Ic \&Cd Ta Yes Ta Yes Ta >0 +.It Ic \&Cm Ta Yes Ta Yes Ta >0 +.It Ic \&Db Ta \&No Ta \&No Ta 1 +.It Ic \&Dd Ta \&No Ta \&No Ta n +.It Ic \&Dt Ta \&No Ta \&No Ta n +.It Ic \&Dv Ta Yes Ta Yes Ta >0 +.It Ic \&Dx Ta Yes Ta Yes Ta n +.It Ic \&Em Ta Yes Ta Yes Ta >0 +.It Ic \&Er Ta Yes Ta Yes Ta >0 +.It Ic \&Es Ta Yes Ta Yes Ta 2 +.It Ic \&Ev Ta Yes Ta Yes Ta >0 +.It Ic \&Ex Ta \&No Ta \&No Ta n +.It Ic \&Fa Ta Yes Ta Yes Ta >0 +.It Ic \&Fd Ta \&No Ta \&No Ta >0 +.It Ic \&Fl Ta Yes Ta Yes Ta n +.It Ic \&Fn Ta Yes Ta Yes Ta >0 +.It Ic \&Fr Ta Yes Ta Yes Ta >0 +.It Ic \&Ft Ta Yes Ta Yes Ta >0 +.It Ic \&Fx Ta Yes Ta Yes Ta n +.It Ic \&Hf Ta \&No Ta \&No Ta n +.It Ic \&Ic Ta Yes Ta Yes Ta >0 +.It Ic \&In Ta \&No Ta \&No Ta 1 +.It Ic \&Lb Ta \&No Ta \&No Ta 1 +.It Ic \&Li Ta Yes Ta Yes Ta >0 +.It Ic \&Lk Ta Yes Ta Yes Ta >0 +.It Ic \&Lp Ta \&No Ta \&No Ta 0 +.It Ic \&Ms Ta Yes Ta Yes Ta >0 +.It Ic \&Mt Ta Yes Ta Yes Ta >0 +.It Ic \&Nm Ta Yes Ta Yes Ta n +.It Ic \&No Ta Yes Ta Yes Ta >0 +.It Ic \&Ns Ta Yes Ta Yes Ta 0 +.It Ic \&Nx Ta Yes Ta Yes Ta n +.It Ic \&Os Ta \&No Ta \&No Ta n +.It Ic \&Ot Ta Yes Ta Yes Ta >0 +.It Ic \&Ox Ta Yes Ta Yes Ta n +.It Ic \&Pa Ta Yes Ta Yes Ta n +.It Ic \&Pf Ta Yes Ta Yes Ta 1 +.It Ic \&Pp Ta \&No Ta \&No Ta 0 +.It Ic \&Rv Ta \&No Ta \&No Ta n +.It Ic \&Sm Ta \&No Ta \&No Ta <2 +.It Ic \&St Ta \&No Ta Yes Ta 1 +.It Ic \&Sx Ta Yes Ta Yes Ta >0 +.It Ic \&Sy Ta Yes Ta Yes Ta >0 +.It Ic \&Tn Ta Yes Ta Yes Ta >0 +.It Ic \&Ud Ta \&No Ta \&No Ta 0 +.It Ic \&Ux Ta Yes Ta Yes Ta n +.It Ic \&Va Ta Yes Ta Yes Ta n +.It Ic \&Vt Ta Yes Ta Yes Ta >0 +.It Ic \&Xr Ta Yes Ta Yes Ta 2 .El .Ss Delimiters When a macro argument consists of one single input character @@ -3242,7 +3114,7 @@ The following problematic behaviour is found in groff: .Pp .Bl -dash -compact .It -.Sx \&Dd +.Ic \&Dd with non-standard arguments behaves very strangely. When there are three arguments, they are printed verbatim. Any other number of arguments is replaced by the current date, @@ -3250,17 +3122,17 @@ but without any arguments the string .Dq Epoch is printed. .It -.Sx \&Lk +.Ic \&Lk only accepts a single link-name argument; the remainder is misformatted. .It -.Sx \&Pa +.Ic \&Pa does not format its arguments when used in the FILES section under certain list types. .It -.Sx \&Ta +.Ic \&Ta can only be called by other macros, but not at the beginning of a line. .It -.Sx \&%C +.Ic \&%C is not implemented (up to and including groff-1.22.2). .It .Sq \ef @@ -3279,23 +3151,22 @@ The following features are unimplemented in mandoc: .Pp .Bl -dash -compact .It -.Sx \&Bd -.Fl file Ar file +.Ic \&Bd Fl file Ar file is unsupported for security reasons. .It -.Sx \&Bd +.Ic \&Bd .Fl filled does not adjust the right margin, but is an alias for -.Sx \&Bd +.Ic \&Bd .Fl ragged . .It -.Sx \&Bd +.Ic \&Bd .Fl literal does not use a literal font, but is an alias for -.Sx \&Bd +.Ic \&Bd .Fl unfilled . .It -.Sx \&Bd +.Ic \&Bd .Fl offset Cm center and .Fl offset Cm right diff --git a/usr/src/man/man5/tbl.5 b/usr/src/man/man5/tbl.5 index 6105a6898b..21cb9ddcdd 100644 --- a/usr/src/man/man5/tbl.5 +++ b/usr/src/man/man5/tbl.5 @@ -1,7 +1,7 @@ -.\" $Id: tbl.7,v 1.29 2017/10/17 23:19:12 schwarze Exp $ +.\" $Id: tbl.7,v 1.34 2019/03/02 21:03:02 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,2019 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: October 17 2017 $ +.Dd $Mdocdate: March 2 2019 $ .Dt TBL 5 .Os .Sh NAME @@ -147,9 +147,9 @@ The combined cell as a whole consumes only one cell of the corresponding data line. .It Cm a Left-justify a string and pad with one space. -.It Cm ^ +.It Cm \(ha Vertically span rows from the last -.Pf non- Cm ^ +.Pf non- Cm \(ha layout cell. It is an error to invoke a vertical span on the first layout line. Unlike a horizontal span, a vertical span consumes a data cell @@ -231,13 +231,19 @@ Each data line consists of one or more data cells, delimited by .Cm tab characters. .Pp -If a data cells contains only the single character +If a data cell contains only the two bytes +.Ql \e\(ha , +the cell above spans to this row, as if the layout specification +of this cell were +.Cm \(ha . +.Pp +If a data cell contains only the single character .Ql _ or .Ql = , a single or double horizontal line is drawn across the cell, joining its neighbours. -If a data cells contains only the two character sequence +If a data cell contains only the two character sequence .Ql \e_ or .Ql \e= , @@ -323,7 +329,7 @@ _ AFL:2.39b Mutt:1.8.0 Ruby:1.8.7.374 -TeX Live:2015 +TeX Live:2015 .TE .Ed .sp 2v @@ -332,8 +338,8 @@ Spans and skipping width calculations: \&.TS box tab(:); lz s | rt -lt| cb| ^ -^ | rz s. +lt| cb| \(ha +\(ha | rz s. left:r l:center: :right @@ -388,8 +394,8 @@ T}::line 5 These examples were constructed to demonstrate many .Nm features in a compact way. -In real manual pages, keep tables as simple as possible: -Like that, they usually look better, are less fragile, and more portable. +In real manual pages, keep tables as simple as possible. +They usually look better, are less fragile, and are more portable. .Sh COMPATIBILITY The .Xr mandoc 1 @@ -432,3 +438,17 @@ reference was written by .An Kristaps Dzonsons Aq Mt kristaps@bsd.lv and .An Ingo Schwarze Aq Mt schwarze@openbsd.org . +.Sh BUGS +In +.Fl T +.Cm utf8 +output mode, heavy lines are drawn instead of double lines. +This cannot be improved because the Unicode standard only provides +an incomplete set of box drawing characters with double lines, +whereas it provides a full set of box drawing characters +with heavy lines. +It is unlikely this can be improved in the future because the box +drawing characters are already marked in Unicode as characters +intended only for backward compatibility with legacy systems, +and their use is not encouraged. +So it seems unlikely that the missing ones might get added in the future. diff --git a/usr/src/man/man7d/Makefile b/usr/src/man/man7d/Makefile index e9bb9ae157..2c6a5cb5a9 100644 --- a/usr/src/man/man7d/Makefile +++ b/usr/src/man/man7d/Makefile @@ -186,6 +186,7 @@ sparc_MANFILES= audiocs.7d \ i386_MANFILES= ahci.7d \ amd8111s.7d \ + amdf17nbdf.7d \ amr.7d \ arcmsr.7d \ arn.7d \ @@ -205,6 +206,7 @@ i386_MANFILES= ahci.7d \ bcm_sata.7d \ bfe.7d \ cmdk.7d \ + coretemp.7d \ cpqary3.7d \ dnet.7d \ ecpp.7d \ diff --git a/usr/src/man/man9f/scsi_hba_tgtmap_create.9f b/usr/src/man/man9f/scsi_hba_tgtmap_create.9f index 9a4640a3e5..3ff2c46d31 100644 --- a/usr/src/man/man9f/scsi_hba_tgtmap_create.9f +++ b/usr/src/man/man9f/scsi_hba_tgtmap_create.9f @@ -11,7 +11,7 @@ .\" .\" Copyright 2019, Joyent, Inc. .\" -.Dd April 22, 2019 +.Dd June 03, 2019 .Dt SCSI_HBA_TGTMAP_CREATE 9F .Os .Sh NAME @@ -35,7 +35,7 @@ .Fa "void *tgtmap_priv" .Fa "scsi_tgt_activate_cb_t activate_cb" .Fa "scsi_tgt_deactivate_cb_t deactivate_cb" -.Fa "scsi_hba_tgtmap_t *tgtmapout" +.Fa "scsi_hba_tgtmap_t **tgtmapout" .Fc .Ft void .Fo scsi_hba_tgtmap_destroy @@ -121,7 +121,7 @@ added to the system. An optional callback that will be called when an existing devices is removed from the system. .It Fa tgtmapout -Pointer where the target map is stored. +Pointer where the target map handle is stored. .It Fa tgtmap Pointer to an allocated target map. .It Fa flags diff --git a/usr/src/man/man9f/usb_parse_data.9f b/usr/src/man/man9f/usb_parse_data.9f index 057caca64d..f3ac26e710 100644 --- a/usr/src/man/man9f/usb_parse_data.9f +++ b/usr/src/man/man9f/usb_parse_data.9f @@ -7,7 +7,6 @@ .SH NAME usb_parse_data \- Tokenize and align the bytes of raw variable-format data .SH SYNOPSIS -.LP .nf #include <sys/usb/usba.h> @@ -18,7 +17,6 @@ usb_parse_data \- Tokenize and align the bytes of raw variable-format data .fi .SH INTERFACE LEVEL -.LP Solaris DDI specific (Solaris DDI) .SH PARAMETERS .ne 2 @@ -71,7 +69,6 @@ exceed this value. .RE .SH DESCRIPTION -.LP The \fBusb_parse_data\fR function parses data such as a variable-format class- or vendor-specific descriptor. The function also tokenizes and aligns the bytes of raw descriptor data into fields of a variable-format descriptor. @@ -91,13 +88,11 @@ While the USB specification defines bit ordering as little-endian, this routine The \fIstructlen\fR parameter defines the size of the destination data buffer. Data is truncated to this size if the destination data buffer is too small. .SH RETURN VALUES -.LP On success: Returns the size (in bytes) of the parsed data result. .sp .LP On failure: Returns 0. (Same as USB_PARSE_ERROR). .SH CONTEXT -.LP May be called from user, kernel or interrupt context. .SH EXAMPLES .in +2 @@ -130,7 +125,6 @@ May be called from user, kernel or interrupt context. .in -2 .SH ATTRIBUTES -.LP See \fBattributes\fR(5) for descriptions of the following attributes: .sp @@ -147,6 +141,5 @@ Interface stability Committed .TE .SH SEE ALSO -.LP \fBattributes\fR(5), \fBusb_get_dev_data\fR(9F), \fBusb_get_string_descr\fR(9F), \fBusb_get_cfg\fR(9F) diff --git a/usr/src/pkg/manifests/driver-cpu-sensor.mf b/usr/src/pkg/manifests/driver-cpu-sensor.mf new file mode 100644 index 0000000000..206456e092 --- /dev/null +++ b/usr/src/pkg/manifests/driver-cpu-sensor.mf @@ -0,0 +1,43 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2019 Joyent, Inc. +# + +<include global_zone_only_component> +set name=pkg.fmri value=pkg:/driver/cpu/sensor@$(PKGVERS) +set name=pkg.description value="CPU Sensor Drivers" +set name=pkg.summary value="CPU Sensor Drivers" +set name=info.classification \ + value=org.opensolaris.category.2008:System/Hardware +set name=variant.arch value=i386 +dir path=kernel group=sys +dir path=kernel/drv group=sys +dir path=kernel/drv/$(ARCH64) group=sys +dir path=usr/include +dir path=usr/include/sys +dir path=usr/lib/devfsadm group=sys +dir path=usr/lib/devfsadm/linkmod group=sys +dir path=usr/share/man +dir path=usr/share/man/man7d +driver name=amdf17nbdf \ + alias=pci1022,1450 \ + alias=pci1022,1460 +driver name=coretemp +file path=kernel/drv/$(ARCH64)/amdf17nbdf group=sys +file path=kernel/drv/$(ARCH64)/coretemp group=sys +file path=kernel/drv/coretemp.conf group=sys +file path=usr/include/sys/sensors.h mode=0644 +file path=usr/lib/devfsadm/linkmod/SUNW_sensor_link.so group=sys +file path=usr/share/man/man7d/amdf17nbdf.7d +file path=usr/share/man/man7d/coretemp.7d +license lic_CDDL license=lic_CDDL diff --git a/usr/src/pkg/manifests/system-test-zfstest.mf b/usr/src/pkg/manifests/system-test-zfstest.mf index a29f2c6bc8..bf1e75980b 100644 --- a/usr/src/pkg/manifests/system-test-zfstest.mf +++ b/usr/src/pkg/manifests/system-test-zfstest.mf @@ -2521,6 +2521,9 @@ file path=opt/zfs-tests/tests/functional/refreserv/refreserv_002_pos mode=0555 file path=opt/zfs-tests/tests/functional/refreserv/refreserv_003_pos mode=0555 file path=opt/zfs-tests/tests/functional/refreserv/refreserv_004_pos mode=0555 file path=opt/zfs-tests/tests/functional/refreserv/refreserv_005_pos mode=0555 +file path=opt/zfs-tests/tests/functional/refreserv/refreserv_multi_raidz \ + mode=0555 +file path=opt/zfs-tests/tests/functional/refreserv/refreserv_raidz mode=0555 file path=opt/zfs-tests/tests/functional/refreserv/setup mode=0555 file path=opt/zfs-tests/tests/functional/removal/cleanup mode=0555 file path=opt/zfs-tests/tests/functional/removal/removal.kshlib mode=0444 diff --git a/usr/src/test/zfs-tests/runfiles/delphix.run b/usr/src/test/zfs-tests/runfiles/delphix.run index dbee1a5433..738fe89309 100644 --- a/usr/src/test/zfs-tests/runfiles/delphix.run +++ b/usr/src/test/zfs-tests/runfiles/delphix.run @@ -536,7 +536,8 @@ tests = ['refquota_001_pos', 'refquota_002_pos', 'refquota_003_pos', [/opt/zfs-tests/tests/functional/refreserv] tests = ['refreserv_001_pos', 'refreserv_002_pos', 'refreserv_003_pos', - 'refreserv_004_pos', 'refreserv_005_pos'] + 'refreserv_004_pos', 'refreserv_005_pos', 'refreserv_raidz', + 'refreserv_multi_raidz'] [/opt/zfs-tests/tests/functional/removal] pre = diff --git a/usr/src/test/zfs-tests/runfiles/omnios.run b/usr/src/test/zfs-tests/runfiles/omnios.run index 875b529e9e..926f65cb20 100644 --- a/usr/src/test/zfs-tests/runfiles/omnios.run +++ b/usr/src/test/zfs-tests/runfiles/omnios.run @@ -536,7 +536,8 @@ tests = ['refquota_001_pos', 'refquota_002_pos', 'refquota_003_pos', [/opt/zfs-tests/tests/functional/refreserv] tests = ['refreserv_001_pos', 'refreserv_002_pos', 'refreserv_003_pos', - 'refreserv_004_pos', 'refreserv_005_pos'] + 'refreserv_004_pos', 'refreserv_005_pos', 'refreserv_raidz', + 'refreserv_multi_raidz'] [/opt/zfs-tests/tests/functional/removal] pre = diff --git a/usr/src/test/zfs-tests/runfiles/openindiana.run b/usr/src/test/zfs-tests/runfiles/openindiana.run index f8c0c40328..f86d6d9a7b 100644 --- a/usr/src/test/zfs-tests/runfiles/openindiana.run +++ b/usr/src/test/zfs-tests/runfiles/openindiana.run @@ -536,7 +536,8 @@ tests = ['refquota_001_pos', 'refquota_002_pos', 'refquota_003_pos', [/opt/zfs-tests/tests/functional/refreserv] tests = ['refreserv_001_pos', 'refreserv_002_pos', 'refreserv_003_pos', - 'refreserv_004_pos', 'refreserv_005_pos'] + 'refreserv_004_pos', 'refreserv_005_pos', 'refreserv_raidz', + 'refreserv_multi_raidz'] [/opt/zfs-tests/tests/functional/removal] pre = diff --git a/usr/src/test/zfs-tests/tests/functional/cache/cache.cfg b/usr/src/test/zfs-tests/tests/functional/cache/cache.cfg index b284bd4b23..0a248c8048 100644 --- a/usr/src/test/zfs-tests/tests/functional/cache/cache.cfg +++ b/usr/src/test/zfs-tests/tests/functional/cache/cache.cfg @@ -26,6 +26,7 @@ # # Copyright (c) 2013, 2015 by Delphix. All rights reserved. +# Copyright 2019 Joyent, Inc. # . $STF_SUITE/include/libtest.shlib @@ -68,3 +69,4 @@ export VDEV="$VDIR/a $VDIR/b $VDIR/c" export LDEV="$DISK0" export VDEV2="$VDIR2/a $VDIR2/b $VDIR2/c" export LDEV2="$DISK1" +export FILEDEV="$VDIR2/d" diff --git a/usr/src/test/zfs-tests/tests/functional/cache/cache_010_neg.ksh b/usr/src/test/zfs-tests/tests/functional/cache/cache_010_neg.ksh index f3dcf6873c..43294220dd 100644 --- a/usr/src/test/zfs-tests/tests/functional/cache/cache_010_neg.ksh +++ b/usr/src/test/zfs-tests/tests/functional/cache/cache_010_neg.ksh @@ -27,6 +27,7 @@ # # Copyright (c) 2013, 2016 by Delphix. All rights reserved. +# Copyright 2019 Joyent, Inc. # . $STF_SUITE/tests/functional/cache/cache.cfg @@ -34,12 +35,12 @@ # # DESCRIPTION: -# Verify cache device must be a block device. +# Verify cache device must be a block device or plain file. # # STRATEGY: # 1. Create a pool -# 2. Add different object as cache -# 3. Verify character devices and files fail +# 2. Verify that raw disks, loopback files, and zvols can't be used to +# back cache vdevs # verify_runnable "global" @@ -52,20 +53,18 @@ function cleanup_testenv fi } -log_assert "Cache device can only be block devices." +log_assert "Cache device can only be block devices or plain files." log_onexit cleanup_testenv TESTVOL=testvol1$$ dsk1=${DISKS%% *} + log_must zpool create $TESTPOOL ${DISKS#$dsk1} -# Add nomal /dev/rdsk device +# Add normal /dev/rdsk device log_mustnot zpool add $TESTPOOL cache /dev/rdsk/${dsk1}s0 #log_must verify_cache_device $TESTPOOL $dsk1 'ONLINE' -# Add nomal file -log_mustnot zpool add $TESTPOOL cache $VDEV2 - # Add /dev/rlofi device lofidev=${VDEV2%% *} log_must lofiadm -a $lofidev @@ -76,9 +75,12 @@ if [[ -n $lofidev ]]; then lofidev="" fi +# Add normal files +log_must zpool add $TESTPOOL cache $FILEDEV + # Add /dev/zvol/rdsk device log_must zpool create $TESTPOOL2 $VDEV2 log_must zfs create -V $SIZE $TESTPOOL2/$TESTVOL log_mustnot zpool add $TESTPOOL cache /dev/zvol/rdsk/$TESTPOOL2/$TESTVOL -log_pass "Cache device can only be block devices." +log_pass "Cache device can only be block devices or plain files." diff --git a/usr/src/test/zfs-tests/tests/functional/cache/setup.ksh b/usr/src/test/zfs-tests/tests/functional/cache/setup.ksh index aa8d6cd06e..0826a887aa 100644 --- a/usr/src/test/zfs-tests/tests/functional/cache/setup.ksh +++ b/usr/src/test/zfs-tests/tests/functional/cache/setup.ksh @@ -27,6 +27,7 @@ # # Copyright (c) 2013, 2016 by Delphix. All rights reserved. +# Copyright 2019 Joyent, Inc. # . $STF_SUITE/tests/functional/cache/cache.cfg @@ -40,6 +41,6 @@ fi log_must rm -rf $VDIR $VDIR2 log_must mkdir -p $VDIR $VDIR2 -log_must mkfile $SIZE $VDEV $VDEV2 +log_must mkfile $SIZE $VDEV $VDEV2 $FILEDEV log_pass diff --git a/usr/src/test/zfs-tests/tests/functional/refreserv/refreserv_multi_raidz.ksh b/usr/src/test/zfs-tests/tests/functional/refreserv/refreserv_multi_raidz.ksh new file mode 100644 index 0000000000..ec5e0bfc27 --- /dev/null +++ b/usr/src/test/zfs-tests/tests/functional/refreserv/refreserv_multi_raidz.ksh @@ -0,0 +1,197 @@ +#!/bin/ksh -p +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2019 Joyent, Inc. +# + +. $STF_SUITE/include/libtest.shlib +. $STF_SUITE/tests/functional/refreserv/refreserv.cfg + +# +# DESCRIPTION: +# raidz refreservation=auto picks worst raidz vdev +# +# STRATEGY: +# 1. Create a pool with a single raidz vdev +# 2. For each block size [512b, 1k, 128k] or [4k, 8k, 128k] +# - create a volume +# - remember its refreservation +# - destroy the volume +# 3. Destroy the pool +# 4. Recreate the pool with one more disk in the vdev, then repeat steps +# 2 and 3. +# +# NOTES: +# 1. This test will use up to 14 disks but can cover the key concepts with +# 5 disks. +# 2. If the disks are a mixture of 4Kn and 512n/512e, failures are likely. +# + +verify_runnable "global" + +typeset -a alldisks=($DISKS) + +# The larger the volsize, the better zvol_volsize_to_reservation() is at +# guessing the right number - though it is horrible with tiny blocks. At 10M on +# ashift=12, the estimate may be over 26% too high. +volsize=100 + +function cleanup +{ + default_cleanup_noexit + default_setup_noexit "${alldisks[0]}" +} + +log_assert "raidz refreservation=auto picks worst raidz vdev" +log_onexit cleanup + +poolexists "$TESTPOOL" && log_must zpool destroy "$TESTPOOL" + +# Testing tiny block sizes on ashift=12 pools causes so much size inflation +# that small test disks may fill before creating small volumes. However, +# testing 512b and 1K blocks on ashift=9 pools is an ok approximation for +# testing the problems that arise from 4K and 8K blocks on ashift=12 pools. +bps=$(prtvtoc /dev/rdsk/${alldisks[0]} | + awk '$NF == "bytes/sector" { print $2; exit 0 }') +case "$bps" in +512) + allshifts=(9 10 17) + ;; +4096) + allshifts=(12 13 17) + ;; +*) + log_fail "bytes/sector != (512|4096)" + ;; +esac +log_note "Testing in ashift=${allshifts[0]} mode" + +typeset -A sizes= + +# +# Determine the refreservation for a $volsize MiB volume on each raidz type at +# various block sizes. +# +for parity in 1 2 3; do + raid=raidz$parity + typeset -A sizes["$raid"] + + # Ensure we hit scenarios with and without skip blocks + for ndisks in $((parity * 2)) $((parity * 2 + 1)); do + typeset -a disks=(${alldisks[0..$((ndisks - 1))]}) + + if (( ${#disks[@]} < ndisks )); then + log_note "Too few disks to test $raid-$ndisks" + continue + fi + + typeset -A sizes["$raid"]["$ndisks"] + + log_must zpool create "$TESTPOOL" "$raid" "${disks[@]}" + + for bits in "${allshifts[@]}"; do + vbs=$((1 << bits)) + log_note "Gathering refreservation for $raid-$ndisks" \ + "volblocksize=$vbs" + + vol=$TESTPOOL/$TESTVOL + log_must zfs create -V ${volsize}m \ + -o volblocksize=$vbs "$vol" + + refres=$(zfs get -Hpo value refreservation "$vol") + log_must test -n "$refres" + sizes["$raid"]["$ndisks"]["$vbs"]=$refres + + log_must zfs destroy "$vol" + done + + log_must zpool destroy "$TESTPOOL" + done +done + +# A little extra info is always helpful when diagnosing problems. To +# pretty-print what you find in the log, do this in ksh: +# typeset -A sizes=(...) +# print -v sizes +log_note "sizes=$(print -C sizes)" + +# +# Helper furnction for checking that refreservation is calculated properly in +# multi-vdev pools. "Properly" is defined as assuming that all vdevs are as +# space inefficient as the worst one. +# +function check_vdevs { + typeset raid=$1 + typeset nd1=$2 + typeset nd2=$3 + typeset -a disks1 disks2 + typeset vbs vol refres refres1 refres2 expect + + disks1=(${alldisks[0..$((nd1 - 1))]}) + disks2=(${alldisks[$nd1..$((nd1 + nd2 - 1))]}) + if (( ${#disks2[@]} < nd2 )); then + log_note "Too few disks to test $raid-$nd1 + $raid=$nd2" + return + fi + + log_must zpool create -f "$TESTPOOL" \ + "$raid" "${disks1[@]}" "$raid" "${disks2[@]}" + + for bits in "${allshifts[@]}"; do + vbs=$((1 << bits)) + log_note "Verifying $raid-$nd1 $raid-$nd2 volblocksize=$vbs" + + vol=$TESTPOOL/$TESTVOL + log_must zfs create -V ${volsize}m -o volblocksize=$vbs "$vol" + refres=$(zfs get -Hpo value refreservation "$vol") + log_must test -n "$refres" + + refres1=${sizes["$raid"]["$nd1"]["$vbs"]} + refres2=${sizes["$raid"]["$nd2"]["$vbs"]} + + if (( refres1 > refres2 )); then + log_note "Expecting refres ($refres) to match refres" \ + "from $raid-$nd1 ($refres1)" + log_must test "$refres" -eq "$refres1" + else + log_note "Expecting refres ($refres) to match refres" \ + "from $raid-$nd1 ($refres2)" + log_must test "$refres" -eq "$refres2" + fi + + log_must zfs destroy "$vol" + done + + log_must zpool destroy "$TESTPOOL" +} + +# +# Verify that multi-vdev pools use the last optimistic size for all the +# permutations within a particular raidz variant. +# +for raid in "${!sizes[@]}"; do + # ksh likes to create a [0] item for us. Thanks, ksh! + [[ $raid == "0" ]] && continue + + for nd1 in "${!sizes["$raid"][@]}"; do + [[ $nd1 == "0" ]] && continue + + for nd2 in "${!sizes["$raid"][@]}"; do + [[ $nd2 == "0" ]] && continue + + check_vdevs "$raid" "$nd1" "$nd2" + done + done +done + +log_pass "raidz refreservation=auto picks worst raidz vdev" diff --git a/usr/src/test/zfs-tests/tests/functional/refreserv/refreserv_raidz.ksh b/usr/src/test/zfs-tests/tests/functional/refreserv/refreserv_raidz.ksh new file mode 100644 index 0000000000..8628d65e7e --- /dev/null +++ b/usr/src/test/zfs-tests/tests/functional/refreserv/refreserv_raidz.ksh @@ -0,0 +1,130 @@ +#!/bin/ksh -p +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2019 Joyent, Inc. +# + +. $STF_SUITE/include/libtest.shlib +. $STF_SUITE/tests/functional/refreserv/refreserv.cfg + +# +# DESCRIPTION: +# raidz refreservation=auto accounts for extra parity and skip blocks +# +# STRATEGY: +# 1. Create a pool with a single raidz vdev +# 2. For each block size [512b, 1k, 128k] or [4k, 8k, 128k] +# - create a volume +# - fully overwrite it +# - verify that referenced is less than or equal to reservation +# - destroy the volume +# 3. Destroy the pool +# 4. Recreate the pool with one more disk in the vdev, then repeat steps +# 2 and 3. +# 5. Repeat all steps above for raidz2 and raidz3. +# +# NOTES: +# 1. This test will use up to 14 disks but can cover the key concepts with +# 5 disks. +# 2. If the disks are a mixture of 4Kn and 512n/512e, failures are likely. +# + +verify_runnable "global" + +typeset -a alldisks=($DISKS) + +# The larger the volsize, the better zvol_volsize_to_reservation() is at +# guessing the right number. At 10M on ashift=12, the estimate may be over 26% +# too high. +volsize=100 + +function cleanup +{ + default_cleanup_noexit + default_setup_noexit "${alldisks[0]}" +} + +log_assert "raidz refreservation=auto accounts for extra parity and skip blocks" +log_onexit cleanup + +poolexists "$TESTPOOL" && log_must zpool destroy "$TESTPOOL" + +# Testing tiny block sizes on ashift=12 pools causes so much size inflation +# that small test disks may fill before creating small volumes. However, +# testing 512b and 1K blocks on ashift=9 pools is an ok approximation for +# testing the problems that arise from 4K and 8K blocks on ashift=12 pools. +bps=$(prtvtoc /dev/rdsk/${alldisks[0]} | + awk '$NF == "bytes/sector" { print $2; exit 0 }') +log_must test "$bps" -eq 512 -o "$bps" -eq 4096 +case "$bps" in +512) + allshifts=(9 10 17) + maxpct=151 + ;; +4096) + allshifts=(12 13 17) + maxpct=110 + ;; +*) + log_fail "bytes/sector != (512|4096)" + ;; +esac +log_note "Testing in ashift=${allshifts[0]} mode" + +# This loop handles all iterations of steps 1 through 4 described in strategy +# comment above, +for parity in 1 2 3; do + raid=raidz$parity + + # Ensure we hit scenarios with and without skip blocks + for ndisks in $((parity * 2)) $((parity * 2 + 1)); do + typeset -a disks=(${alldisks[0..$((ndisks - 1))]}) + + if (( ${#disks[@]} < ndisks )); then + log_note "Too few disks to test $raid-$ndisks" + continue + fi + + log_must zpool create "$TESTPOOL" "$raid" "${disks[@]}" + + for bits in "${allshifts[@]}"; do + vbs=$((1 << bits)) + log_note "Testing $raid-$ndisks volblocksize=$vbs" + + vol=$TESTPOOL/$TESTVOL + log_must zfs create -V ${volsize}m \ + -o volblocksize=$vbs "$vol" + log_must dd if=/dev/zero of=/dev/zvol/dsk/$vol \ + bs=1024k count=$volsize + sync + + ref=$(zfs get -Hpo value referenced "$vol") + refres=$(zfs get -Hpo value refreservation "$vol") + log_must test -n "$ref" + log_must test -n "$refres" + + typeset -F2 deltapct=$((refres * 100.0 / ref)) + log_note "$raid-$ndisks refreservation $refres" \ + "is $deltapct% of reservation $res" + + log_must test "$ref" -le "$refres" + log_must test "$deltapct" -le $maxpct + + log_must zfs destroy "$vol" + done + + log_must zpool destroy "$TESTPOOL" + done +done + +log_pass "raidz refreservation=auto accounts for extra parity and skip blocks" diff --git a/usr/src/tools/scripts/webrev.sh b/usr/src/tools/scripts/webrev.sh index 88478554e1..22ea97d507 100644 --- a/usr/src/tools/scripts/webrev.sh +++ b/usr/src/tools/scripts/webrev.sh @@ -148,11 +148,16 @@ span.new { ' # CSS for the HTML version of the man pages. -# Current version is from mandoc 1.14.4. +# Current version is from mandoc 1.14.5. MANCSS=' -/* $Id: mandoc.css,v 1.36 2018/07/23 22:51:26 schwarze Exp $ */ +/* $Id: mandoc.css,v 1.45 2019/03/01 10:57:18 schwarze Exp $ */ /* * Standard style sheet for mandoc(1) -Thtml and man.cgi(8). + * + * Written by Ingo Schwarze <schwarze@openbsd.org>. + * I place this file into the public domain. + * Permission to use, copy, modify, and distribute it for any purpose + * with or without fee is hereby granted, without any conditions. */ /* Global defaults. */ @@ -160,8 +165,16 @@ MANCSS=' html { max-width: 65em; } body { font-family: Helvetica,Arial,sans-serif; } table { margin-top: 0em; - margin-bottom: 0em; } -td { vertical-align: top; } + margin-bottom: 0em; + border-collapse: collapse; } +/* Some browsers set border-color in a browser style for tbody, + * but not for table, resulting in inconsistent border styling. */ +tbody { border-color: inherit; } +tr { border-color: inherit; } +td { vertical-align: top; + padding-left: 0.2em; + padding-right: 0.2em; + border-color: inherit; } ul, ol, dl { margin-top: 0em; margin-bottom: 0em; } li, dt { margin-top: 1em; } @@ -204,12 +217,14 @@ td.foot-os { text-align: right; } .manual-text { margin-left: 3.8em; } -.Nd { display: inline; } -.Sh { margin-top: 1.2em; +.Nd { } +section.Sh { } +h1.Sh { margin-top: 1.2em; margin-bottom: 0.6em; margin-left: -3.2em; font-size: 110%; } -.Ss { margin-top: 1.2em; +section.Ss { } +h2.Ss { margin-top: 1.2em; margin-bottom: 0.6em; margin-left: -1.2em; font-size: 105%; } @@ -258,20 +273,25 @@ td.foot-os { text-align: right; } .Bl-ohang > dt { } .Bl-ohang > dd { margin-left: 0em; } -.Bl-tag { margin-left: 5.5em; } +.Bl-tag { margin-top: 0.6em; + margin-left: 5.5em; } .Bl-tag > dt { float: left; margin-top: 0em; margin-left: -5.5em; - padding-right: 1.2em; + padding-right: 0.5em; vertical-align: top; } .Bl-tag > dd { clear: right; width: 100%; margin-top: 0em; margin-left: 0em; + margin-bottom: 0.6em; vertical-align: top; overflow: auto; } +.Bl-compact { margin-top: 0em; } +.Bl-compact > dd { + margin-bottom: 0em; } .Bl-compact > dt { margin-top: 0em; } @@ -303,7 +323,7 @@ td.foot-os { text-align: right; } .RsV { } .eqn { } -.tbl { } +.tbl td { vertical-align: middle; } .HP { margin-left: 3.8em; text-indent: -3.8em; } @@ -388,12 +408,86 @@ a.In { } font-weight: normal; font-family: monospace; } +/* Tooltip support. */ + +h1.Sh, h2.Ss { position: relative; } +.An, .Ar, .Cd, .Cm, .Dv, .Em, .Er, .Ev, .Fa, .Fd, .Fl, .Fn, .Ft, +.Ic, code.In, .Lb, .Lk, .Ms, .Mt, .Nd, code.Nm, .Pa, .Rs, +.St, .Sx, .Sy, .Va, .Vt, .Xr { + display: inline-block; + position: relative; } + +.An::before { content: "An"; } +.Ar::before { content: "Ar"; } +.Cd::before { content: "Cd"; } +.Cm::before { content: "Cm"; } +.Dv::before { content: "Dv"; } +.Em::before { content: "Em"; } +.Er::before { content: "Er"; } +.Ev::before { content: "Ev"; } +.Fa::before { content: "Fa"; } +.Fd::before { content: "Fd"; } +.Fl::before { content: "Fl"; } +.Fn::before { content: "Fn"; } +.Ft::before { content: "Ft"; } +.Ic::before { content: "Ic"; } +code.In::before { content: "In"; } +.Lb::before { content: "Lb"; } +.Lk::before { content: "Lk"; } +.Ms::before { content: "Ms"; } +.Mt::before { content: "Mt"; } +.Nd::before { content: "Nd"; } +code.Nm::before { content: "Nm"; } +.Pa::before { content: "Pa"; } +.Rs::before { content: "Rs"; } +h1.Sh::before { content: "Sh"; } +h2.Ss::before { content: "Ss"; } +.St::before { content: "St"; } +.Sx::before { content: "Sx"; } +.Sy::before { content: "Sy"; } +.Va::before { content: "Va"; } +.Vt::before { content: "Vt"; } +.Xr::before { content: "Xr"; } + +.An::before, .Ar::before, .Cd::before, .Cm::before, +.Dv::before, .Em::before, .Er::before, .Ev::before, +.Fa::before, .Fd::before, .Fl::before, .Fn::before, .Ft::before, +.Ic::before, code.In::before, .Lb::before, .Lk::before, +.Ms::before, .Mt::before, .Nd::before, code.Nm::before, +.Pa::before, .Rs::before, +h1.Sh::before, h2.Ss::before, .St::before, .Sx::before, .Sy::before, +.Va::before, .Vt::before, .Xr::before { + opacity: 0; + transition: .15s ease opacity; + pointer-events: none; + position: absolute; + bottom: 100%; + box-shadow: 0 0 .35em #000; + padding: .15em .25em; + white-space: nowrap; + font-family: Helvetica,Arial,sans-serif; + font-style: normal; + font-weight: bold; + color: black; + background: #fff; } +.An:hover::before, .Ar:hover::before, .Cd:hover::before, .Cm:hover::before, +.Dv:hover::before, .Em:hover::before, .Er:hover::before, .Ev:hover::before, +.Fa:hover::before, .Fd:hover::before, .Fl:hover::before, .Fn:hover::before, +.Ft:hover::before, .Ic:hover::before, code.In:hover::before, +.Lb:hover::before, .Lk:hover::before, .Ms:hover::before, .Mt:hover::before, +.Nd:hover::before, code.Nm:hover::before, .Pa:hover::before, +.Rs:hover::before, h1.Sh:hover::before, h2.Ss:hover::before, .St:hover::before, +.Sx:hover::before, .Sy:hover::before, .Va:hover::before, .Vt:hover::before, +.Xr:hover::before { + opacity: 1; + pointer-events: inherit; } + /* Overrides to avoid excessive margins on small devices. */ @media (max-width: 37.5em) { .manual-text { margin-left: 0.5em; } -.Sh, .Ss { margin-left: 0em; } +h1.Sh, h2.Ss { margin-left: 0em; } .Bd-indent { margin-left: 2em; } .Bl-hang > dd { margin-left: 2em; } @@ -779,7 +873,7 @@ html_quote() $SED -e "s/&/\&/g" -e "s/</\</g" -e "s/>/\>/g" "$@" | expand } -# +# # Trim a digest-style revision to a conventionally readable yet useful length # trim_digest() @@ -1981,7 +2075,7 @@ function git_wxfile } } close(F); - + for (sort keys %files) { if ($realfiles{$_} ne $_) { print "$_ $realfiles{$_}\n$files{$_}\n\n"; diff --git a/usr/src/uts/common/sys/sunddi.h b/usr/src/uts/common/sys/sunddi.h index 8ce8508114..596084f253 100644 --- a/usr/src/uts/common/sys/sunddi.h +++ b/usr/src/uts/common/sys/sunddi.h @@ -24,7 +24,7 @@ * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved. * Copyright (c) 2012 by Delphix. All rights reserved. * Copyright 2016 Nexenta Systems, Inc. All rights reserved. - * Copyright 2019 Joyent, Inc. + * Copyright 2019, Joyent, Inc. */ #ifndef _SYS_SUNDDI_H diff --git a/usr/src/uts/i86pc/os/cpuid.c b/usr/src/uts/i86pc/os/cpuid.c index f53ec818d2..40d5586c08 100644 --- a/usr/src/uts/i86pc/os/cpuid.c +++ b/usr/src/uts/i86pc/os/cpuid.c @@ -1038,7 +1038,7 @@ static char *x86_feature_names[NUM_X86_FEATURES] = { "tbm", "avx512_vnni", "amd_pcec", - "md_clear", + "mb_clear", "mds_no", "core_thermal", "pkg_thermal" diff --git a/usr/src/uts/intel/Makefile.files b/usr/src/uts/intel/Makefile.files index bd10d299d7..54626b8222 100644 --- a/usr/src/uts/intel/Makefile.files +++ b/usr/src/uts/intel/Makefile.files @@ -21,7 +21,7 @@ # # Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. -# Copyright 2019 Joyent, Inc. +# Copyright 2019, Joyent, Inc. # Copyright 2018 Nexenta Systems, Inc. # diff --git a/usr/src/uts/intel/Makefile.intel b/usr/src/uts/intel/Makefile.intel index 5494ae8a30..6dd7be2287 100644 --- a/usr/src/uts/intel/Makefile.intel +++ b/usr/src/uts/intel/Makefile.intel @@ -21,7 +21,7 @@ # # Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2013 Andrew Stormont. All rights reserved. -# Copyright 2019 Joyent, Inc. +# Copyright 2019, Joyent, Inc. # Copyright 2016 Garrett D'Amore <garrett@damore.org> # Copyright 2018 Nexenta Systems, Inc. # |