*
* 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 htmltag {
TAG_HTML,
TAG_HEAD,
TAG_BODY,
TAG_META,
TAG_TITLE,
TAG_DIV,
TAG_H1,
TAG_H2,
TAG_SPAN,
TAG_LINK,
TAG_BR,
TAG_A,
TAG_TABLE,
TAG_COLGROUP,
TAG_COL,
TAG_TR,
TAG_TD,
TAG_LI,
TAG_UL,
TAG_OL,
TAG_DL,
TAG_DT,
TAG_DD,
TAG_PRE,
TAG_VAR,
TAG_CITE,
TAG_B,
TAG_I,
TAG_CODE,
TAG_SMALL,
TAG_STYLE,
TAG_MATH,
TAG_MROW,
TAG_MI,
+ TAG_MN,
TAG_MO,
TAG_MSUP,
TAG_MSUB,
TAG_MSUBSUP,
TAG_MFRAC,
TAG_MSQRT,
TAG_MFENCED,
TAG_MTABLE,
TAG_MTR,
TAG_MTD,
TAG_MUNDEROVER,
TAG_MUNDER,
TAG_MOVER,
TAG_MAX
};
enum htmlfont {
HTMLFONT_NONE = 0,
HTMLFONT_BOLD,
HTMLFONT_ITALIC,
HTMLFONT_BI,
HTMLFONT_MAX
};
struct tag {
struct tag *next;
enum htmltag tag;
};
struct html {
int flags;
#define HTML_NOSPACE (1 << 0) /* suppress next space */
#define HTML_IGNDELIM (1 << 1)
#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., ) 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. */
size_t indent; /* current output indentation level */
int noindent; /* indent disabled by */
size_t col; /* current output byte position */
size_t bufcol; /* current buf byte position */
char buf[80]; /* output buffer */
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_includes; /* base for include href */
char *style; /* style-sheet URI */
struct tag *metaf; /* current open font scope */
enum htmlfont metal; /* last used font */
enum htmlfont metac; /* current font mode */
int oflags; /* output options */
#define HTML_FRAGMENT (1 << 0) /* don't emit HTML/HEAD/BODY */
};
struct roff_node;
struct tbl_span;
-struct eqn;
+struct eqn_box;
void roff_html_pre(struct html *, const struct roff_node *);
void print_gen_decls(struct html *);
void print_gen_head(struct html *);
struct tag *print_otag(struct html *, enum htmltag, const char *, ...);
void print_tagq(struct html *, const struct tag *);
void print_stagq(struct html *, const struct tag *);
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 *);
+void print_eqn(struct html *, const struct eqn_box *);
void print_paragraph(struct html *);
void print_endline(struct html *);
char *html_make_id(const struct roff_node *);
int html_strlen(const char *);
Index: vendor/mdocml/dist/lib.c
===================================================================
--- vendor/mdocml/dist/lib.c (revision 321806)
+++ vendor/mdocml/dist/lib.c (revision 321807)
@@ -1,37 +1,38 @@
-/* $Id: lib.c,v 1.13 2015/10/06 18:32:19 schwarze Exp $ */
+/* $Id: lib.c,v 1.14 2017/06/24 14:38:32 schwarze Exp $ */
/*
* Copyright (c) 2009 Kristaps Dzonsons
*
* 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
#include
+#include "mandoc.h"
#include "roff.h"
#include "mdoc.h"
#include "libmdoc.h"
#define LINE(x, y) \
if (0 == strcmp(p, x)) return(y);
const char *
mdoc_a2lib(const char *p)
{
#include "lib.in"
return NULL;
}
Index: vendor/mdocml/dist/libmandoc.h
===================================================================
--- vendor/mdocml/dist/libmandoc.h (revision 321806)
+++ vendor/mdocml/dist/libmandoc.h (revision 321807)
@@ -1,80 +1,73 @@
-/* $Id: libmandoc.h,v 1.67 2017/04/29 12:45:41 schwarze Exp $ */
+/* $Id: libmandoc.h,v 1.70 2017/07/08 17:52:49 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011, 2012 Kristaps Dzonsons
- * Copyright (c) 2013, 2014, 2015 Ingo Schwarze
+ * Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze
*
* 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.
*/
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 */
- ROFF_TBL, /* a table row was successfully parsed */
- ROFF_EQN /* an equation was successfully parsed */
};
struct buf {
char *buf;
size_t sz;
};
struct mparse;
-struct tbl_span;
-struct eqn;
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 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);
const char *mandoc_a2msec(const char*);
int mdoc_parseln(struct roff_man *, int, char *, int);
void mdoc_endparse(struct roff_man *);
int man_parseln(struct roff_man *, int, char *, int);
void man_endparse(struct roff_man *);
int preconv_cue(const struct buf *, size_t);
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);
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);
void roff_man_reset(struct roff_man *);
enum rofferr roff_parseln(struct roff *, int, struct buf *, int *);
void roff_endparse(struct roff *);
void roff_setreg(struct roff *, const char *, int, char sign);
int roff_getreg(const struct roff *, const char *);
char *roff_strdup(const struct roff *, const char *);
int roff_getcontrol(const struct roff *,
const char *, int *);
int roff_getformat(const struct roff *);
-
-const struct tbl_span *roff_span(const struct roff *);
-const struct eqn *roff_eqn(const struct roff *);
Index: vendor/mdocml/dist/libroff.h
===================================================================
--- vendor/mdocml/dist/libroff.h (revision 321806)
+++ vendor/mdocml/dist/libroff.h (revision 321807)
@@ -1,79 +1,80 @@
-/* $Id: libroff.h,v 1.39 2015/11/07 14:01:16 schwarze Exp $ */
+/* $Id: libroff.h,v 1.42 2017/07/08 17:52:49 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons
- * Copyright (c) 2014, 2015 Ingo Schwarze
+ * Copyright (c) 2014, 2015, 2017 Ingo Schwarze
*
* 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 eqn eqn; /* syntax tree of this equation */
struct mparse *parse; /* main parser, for error reporting */
- struct eqn_node *next; /* singly linked list of equations */
+ 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 cur; /* parse point in the source code */
- size_t rew; /* beginning of the current token */
+ 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 *);
-enum rofferr tbl_read(struct tbl_node *, int, const char *, int);
+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);
-int tbl_cdata(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(int, int, struct mparse *);
-enum rofferr eqn_end(struct eqn_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 *);
-enum rofferr eqn_read(struct eqn_node **, int,
- const char *, int, int *);
+void eqn_parse(struct eqn_node *);
+void eqn_read(struct eqn_node *, const char *);
+void eqn_reset(struct eqn_node *);
Index: vendor/mdocml/dist/main.c
===================================================================
--- vendor/mdocml/dist/main.c (revision 321806)
+++ vendor/mdocml/dist/main.c (revision 321807)
@@ -1,1112 +1,1185 @@
-/* $Id: main.c,v 1.292 2017/06/03 12:17:25 schwarze Exp $ */
+/* $Id: main.c,v 1.301 2017/07/26 10:21:55 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons
* Copyright (c) 2010-2012, 2014-2017 Ingo Schwarze
* Copyright (c) 2010 Joerg Sonnenberger
*
* 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
#include /* MACHINE */
#include
#include
#include
#if HAVE_ERR
#include
#endif
#include
#include
#include
#if HAVE_SANDBOX_INIT
#include
#endif
#include
#include
#include
#include
#include
#include
#include
#include "mandoc_aux.h"
#include "mandoc.h"
+#include "mandoc_xr.h"
#include "roff.h"
#include "mdoc.h"
#include "man.h"
#include "tag.h"
#include "main.h"
#include "manconf.h"
#include "mansearch.h"
enum outmode {
OUTMODE_DEF = 0,
OUTMODE_FLN,
OUTMODE_LST,
OUTMODE_ALL,
OUTMODE_ONE
};
enum outt {
OUTT_ASCII = 0, /* -Tascii */
OUTT_LOCALE, /* -Tlocale */
OUTT_UTF8, /* -Tutf8 */
OUTT_TREE, /* -Ttree */
OUTT_MAN, /* -Tman */
OUTT_HTML, /* -Thtml */
OUTT_MARKDOWN, /* -Tmarkdown */
OUTT_LINT, /* -Tlint */
OUTT_PS, /* -Tps */
OUTT_PDF /* -Tpdf */
};
struct curparse {
struct mparse *mp;
- enum mandoclevel wlevel; /* ignore messages below this */
+ struct manoutput *outopts; /* output options */
+ 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 */
- void *outdata; /* data for output */
- struct manoutput *outopts; /* output options */
};
int mandocdb(int, char *[]);
+static void check_xr(const char *);
static int fs_lookup(const struct manpaths *,
size_t ipath, const char *,
const char *, const char *,
struct manpage **, size_t *);
-static void fs_search(const struct mansearch *,
+static int fs_search(const struct mansearch *,
const struct manpaths *, int, char**,
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);
static pid_t spawn_pager(struct tag_files *);
static int toptions(struct curparse *, char *);
static void usage(enum argmode) __attribute__((__noreturn__));
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
main(int argc, char *argv[])
{
struct manconf conf;
struct mansearch search;
struct curparse curp;
struct tag_files *tag_files;
struct manpage *res, *resp;
const char *progname, *sec, *thisarg;
char *conf_file, *defpaths, *auxpaths;
- char *defos, *oarg;
+ char *oarg;
unsigned char *uc;
size_t i, sz;
int prio, best_prio;
enum outmode outmode;
int fd;
int show_usage;
int options;
int use_pager;
int status, signum;
int c;
pid_t pager_pid, tc_pgid, man_pgid, pid;
#if HAVE_PROGNAME
progname = getprogname();
#else
if (argc < 1)
progname = mandoc_strdup("mandoc");
else if ((progname = strrchr(argv[0], '/')) == NULL)
progname = argv[0];
else
++progname;
setprogname(progname);
#endif
if (strncmp(progname, "mandocdb", 8) == 0 ||
strcmp(progname, BINM_MAKEWHATIS) == 0)
return mandocdb(argc, argv);
#if HAVE_PLEDGE
if (pledge("stdio rpath tmppath tty proc exec", NULL) == -1)
err((int)MANDOCLEVEL_SYSERR, "pledge");
#endif
#if HAVE_SANDBOX_INIT
if (sandbox_init(kSBXProfileNoInternet, SANDBOX_NAMED, NULL) == -1)
errx((int)MANDOCLEVEL_SYSERR, "sandbox_init");
#endif
/* Search options. */
memset(&conf, 0, sizeof(conf));
conf_file = defpaths = NULL;
auxpaths = NULL;
memset(&search, 0, sizeof(struct mansearch));
search.outkey = "Nd";
oarg = NULL;
if (strcmp(progname, BINM_MAN) == 0)
search.argmode = ARG_NAME;
else if (strcmp(progname, BINM_APROPOS) == 0)
search.argmode = ARG_EXPR;
else if (strcmp(progname, BINM_WHATIS) == 0)
search.argmode = ARG_WORD;
else if (strncmp(progname, "help", 4) == 0)
search.argmode = ARG_NAME;
else
search.argmode = ARG_FILE;
/* Parser and formatter options. */
memset(&curp, 0, sizeof(struct curparse));
curp.outtype = OUTT_LOCALE;
- curp.wlevel = MANDOCLEVEL_BADARG;
+ curp.mmin = MANDOCERR_MAX;
curp.outopts = &conf.output;
options = MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1;
- defos = NULL;
+ mmsg_stream = stderr;
use_pager = 1;
tag_files = NULL;
show_usage = 0;
outmode = OUTMODE_DEF;
while ((c = getopt(argc, argv,
"aC:cfhI:iK:klM:m:O:S:s:T:VW:w")) != -1) {
if (c == 'i' && search.argmode == ARG_EXPR) {
optind--;
break;
}
switch (c) {
case 'a':
outmode = OUTMODE_ALL;
break;
case 'C':
conf_file = optarg;
break;
case 'c':
use_pager = 0;
break;
case 'f':
search.argmode = ARG_WORD;
break;
case 'h':
conf.output.synopsisonly = 1;
use_pager = 0;
outmode = OUTMODE_ALL;
break;
case 'I':
if (strncmp(optarg, "os=", 3)) {
warnx("-I %s: Bad argument", optarg);
return (int)MANDOCLEVEL_BADARG;
}
- if (defos) {
+ if (curp.os_s != NULL) {
warnx("-I %s: Duplicate argument", optarg);
return (int)MANDOCLEVEL_BADARG;
}
- defos = mandoc_strdup(optarg + 3);
+ curp.os_s = mandoc_strdup(optarg + 3);
break;
case 'K':
if ( ! koptions(&options, optarg))
return (int)MANDOCLEVEL_BADARG;
break;
case 'k':
search.argmode = ARG_EXPR;
break;
case 'l':
search.argmode = ARG_FILE;
outmode = OUTMODE_ALL;
break;
case 'M':
defpaths = optarg;
break;
case 'm':
auxpaths = optarg;
break;
case 'O':
oarg = optarg;
break;
case 'S':
search.arch = optarg;
break;
case 's':
search.sec = optarg;
break;
case 'T':
if ( ! toptions(&curp, optarg))
return (int)MANDOCLEVEL_BADARG;
break;
case 'W':
if ( ! woptions(&curp, optarg))
return (int)MANDOCLEVEL_BADARG;
break;
case 'w':
outmode = OUTMODE_FLN;
break;
default:
show_usage = 1;
break;
}
}
if (show_usage)
usage(search.argmode);
/* Postprocess options. */
if (outmode == OUTMODE_DEF) {
switch (search.argmode) {
case ARG_FILE:
outmode = OUTMODE_ALL;
use_pager = 0;
break;
case ARG_NAME:
outmode = OUTMODE_ONE;
break;
default:
outmode = OUTMODE_LST;
break;
}
}
if (oarg != NULL) {
if (outmode == OUTMODE_LST)
search.outkey = oarg;
else {
while (oarg != NULL) {
thisarg = oarg;
if (manconf_output(&conf.output,
strsep(&oarg, ","), 0) == 0)
continue;
warnx("-O %s: Bad argument", thisarg);
return (int)MANDOCLEVEL_BADARG;
}
}
}
if (outmode == OUTMODE_FLN ||
outmode == OUTMODE_LST ||
!isatty(STDOUT_FILENO))
use_pager = 0;
#if HAVE_PLEDGE
if (!use_pager)
if (pledge("stdio rpath", NULL) == -1)
err((int)MANDOCLEVEL_SYSERR, "pledge");
#endif
/* Parse arguments. */
if (argc > 0) {
argc -= optind;
argv += optind;
}
resp = NULL;
/*
* Quirks for help(1)
* and for a man(1) section argument without -s.
*/
if (search.argmode == ARG_NAME) {
if (*progname == 'h') {
if (argc == 0) {
argv = help_argv;
argc = 1;
}
} else if (argc > 1 &&
((uc = (unsigned char *)argv[0]) != NULL) &&
((isdigit(uc[0]) && (uc[1] == '\0' ||
(isalpha(uc[1]) && uc[2] == '\0'))) ||
(uc[0] == 'n' && uc[1] == '\0'))) {
search.sec = (char *)uc;
argv++;
argc--;
}
if (search.arch == NULL)
search.arch = getenv("MACHINE");
#ifdef MACHINE
if (search.arch == NULL)
search.arch = MACHINE;
#endif
}
rc = MANDOCLEVEL_OK;
/* man(1), whatis(1), apropos(1) */
if (search.argmode != ARG_FILE) {
if (search.argmode == ARG_NAME &&
outmode == OUTMODE_ONE)
search.firstmatch = 1;
/* Access the mandoc database. */
manconf_parse(&conf, conf_file, defpaths, auxpaths);
if ( ! mansearch(&search, &conf.manpath,
argc, argv, &res, &sz))
usage(search.argmode);
if (sz == 0) {
if (search.argmode == ARG_NAME)
fs_search(&search, &conf.manpath,
argc, argv, &res, &sz);
else
warnx("nothing appropriate");
}
if (sz == 0) {
rc = MANDOCLEVEL_BADARG;
goto out;
}
/*
* For standard man(1) and -a output mode,
* prepare for copying filename pointers
* into the program parameter array.
*/
if (outmode == OUTMODE_ONE) {
argc = 1;
best_prio = 20;
} else if (outmode == OUTMODE_ALL)
argc = (int)sz;
/* Iterate all matching manuals. */
resp = res;
for (i = 0; i < sz; i++) {
if (outmode == OUTMODE_FLN)
puts(res[i].file);
else if (outmode == OUTMODE_LST)
printf("%s - %s\n", res[i].names,
res[i].output == NULL ? "" :
res[i].output);
else if (outmode == OUTMODE_ONE) {
/* Search for the best section. */
sec = res[i].file;
sec += strcspn(sec, "123456789");
if (sec[0] == '\0')
continue;
prio = sec_prios[sec[0] - '1'];
if (sec[1] != '/')
prio += 10;
if (prio >= best_prio)
continue;
best_prio = prio;
resp = res + i;
}
}
/*
* For man(1), -a and -i output mode, fall through
* to the main mandoc(1) code iterating files
* and running the parsers on each of them.
*/
if (outmode == OUTMODE_FLN || outmode == OUTMODE_LST)
goto out;
}
/* mandoc(1) */
#if HAVE_PLEDGE
if (use_pager) {
if (pledge("stdio rpath tmppath tty proc exec", NULL) == -1)
err((int)MANDOCLEVEL_SYSERR, "pledge");
} else {
if (pledge("stdio rpath", NULL) == -1)
err((int)MANDOCLEVEL_SYSERR, "pledge");
}
#endif
if (search.argmode == ARG_FILE)
moptions(&options, auxpaths);
mchars_alloc();
- curp.mp = mparse_alloc(options, curp.wlevel, mmsg, defos);
+ 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);
if (argc < 1) {
if (use_pager)
tag_files = tag_init();
parse(&curp, STDIN_FILENO, "");
}
while (argc > 0) {
fd = mparse_open(curp.mp, resp != NULL ? resp->file : *argv);
if (fd != -1) {
if (use_pager) {
tag_files = tag_init();
use_pager = 0;
}
if (resp == NULL)
parse(&curp, fd, *argv);
else if (resp->form == FORM_SRC) {
/* For .so only; ignore failure. */
- chdir(conf.manpath.paths[resp->ipath]);
+ (void)chdir(conf.manpath.paths[resp->ipath]);
parse(&curp, fd, resp->file);
} else
passthrough(resp->file, fd,
conf.output.synopsisonly);
if (argc > 1 && curp.outtype <= OUTT_UTF8) {
if (curp.outdata == NULL)
outdata_alloc(&curp);
terminal_sepline(curp.outdata);
}
} else if (rc < MANDOCLEVEL_ERROR)
rc = MANDOCLEVEL_ERROR;
if (MANDOCLEVEL_OK != rc && curp.wstop)
break;
if (resp != NULL)
resp++;
else
argv++;
if (--argc)
mparse_reset(curp.mp);
}
if (curp.outdata != NULL) {
switch (curp.outtype) {
case OUTT_HTML:
html_free(curp.outdata);
break;
case OUTT_UTF8:
case OUTT_LOCALE:
case OUTT_ASCII:
ascii_free(curp.outdata);
break;
case OUTT_PDF:
case OUTT_PS:
pspdf_free(curp.outdata);
break;
default:
break;
}
}
+ mandoc_xr_free();
mparse_free(curp.mp);
mchars_free();
out:
if (search.argmode != ARG_FILE) {
manconf_free(&conf);
mansearch_free(res, sz);
}
- free(defos);
+ free(curp.os_s);
/*
* When using a pager, finish writing both temporary files,
* fork it, wait for the user to close it, and clean up.
*/
if (tag_files != NULL) {
fclose(stdout);
tag_write();
man_pgid = getpgid(0);
tag_files->tcpgid = man_pgid == getpid() ?
getpgid(getppid()) : man_pgid;
pager_pid = 0;
signum = SIGSTOP;
for (;;) {
/* Stop here until moved to the foreground. */
tc_pgid = tcgetpgrp(tag_files->ofd);
if (tc_pgid != man_pgid) {
if (tc_pgid == pager_pid) {
(void)tcsetpgrp(tag_files->ofd,
man_pgid);
if (signum == SIGTTIN)
continue;
} else
tag_files->tcpgid = tc_pgid;
kill(0, signum);
continue;
}
/* Once in the foreground, activate the pager. */
if (pager_pid) {
(void)tcsetpgrp(tag_files->ofd, pager_pid);
kill(pager_pid, SIGCONT);
} else
pager_pid = spawn_pager(tag_files);
/* Wait for the pager to stop or exit. */
while ((pid = waitpid(pager_pid, &status,
WUNTRACED)) == -1 && errno == EINTR)
continue;
if (pid == -1) {
warn("wait");
rc = MANDOCLEVEL_SYSERR;
break;
}
if (!WIFSTOPPED(status))
break;
signum = WSTOPSIG(status);
}
tag_unlink();
}
return (int)rc;
}
static void
usage(enum argmode argmode)
{
switch (argmode) {
case ARG_FILE:
fputs("usage: mandoc [-ac] [-I os=name] "
"[-K encoding] [-mdoc | -man] [-O options]\n"
"\t [-T output] [-W level] [file ...]\n", stderr);
break;
case ARG_NAME:
fputs("usage: man [-acfhklw] [-C file] [-M path] "
"[-m path] [-S subsection]\n"
"\t [[-s] section] name ...\n", stderr);
break;
case ARG_WORD:
fputs("usage: whatis [-afk] [-C file] "
"[-M path] [-m path] [-O outkey] [-S arch]\n"
"\t [-s section] name ...\n", stderr);
break;
case ARG_EXPR:
fputs("usage: apropos [-afk] [-C file] "
"[-M path] [-m path] [-O outkey] [-S arch]\n"
"\t [-s section] expression ...\n", stderr);
break;
}
exit((int)MANDOCLEVEL_BADARG);
}
static int
fs_lookup(const struct manpaths *paths, size_t ipath,
const char *sec, const char *arch, const char *name,
struct manpage **res, size_t *ressz)
{
glob_t globinfo;
struct manpage *page;
char *file;
int globres;
enum form form;
form = FORM_SRC;
mandoc_asprintf(&file, "%s/man%s/%s.%s",
paths->paths[ipath], sec, name, sec);
if (access(file, R_OK) != -1)
goto found;
free(file);
mandoc_asprintf(&file, "%s/cat%s/%s.0",
paths->paths[ipath], sec, name);
if (access(file, R_OK) != -1) {
form = FORM_CAT;
goto found;
}
free(file);
if (arch != NULL) {
mandoc_asprintf(&file, "%s/man%s/%s/%s.%s",
paths->paths[ipath], sec, arch, name, sec);
if (access(file, R_OK) != -1)
goto found;
free(file);
}
mandoc_asprintf(&file, "%s/man%s/%s.[01-9]*",
paths->paths[ipath], sec, name);
globres = glob(file, 0, NULL, &globinfo);
if (globres != 0 && globres != GLOB_NOMATCH)
warn("%s: glob", file);
free(file);
if (globres == 0)
file = mandoc_strdup(*globinfo.gl_pathv);
globfree(&globinfo);
- if (globres != 0)
+ if (globres == 0)
+ goto found;
+ if (res != NULL || ipath + 1 != paths->sz)
return 0;
+ mandoc_asprintf(&file, "%s.%s", name, sec);
+ globres = access(file, R_OK);
+ free(file);
+ return globres != -1;
+
found:
warnx("outdated mandoc.db lacks %s(%s) entry, run %s %s",
name, sec, BINM_MAKEWHATIS, paths->paths[ipath]);
+ if (res == NULL) {
+ free(file);
+ return 1;
+ }
*res = mandoc_reallocarray(*res, ++*ressz, sizeof(struct manpage));
page = *res + (*ressz - 1);
page->file = file;
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;
}
-static void
+static int
fs_search(const struct mansearch *cfg, const struct manpaths *paths,
int argc, char **argv, struct manpage **res, size_t *ressz)
{
const char *const sections[] =
{"1", "8", "6", "2", "3", "5", "7", "4", "9", "3p"};
const size_t nsec = sizeof(sections)/sizeof(sections[0]);
size_t ipath, isec, lastsz;
assert(cfg->argmode == ARG_NAME);
- *res = NULL;
+ if (res != NULL)
+ *res = NULL;
*ressz = lastsz = 0;
while (argc) {
for (ipath = 0; ipath < paths->sz; ipath++) {
if (cfg->sec != NULL) {
if (fs_lookup(paths, ipath, cfg->sec,
cfg->arch, *argv, res, ressz) &&
cfg->firstmatch)
- return;
+ return 1;
} else for (isec = 0; isec < nsec; isec++)
if (fs_lookup(paths, ipath, sections[isec],
cfg->arch, *argv, res, ressz) &&
cfg->firstmatch)
- return;
+ return 1;
}
- if (*ressz == lastsz)
+ if (res != NULL && *ressz == lastsz)
warnx("No entry for %s in the manual.", *argv);
lastsz = *ressz;
argv++;
argc--;
}
+ return 0;
}
static void
parse(struct curparse *curp, int fd, const char *file)
{
enum mandoclevel rctmp;
struct roff_man *man;
/* Begin by parsing the file itself. */
assert(file);
assert(fd >= 0);
rctmp = 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)
return;
if (curp->outdata == NULL)
outdata_alloc(curp);
mparse_result(curp->mp, &man, NULL);
/* 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);
switch (curp->outtype) {
case OUTT_HTML:
html_mdoc(curp->outdata, man);
break;
case OUTT_TREE:
tree_mdoc(curp->outdata, man);
break;
case OUTT_MAN:
man_mdoc(curp->outdata, man);
break;
case OUTT_PDF:
case OUTT_ASCII:
case OUTT_UTF8:
case OUTT_LOCALE:
case OUTT_PS:
terminal_mdoc(curp->outdata, man);
break;
case OUTT_MARKDOWN:
markdown_mdoc(curp->outdata, man);
break;
default:
break;
}
}
if (man->macroset == MACROSET_MAN) {
if (curp->outtype != OUTT_TREE || !curp->outopts->noval)
man_validate(man);
switch (curp->outtype) {
case OUTT_HTML:
html_man(curp->outdata, man);
break;
case OUTT_TREE:
tree_man(curp->outdata, man);
break;
case OUTT_MAN:
man_man(curp->outdata, man);
break;
case OUTT_PDF:
case OUTT_ASCII:
case OUTT_UTF8:
case OUTT_LOCALE:
case OUTT_PS:
terminal_man(curp->outdata, man);
break;
default:
break;
}
}
+ if (curp->mmin < MANDOCERR_STYLE)
+ check_xr(file);
mparse_updaterc(curp->mp, &rc);
}
static void
+check_xr(const char *file)
+{
+ static struct manpaths paths;
+ struct mansearch search;
+ struct mandoc_xr *xr;
+ char *cp;
+ size_t sz;
+
+ if (paths.sz == 0)
+ manpath_base(&paths);
+
+ for (xr = mandoc_xr_get(); xr != NULL; xr = xr->next) {
+ if (xr->line == -1)
+ continue;
+ search.arch = NULL;
+ search.sec = xr->sec;
+ search.outkey = NULL;
+ search.argmode = ARG_NAME;
+ search.firstmatch = 1;
+ if (mansearch(&search, &paths, 1, &xr->name, NULL, &sz))
+ continue;
+ 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);
+ else
+ mandoc_asprintf(&cp, "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);
+ }
+}
+
+static void
outdata_alloc(struct curparse *curp)
{
switch (curp->outtype) {
case OUTT_HTML:
curp->outdata = html_alloc(curp->outopts);
break;
case OUTT_UTF8:
curp->outdata = utf8_alloc(curp->outopts);
break;
case OUTT_LOCALE:
curp->outdata = locale_alloc(curp->outopts);
break;
case OUTT_ASCII:
curp->outdata = ascii_alloc(curp->outopts);
break;
case OUTT_PDF:
curp->outdata = pdf_alloc(curp->outopts);
break;
case OUTT_PS:
curp->outdata = ps_alloc(curp->outopts);
break;
default:
break;
}
}
static void
passthrough(const char *file, int fd, int synopsis_only)
{
const char synb[] = "S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS";
const char synr[] = "SYNOPSIS";
FILE *stream;
const char *syscall;
char *line, *cp;
size_t linesz;
ssize_t len, written;
int print;
line = NULL;
linesz = 0;
if (fflush(stdout) == EOF) {
syscall = "fflush";
goto fail;
}
if ((stream = fdopen(fd, "r")) == NULL) {
close(fd);
syscall = "fdopen";
goto fail;
}
print = 0;
while ((len = getline(&line, &linesz, stream)) != -1) {
cp = line;
if (synopsis_only) {
if (print) {
if ( ! isspace((unsigned char)*cp))
goto done;
while (isspace((unsigned char)*cp)) {
cp++;
len--;
}
} else {
if (strcmp(cp, synb) == 0 ||
strcmp(cp, synr) == 0)
print = 1;
continue;
}
}
for (; len > 0; len -= written) {
if ((written = write(STDOUT_FILENO, cp, len)) != -1)
continue;
fclose(stream);
syscall = "write";
goto fail;
}
}
if (ferror(stream)) {
fclose(stream);
syscall = "getline";
goto fail;
}
done:
free(line);
fclose(stream);
return;
fail:
free(line);
warn("%s: SYSERR: %s", file, syscall);
if (rc < MANDOCLEVEL_SYSERR)
rc = MANDOCLEVEL_SYSERR;
}
static int
koptions(int *options, char *arg)
{
if ( ! strcmp(arg, "utf-8")) {
*options |= MPARSE_UTF8;
*options &= ~MPARSE_LATIN1;
} else if ( ! strcmp(arg, "iso-8859-1")) {
*options |= MPARSE_LATIN1;
*options &= ~MPARSE_UTF8;
} else if ( ! strcmp(arg, "us-ascii")) {
*options &= ~(MPARSE_UTF8 | MPARSE_LATIN1);
} else {
warnx("-K %s: Bad argument", arg);
return 0;
}
return 1;
}
static void
moptions(int *options, char *arg)
{
if (arg == NULL)
return;
if (strcmp(arg, "doc") == 0)
*options |= MPARSE_MDOC;
else if (strcmp(arg, "an") == 0)
*options |= MPARSE_MAN;
}
static int
toptions(struct curparse *curp, char *arg)
{
if (0 == strcmp(arg, "ascii"))
curp->outtype = OUTT_ASCII;
else if (0 == strcmp(arg, "lint")) {
curp->outtype = OUTT_LINT;
- curp->wlevel = MANDOCLEVEL_STYLE;
+ curp->mmin = MANDOCERR_BASE;
+ mmsg_stream = stdout;
} else if (0 == strcmp(arg, "tree"))
curp->outtype = OUTT_TREE;
else if (0 == strcmp(arg, "man"))
curp->outtype = OUTT_MAN;
else if (0 == strcmp(arg, "html"))
curp->outtype = OUTT_HTML;
else if (0 == strcmp(arg, "markdown"))
curp->outtype = OUTT_MARKDOWN;
else if (0 == strcmp(arg, "utf8"))
curp->outtype = OUTT_UTF8;
else if (0 == strcmp(arg, "locale"))
curp->outtype = OUTT_LOCALE;
else if (0 == strcmp(arg, "ps"))
curp->outtype = OUTT_PS;
else if (0 == strcmp(arg, "pdf"))
curp->outtype = OUTT_PDF;
else {
warnx("-T %s: Bad argument", arg);
return 0;
}
return 1;
}
static int
woptions(struct curparse *curp, char *arg)
{
char *v, *o;
- const char *toks[8];
+ const char *toks[11];
toks[0] = "stop";
toks[1] = "all";
- toks[2] = "style";
- toks[3] = "warning";
- toks[4] = "error";
- toks[5] = "unsupp";
- toks[6] = "fatal";
- toks[7] = NULL;
+ toks[2] = "base";
+ toks[3] = "style";
+ toks[4] = "warning";
+ toks[5] = "error";
+ toks[6] = "unsupp";
+ toks[7] = "fatal";
+ toks[8] = "openbsd";
+ toks[9] = "netbsd";
+ toks[10] = NULL;
while (*arg) {
o = arg;
switch (getsubopt(&arg, (char * const *)toks, &v)) {
case 0:
curp->wstop = 1;
break;
case 1:
case 2:
- curp->wlevel = MANDOCLEVEL_STYLE;
+ curp->mmin = MANDOCERR_BASE;
break;
case 3:
- curp->wlevel = MANDOCLEVEL_WARNING;
+ curp->mmin = MANDOCERR_STYLE;
break;
case 4:
- curp->wlevel = MANDOCLEVEL_ERROR;
+ curp->mmin = MANDOCERR_WARNING;
break;
case 5:
- curp->wlevel = MANDOCLEVEL_UNSUPP;
+ curp->mmin = MANDOCERR_ERROR;
break;
case 6:
- curp->wlevel = MANDOCLEVEL_BADARG;
+ curp->mmin = MANDOCERR_UNSUPP;
break;
+ case 7:
+ curp->mmin = MANDOCERR_MAX;
+ break;
+ case 8:
+ curp->mmin = MANDOCERR_BASE;
+ curp->os_e = MANDOC_OS_OPENBSD;
+ break;
+ case 9:
+ curp->mmin = MANDOCERR_BASE;
+ curp->os_e = MANDOC_OS_NETBSD;
+ break;
default:
warnx("-W %s: Bad argument", o);
return 0;
}
}
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(stderr, "%s: %s:", getprogname(),
+ fprintf(mmsg_stream, "%s: %s:", getprogname(),
file == NULL ? "" : file);
if (line)
- fprintf(stderr, "%d:%d:", line, col + 1);
+ fprintf(mmsg_stream, "%d:%d:", line, col + 1);
- fprintf(stderr, " %s", mparse_strlevel(lvl));
+ fprintf(mmsg_stream, " %s", mparse_strlevel(lvl));
- if (NULL != (mparse_msg = mparse_strerror(t)))
- fprintf(stderr, ": %s", mparse_msg);
+ if ((mparse_msg = mparse_strerror(t)) != NULL)
+ fprintf(mmsg_stream, ": %s", mparse_msg);
if (msg)
- fprintf(stderr, ": %s", msg);
+ fprintf(mmsg_stream, ": %s", msg);
- fputc('\n', stderr);
+ fputc('\n', mmsg_stream);
}
static pid_t
spawn_pager(struct tag_files *tag_files)
{
const struct timespec timeout = { 0, 100000000 }; /* 0.1s */
#define MAX_PAGER_ARGS 16
char *argv[MAX_PAGER_ARGS];
const char *pager;
char *cp;
size_t cmdlen;
int argc;
pid_t pager_pid;
pager = getenv("MANPAGER");
if (pager == NULL || *pager == '\0')
pager = getenv("PAGER");
if (pager == NULL || *pager == '\0')
pager = "more -s";
cp = mandoc_strdup(pager);
/*
* Parse the pager command into words.
* Intentionally do not do anything fancy here.
*/
argc = 0;
while (argc + 4 < MAX_PAGER_ARGS) {
argv[argc++] = cp;
cp = strchr(cp, ' ');
if (cp == NULL)
break;
*cp++ = '\0';
while (*cp == ' ')
cp++;
if (*cp == '\0')
break;
}
/* For less(1), use the tag file. */
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;
}
}
argv[argc++] = tag_files->ofn;
argv[argc] = NULL;
switch (pager_pid = fork()) {
case -1:
err((int)MANDOCLEVEL_SYSERR, "fork");
case 0:
break;
default:
(void)setpgid(pager_pid, 0);
(void)tcsetpgrp(tag_files->ofd, pager_pid);
#if HAVE_PLEDGE
if (pledge("stdio rpath tmppath tty proc", NULL) == -1)
err((int)MANDOCLEVEL_SYSERR, "pledge");
#endif
tag_files->pager_pid = pager_pid;
return pager_pid;
}
/* The child process becomes the pager. */
if (dup2(tag_files->ofd, STDOUT_FILENO) == -1)
err((int)MANDOCLEVEL_SYSERR, "pager stdout");
close(tag_files->ofd);
close(tag_files->tfd);
/* Do not start the pager before controlling the terminal. */
while (tcgetpgrp(STDOUT_FILENO) != getpid())
nanosleep(&timeout, NULL);
execvp(argv[0], argv);
err((int)MANDOCLEVEL_SYSERR, "exec %s", argv[0]);
}
Index: vendor/mdocml/dist/man.7
===================================================================
--- vendor/mdocml/dist/man.7 (revision 321806)
+++ vendor/mdocml/dist/man.7 (revision 321807)
@@ -1,901 +1,915 @@
-.\" $Id: man.7,v 1.135 2017/05/07 21:44:49 schwarze Exp $
+.\" $Id: man.7,v 1.136 2017/06/25 11:42:02 schwarze Exp $
.\"
.\" Copyright (c) 2009, 2010, 2011, 2012 Kristaps Dzonsons
.\" Copyright (c) 2011-2015 Ingo Schwarze
.\" Copyright (c) 2010 Joerg Sonnenberger
.\"
.\" 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.
.\"
-.Dd $Mdocdate: May 7 2017 $
+.Dd $Mdocdate: June 25 2017 $
.Dt MAN 7
.Os
.Sh NAME
.Nm man
.Nd legacy formatting language for manual pages
.Sh DESCRIPTION
Traditionally, the
.Nm man
language has been used to write
.Ux
manuals for the
.Xr man 1
utility.
It supports limited control of presentational details like fonts,
indentation and spacing.
This reference document describes the structure of manual pages
and the syntax and usage of the man language.
.Pp
.Bf -emphasis
Do not use
.Nm
to write your manuals:
.Ef
It lacks support for semantic markup.
Use the
.Xr mdoc 7
language, instead.
.Pp
In a
.Nm
document, lines beginning with the control character
.Sq \&.
are called
.Dq macro lines .
The first word is the macro name.
It usually consists of two capital letters.
For a list of available macros, see
.Sx MACRO OVERVIEW .
The words following the macro name are arguments to the macro.
.Pp
Lines not beginning with the control character are called
.Dq text lines .
They provide free-form text to be printed; the formatting of the text
depends on the respective processing context:
.Bd -literal -offset indent
\&.SH Macro lines change control state.
Text lines are interpreted within the current state.
.Ed
.Pp
Many aspects of the basic syntax of the
.Nm
language are based on the
.Xr roff 7
language; see the
.Em LANGUAGE SYNTAX
and
.Em MACRO SYNTAX
sections in the
.Xr roff 7
manual for details, in particular regarding
comments, escape sequences, whitespace, and quoting.
.Sh MANUAL STRUCTURE
Each
.Nm
document must contain the
.Sx \&TH
macro describing the document's section and title.
It may occur anywhere in the document, although conventionally it
appears as the first macro.
.Pp
Beyond
.Sx \&TH ,
at least one macro or text line must appear in the document.
.Pp
The following is a well-formed skeleton
.Nm
file for a utility
.Qq progname :
.Bd -literal -offset indent
\&.TH PROGNAME 1 2009-10-10
\&.SH NAME
\efBprogname\efR \e(en one line about what it does
\&.\e\(dq .SH LIBRARY
\&.\e\(dq For sections 2, 3, and 9 only.
\&.\e\(dq Not used in OpenBSD.
\&.SH SYNOPSIS
\efBprogname\efR [\efB\e-options\efR] \efIfile ...\efR
\&.SH DESCRIPTION
The \efBfoo\efR utility processes files ...
\&.\e\(dq .Sh CONTEXT
\&.\e\(dq For section 9 functions only.
\&.\e\(dq .SH IMPLEMENTATION NOTES
\&.\e\(dq Not used in OpenBSD.
\&.\e\(dq .SH RETURN VALUES
\&.\e\(dq For sections 2, 3, and 9 function return values only.
\&.\e\(dq .SH ENVIRONMENT
\&.\e\(dq For sections 1, 6, 7, and 8 only.
\&.\e\(dq .SH FILES
\&.\e\(dq .SH EXIT STATUS
\&.\e\(dq For sections 1, 6, and 8 only.
\&.\e\(dq .SH EXAMPLES
\&.\e\(dq .SH DIAGNOSTICS
\&.\e\(dq For sections 1, 4, 6, 7, 8, and 9 printf/stderr messages only.
\&.\e\(dq .SH ERRORS
\&.\e\(dq For sections 2, 3, 4, and 9 errno settings only.
\&.\e\(dq .SH SEE ALSO
\&.\e\(dq .BR foobar ( 1 )
\&.\e\(dq .SH STANDARDS
\&.\e\(dq .SH HISTORY
\&.\e\(dq .SH AUTHORS
\&.\e\(dq .SH CAVEATS
\&.\e\(dq .SH BUGS
\&.\e\(dq .SH SECURITY CONSIDERATIONS
\&.\e\(dq Not used in OpenBSD.
.Ed
.Pp
The sections in a
.Nm
document are conventionally ordered as they appear above.
Sections should be composed as follows:
.Bl -ohang -offset indent
.It Em NAME
The name(s) and a short description of the documented material.
The syntax for this is generally as follows:
.Pp
.D1 \efBname\efR \e(en description
.It Em LIBRARY
The name of the library containing the documented material, which is
assumed to be a function in a section 2 or 3 manual.
For functions in the C library, this may be as follows:
.Pp
.D1 Standard C Library (libc, -lc)
.It Em SYNOPSIS
Documents the utility invocation syntax, function call syntax, or device
configuration.
.Pp
For the first, utilities (sections 1, 6, and 8), this is
generally structured as follows:
.Pp
.D1 \efBname\efR [-\efBab\efR] [-\efBc\efR\efIarg\efR] \efBpath\efR...
.Pp
For the second, function calls (sections 2, 3, 9):
.Pp
.D1 \&.B char *name(char *\efIarg\efR);
.Pp
And for the third, configurations (section 4):
.Pp
.D1 \&.B name* at cardbus ? function ?
.Pp
Manuals not in these sections generally don't need a
.Em SYNOPSIS .
.It Em DESCRIPTION
This expands upon the brief, one-line description in
.Em NAME .
It usually contains a break-down of the options (if documenting a
command).
.It Em CONTEXT
This section lists the contexts in which functions can be called in section 9.
The contexts are autoconf, process, or interrupt.
.It Em IMPLEMENTATION NOTES
Implementation-specific notes should be kept here.
This is useful when implementing standard functions that may have side
effects or notable algorithmic implications.
.It Em RETURN VALUES
This section documents the return values of functions in sections 2, 3, and 9.
.It Em ENVIRONMENT
Documents any usages of environment variables, e.g.,
.Xr environ 7 .
.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.).
.It Em EXIT STATUS
This section documents the command exit status for
section 1, 6, and 8 utilities.
Historically, this information was described in
.Em DIAGNOSTICS ,
a practise that is now discouraged.
.It Em EXAMPLES
Example usages.
This often contains snippets of well-formed,
well-tested invocations.
Make sure that examples work properly!
.It Em DIAGNOSTICS
Documents error conditions.
In section 4 and 9 manuals, these are usually messages
printed by the kernel to the console and to the kernel log.
In section 1, 6, 7, and 8, these are usually messages
printed by userland programs to the standard error output.
.Pp
Historically, this section was used in place of
.Em EXIT STATUS
for manuals in sections 1, 6, and 8; however, this practise is
discouraged.
.It Em ERRORS
Documents
.Xr errno 2
settings in sections 2, 3, 4, and 9.
.It Em SEE ALSO
References other manuals with related topics.
This section should exist for most manuals.
.Pp
.D1 \&.BR bar \&( 1 \&),
.Pp
Cross-references should conventionally be ordered
first by section, then alphabetically.
.It Em STANDARDS
References any standards implemented or used, such as
.Pp
.D1 IEEE Std 1003.2 (\e(lqPOSIX.2\e(rq)
.Pp
If not adhering to any standards, the
.Em HISTORY
section should be used.
.It Em HISTORY
A brief history of the subject, including where support first appeared.
.It Em AUTHORS
Credits to the person or persons who wrote the code and/or documentation.
Authors should generally be noted by both name and email address.
.It Em CAVEATS
Common misuses and misunderstandings should be explained
in this section.
.It Em BUGS
Known bugs, limitations, and work-arounds should be described
in this section.
.It Em SECURITY CONSIDERATIONS
Documents any security precautions that operators should consider.
.El
.Sh MACRO OVERVIEW
This overview is sorted such that macros of similar purpose are listed
together, to help find the best macro for any given purpose.
Deprecated macros are not included in the overview, but can be found
in the alphabetical reference below.
.Ss Page header and footer meta-data
.Bl -column "PP, LP, P" description
.It Sx TH Ta set the title: Ar title section date Op Ar source Op Ar volume
.It Sx AT Ta display AT&T UNIX version in the page footer (<= 1 argument)
.It Sx UC Ta display BSD version in the page footer (<= 1 argument)
.El
.Ss Sections and paragraphs
.Bl -column "PP, LP, P" description
.It Sx SH Ta section header (one line)
.It Sx SS Ta subsection header (one line)
.It Sx PP , LP , P Ta start an undecorated paragraph (no arguments)
.It Sx RS , RE Ta reset the left margin: Op Ar width
.It Sx IP Ta indented paragraph: Op Ar head Op Ar width
.It Sx TP Ta tagged paragraph: Op Ar width
.It Sx HP Ta hanged paragraph: Op Ar width
.It Sx PD Ta set vertical paragraph distance: Op Ar height
.It Sx fi , nf Ta fill mode and no-fill mode (no arguments)
.It Sx in Ta additional indent: Op Ar width
.El
.Ss Physical markup
.Bl -column "PP, LP, P" description
.It Sx B Ta boldface font
.It Sx I Ta italic font
.It Sx R Ta roman (default) font
.It Sx SB Ta small boldface font
.It Sx SM Ta small roman font
.It Sx BI Ta alternate between boldface and italic fonts
.It Sx BR Ta alternate between boldface and roman fonts
.It Sx IB Ta alternate between italic and boldface fonts
.It Sx IR Ta alternate between italic and roman fonts
.It Sx RB Ta alternate between roman and boldface fonts
.It Sx RI Ta alternate between roman and italic fonts
.El
.Sh MACRO REFERENCE
This section is a canonical reference to all macros, arranged
alphabetically.
For the scoping of individual macros, see
.Sx MACRO SYNTAX .
.Ss \&AT
Sets the volume for the footer for compatibility with man pages from
.At
releases.
The optional arguments specify which release it is from.
.Ss \&B
Text is rendered in bold face.
.Pp
See also
.Sx \&I
and
.Sx \&R .
.Ss \&BI
Text is rendered alternately in bold face and italic.
Thus,
.Sq .BI this word and that
causes
.Sq this
and
.Sq and
to render in bold face, while
.Sq word
and
.Sq that
render in italics.
Whitespace between arguments is omitted in output.
.Pp
Examples:
.Pp
.Dl \&.BI bold italic bold italic
.Pp
The output of this example will be emboldened
.Dq bold
and italicised
.Dq italic ,
with spaces stripped between arguments.
.Pp
See also
.Sx \&IB ,
.Sx \&BR ,
.Sx \&RB ,
.Sx \&RI ,
and
.Sx \&IR .
.Ss \&BR
Text is rendered alternately in bold face and roman (the default font).
Whitespace between arguments is omitted in output.
.Pp
See
.Sx \&BI
for an equivalent example.
.Pp
See also
.Sx \&BI ,
.Sx \&IB ,
.Sx \&RB ,
.Sx \&RI ,
and
.Sx \&IR .
.Ss \&DT
Restore the default tabulator positions.
They are at intervals of 0.5 inches.
This has no effect unless the tabulator positions were changed with the
.Xr roff 7
.Ic \&ta
request.
.Ss \&EE
This is a non-standard GNU extension, included only for compatibility.
In
.Xr mandoc 1 ,
it does the same as
.Sx \&fi .
.Ss \&EX
This is a non-standard GNU extension, included only for compatibility.
In
.Xr mandoc 1 ,
it does the same as
.Sx \&nf .
.Ss \&HP
Begin a paragraph whose initial output line is left-justified, but
subsequent output lines are indented, with the following syntax:
.Bd -filled -offset indent
.Pf \. Sx \&HP
.Op Ar width
.Ed
.Pp
The
.Ar width
argument is a
.Xr roff 7
scaling width.
If specified, it's saved for later paragraph left-margins; if unspecified, the
saved or default width is used.
.Pp
See also
.Sx \&IP ,
.Sx \&LP ,
.Sx \&P ,
.Sx \&PP ,
and
.Sx \&TP .
.Ss \&I
Text is rendered in italics.
.Pp
See also
.Sx \&B
and
.Sx \&R .
.Ss \&IB
Text is rendered alternately in italics and bold face.
Whitespace between arguments is omitted in output.
.Pp
See
.Sx \&BI
for an equivalent example.
.Pp
See also
.Sx \&BI ,
.Sx \&BR ,
.Sx \&RB ,
.Sx \&RI ,
and
.Sx \&IR .
.Ss \&IP
Begin an indented paragraph with the following syntax:
.Bd -filled -offset indent
.Pf \. Sx \&IP
.Op Ar head Op Ar width
.Ed
.Pp
The
.Ar width
argument is a
.Xr roff 7
scaling width defining the left margin.
It's saved for later paragraph left-margins; if unspecified, the saved or
default width is used.
.Pp
The
.Ar head
argument is used as a leading term, flushed to the left margin.
This is useful for bulleted paragraphs and so on.
.Pp
See also
.Sx \&HP ,
.Sx \&LP ,
.Sx \&P ,
.Sx \&PP ,
and
.Sx \&TP .
.Ss \&IR
Text is rendered alternately in italics and roman (the default font).
Whitespace between arguments is omitted in output.
.Pp
See
.Sx \&BI
for an equivalent example.
.Pp
See also
.Sx \&BI ,
.Sx \&IB ,
.Sx \&BR ,
.Sx \&RB ,
and
.Sx \&RI .
.Ss \&LP
Begin an undecorated paragraph.
The scope of a paragraph is closed by a subsequent paragraph,
sub-section, section, or end of file.
The saved paragraph left-margin width is reset to the default.
.Pp
See also
.Sx \&HP ,
.Sx \&IP ,
.Sx \&P ,
.Sx \&PP ,
and
.Sx \&TP .
+.Ss \&ME
+End a mailto block.
+This is a non-standard GNU extension, included only for compatibility.
+See
+.Sx \&MT .
+.Ss \&MT
+Begin a mailto block.
+This is a non-standard GNU extension, included only for compatibility.
+It has the following syntax:
+.Bd -literal -offset indent
+.Pf \. Sx \&MT Ar address
+link description to be shown
+.Pf \. Sx ME
+.Ed
.Ss \&OP
Optional command-line argument.
This is a non-standard GNU extension, included only for compatibility.
It has the following syntax:
.Bd -filled -offset indent
.Pf \. Sx \&OP
.Ar key Op Ar value
.Ed
.Pp
The
.Ar key
is usually a command-line flag and
.Ar value
its argument.
.Ss \&P
Synonym for
.Sx \&LP .
.Pp
See also
.Sx \&HP ,
.Sx \&IP ,
.Sx \&LP ,
.Sx \&PP ,
and
.Sx \&TP .
.Ss \&PD
Specify the vertical space to be inserted before each new paragraph.
.br
The syntax is as follows:
.Bd -filled -offset indent
.Pf \. Sx \&PD
.Op Ar height
.Ed
.Pp
The
.Ar height
argument is a
.Xr roff 7
scaling width.
It defaults to
.Cm 1v .
If the unit is omitted,
.Cm v
is assumed.
.Pp
This macro affects the spacing before any subsequent instances of
.Sx \&HP ,
.Sx \&IP ,
.Sx \&LP ,
.Sx \&P ,
.Sx \&PP ,
.Sx \&SH ,
.Sx \&SS ,
and
.Sx \&TP .
.Ss \&PP
Synonym for
.Sx \&LP .
.Pp
See also
.Sx \&HP ,
.Sx \&IP ,
.Sx \&LP ,
.Sx \&P ,
and
.Sx \&TP .
.Ss \&R
Text is rendered in roman (the default font).
.Pp
See also
.Sx \&I
and
.Sx \&B .
.Ss \&RB
Text is rendered alternately in roman (the default font) and bold face.
Whitespace between arguments is omitted in output.
.Pp
See
.Sx \&BI
for an equivalent example.
.Pp
See also
.Sx \&BI ,
.Sx \&IB ,
.Sx \&BR ,
.Sx \&RI ,
and
.Sx \&IR .
.Ss \&RE
Explicitly close out the scope of a prior
.Sx \&RS .
The default left margin is restored to the state before that
.Sx \&RS
invocation.
.Pp
The syntax is as follows:
.Bd -filled -offset indent
.Pf \. Sx \&RE
.Op Ar level
.Ed
.Pp
Without an argument, the most recent
.Sx \&RS
block is closed out.
If
.Ar level
is 1, all open
.Sx \&RS
blocks are closed out.
Otherwise,
.Ar level No \(mi 1
nested
.Sx \&RS
blocks remain open.
.Ss \&RI
Text is rendered alternately in roman (the default font) and italics.
Whitespace between arguments is omitted in output.
.Pp
See
.Sx \&BI
for an equivalent example.
.Pp
See also
.Sx \&BI ,
.Sx \&IB ,
.Sx \&BR ,
.Sx \&RB ,
and
.Sx \&IR .
.Ss \&RS
Temporarily reset the default left margin.
This has the following syntax:
.Bd -filled -offset indent
.Pf \. Sx \&RS
.Op Ar width
.Ed
.Pp
The
.Ar width
argument is a
.Xr roff 7
scaling width.
If not specified, the saved or default width is used.
.Pp
See also
.Sx \&RE .
.Ss \&SB
Text is rendered in small size (one point smaller than the default font)
bold face.
.Ss \&SH
Begin a section.
The scope of a section is only closed by another section or the end of
file.
The paragraph left-margin width is reset to the default.
.Ss \&SM
Text is rendered in small size (one point smaller than the default
font).
.Ss \&SS
Begin a sub-section.
The scope of a sub-section is closed by a subsequent sub-section,
section, or end of file.
The paragraph left-margin width is reset to the default.
.Ss \&TH
Sets the title of the manual page for use in the page header
and footer with the following syntax:
.Bd -filled -offset indent
.Pf \. Sx \&TH
.Ar title section date
.Op Ar source Op Ar volume
.Ed
.Pp
Conventionally, the document
.Ar title
is given in all caps.
The recommended
.Ar date
format is
.Sy YYYY-MM-DD
as specified in the ISO-8601 standard;
if the argument does not conform, it is printed verbatim.
If the
.Ar date
is empty or not specified, the current date is used.
The optional
.Ar source
string specifies the organisation providing the utility.
When unspecified,
.Xr mandoc 1
uses its
.Fl Ios
argument.
The
.Ar volume
string replaces the default rendered volume, which is dictated by the
manual section.
.Pp
Examples:
.Pp
.Dl \&.TH CVS 5 "1992-02-12" GNU
.Ss \&TP
Begin a paragraph where the head, if exceeding the indentation width, is
followed by a newline; if not, the body follows on the same line after a
buffer to the indentation width.
Subsequent output lines are indented.
The syntax is as follows:
.Bd -filled -offset indent
.Pf \. Sx \&TP
.Op Ar width
.Ed
.Pp
The
.Ar width
argument is a
.Xr roff 7
scaling width.
If specified, it's saved for later paragraph left-margins; if
unspecified, the saved or default width is used.
.Pp
See also
.Sx \&HP ,
.Sx \&IP ,
.Sx \&LP ,
.Sx \&P ,
and
.Sx \&PP .
.Ss \&UC
Sets the volume for the footer for compatibility with man pages from
.Bx
releases.
The optional first argument specifies which release it is from.
.Ss \&UE
End a uniform resource identifier block.
This is a non-standard GNU extension, included only for compatibility.
See
.Sx \&UE .
.Ss \&UR
Begin a uniform resource identifier block.
This is a non-standard GNU extension, included only for compatibility.
It has the following syntax:
.Bd -literal -offset indent
.Pf \. Sx \&UR Ar uri
link description to be shown
.Pf \. Sx UE
.Ed
.Ss \&fi
End literal mode begun by
.Sx \&nf .
.Ss \&in
Indent relative to the current indentation:
.Pp
.D1 Pf \. Sx \&in Op Ar width
.Pp
If
.Ar width
is signed, the new offset is relative.
Otherwise, it is absolute.
This value is reset upon the next paragraph, section, or sub-section.
.Ss \&nf
Begin literal mode: all subsequent free-form lines have their end of
line boundaries preserved.
May be ended by
.Sx \&fi .
Literal mode is implicitly ended by
.Sx \&SH
or
.Sx \&SS .
.Sh MACRO SYNTAX
The
.Nm
macros are classified by scope: line scope or block scope.
Line macros are only scoped to the current line (and, in some
situations, the subsequent line).
Block macros are scoped to the current line and subsequent lines until
closed by another block macro.
.Ss Line Macros
Line macros are generally scoped to the current line, with the body
consisting of zero or more arguments.
If a macro is scoped to the next line and the line arguments are empty,
the next line, which must be text, is used instead.
Thus:
.Bd -literal -offset indent
\&.I
foo
.Ed
.Pp
is equivalent to
.Sq \&.I foo .
If next-line macros are invoked consecutively, only the last is used.
If a next-line macro is followed by a non-next-line macro, an error is
raised.
.Pp
The syntax is as follows:
.Bd -literal -offset indent
\&.YO \(lBbody...\(rB
\(lBbody...\(rB
.Ed
.Bl -column "MacroX" "ArgumentsX" "ScopeXXXXX" "CompatX" -offset indent
.It Em Macro Ta Em Arguments Ta Em Scope Ta Em Notes
.It Sx \&AT Ta <=1 Ta current Ta \&
.It Sx \&B Ta n Ta next-line Ta \&
.It Sx \&BI Ta n Ta current Ta \&
.It Sx \&BR Ta n Ta current Ta \&
.It Sx \&DT Ta 0 Ta current Ta \&
.It Sx \&EE Ta 0 Ta current Ta compat
.It Sx \&EX Ta 0 Ta current Ta compat
.It Sx \&I Ta n Ta next-line Ta \&
.It Sx \&IB Ta n Ta current Ta \&
.It Sx \&IR Ta n Ta current Ta \&
.It Sx \&OP Ta 0, 1 Ta current Ta compat
.It Sx \&PD Ta 1 Ta current Ta \&
.It Sx \&R Ta n Ta next-line Ta \&
.It Sx \&RB Ta n Ta current Ta \&
.It Sx \&RI Ta n Ta current Ta \&
.It Sx \&SB Ta n Ta next-line Ta \&
.It Sx \&SM Ta n Ta next-line Ta \&
.It Sx \&TH Ta >1, <6 Ta current Ta \&
.It Sx \&UC Ta <=1 Ta current Ta \&
.It Sx \&fi Ta 0 Ta current Ta compat
.It Sx \&in Ta 1 Ta current Ta compat
.It Sx \&nf Ta 0 Ta current Ta compat
.El
.Pp
Macros marked as
.Qq compat
are included for compatibility with the significant corpus of existing
manuals that mix dialects of roff.
These macros should not be used for portable
.Nm
manuals.
.Ss Block Macros
Block macros comprise a head and body.
As with in-line macros, the head is scoped to the current line and, in
one circumstance, the next line (the next-line stipulations as in
.Sx Line Macros
apply here as well).
.Pp
The syntax is as follows:
.Bd -literal -offset indent
\&.YO \(lBhead...\(rB
\(lBhead...\(rB
\(lBbody...\(rB
.Ed
.Pp
The closure of body scope may be to the section, where a macro is closed
by
.Sx \&SH ;
sub-section, closed by a section or
.Sx \&SS ;
part, closed by a section, sub-section, or
.Sx \&RE ;
or paragraph, closed by a section, sub-section, part,
.Sx \&HP ,
.Sx \&IP ,
.Sx \&LP ,
.Sx \&P ,
.Sx \&PP ,
or
.Sx \&TP .
No closure refers to an explicit block closing macro.
.Pp
As a rule, block macros may not be nested; thus, calling a block macro
while another block macro scope is open, and the open scope is not
implicitly closed, is syntactically incorrect.
.Bl -column "MacroX" "ArgumentsX" "Head ScopeX" "sub-sectionX" "compatX" -offset indent
.It Em Macro Ta Em Arguments Ta Em Head Scope Ta Em Body Scope Ta Em Notes
.It Sx \&HP Ta <2 Ta current Ta paragraph Ta \&
.It Sx \&IP Ta <3 Ta current Ta paragraph Ta \&
.It Sx \&LP Ta 0 Ta current Ta paragraph Ta \&
.It Sx \&P Ta 0 Ta current Ta paragraph Ta \&
.It Sx \&PP Ta 0 Ta current Ta paragraph Ta \&
.It Sx \&RE Ta 0 Ta current Ta none Ta compat
.It Sx \&RS Ta 1 Ta current Ta part Ta compat
.It Sx \&SH Ta >0 Ta next-line Ta section Ta \&
.It Sx \&SS Ta >0 Ta next-line Ta sub-section Ta \&
.It Sx \&TP Ta n Ta next-line Ta paragraph Ta \&
.It Sx \&UE Ta 0 Ta current Ta none Ta compat
.It Sx \&UR Ta 1 Ta current Ta part Ta compat
.El
.Pp
Macros marked
.Qq compat
are as mentioned in
.Sx Line Macros .
.Pp
If a block macro is next-line scoped, it may only be followed by in-line
macros for decorating text.
.Ss Font handling
In
.Nm
documents, both
.Sx Physical markup
macros and
.Xr roff 7
.Ql \ef
font escape sequences can be used to choose fonts.
In text lines, the effect of manual font selection by escape sequences
only lasts until the next macro invocation; in macro lines, it only lasts
until the end of the macro scope.
Note that macros like
.Sx \&BR
open and close a font scope for each argument.
.Sh SEE ALSO
.Xr man 1 ,
.Xr mandoc 1 ,
.Xr eqn 7 ,
.Xr mandoc_char 7 ,
.Xr mdoc 7 ,
.Xr roff 7 ,
.Xr tbl 7
.Sh HISTORY
The
.Nm
language first appeared as a macro package for the roff typesetting
system in
.At v7 .
It was later rewritten by James Clark as a macro package for groff.
Eric S. Raymond wrote the extended
.Nm
macros for groff in 2007.
The stand-alone implementation that is part of the
.Xr mandoc 1
utility written by Kristaps Dzonsons appeared in
.Ox 4.6 .
.Sh AUTHORS
This
.Nm
reference was written by
.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv .
.Sh CAVEATS
Do not use this language.
Use
.Xr mdoc 7 ,
instead.
Index: vendor/mdocml/dist/man.c
===================================================================
--- vendor/mdocml/dist/man.c (revision 321806)
+++ vendor/mdocml/dist/man.c (revision 321807)
@@ -1,361 +1,383 @@
-/* $Id: man.c,v 1.174 2017/06/03 15:55:24 schwarze Exp $ */
+/* $Id: man.c,v 1.176 2017/06/28 12:52:45 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons
* Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze
* Copyright (c) 2011 Joerg Sonnenberger
*
* 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
#include
#include
#include
#include
#include
#include
#include "mandoc_aux.h"
#include "mandoc.h"
#include "roff.h"
#include "man.h"
#include "libmandoc.h"
#include "roff_int.h"
#include "libman.h"
static void man_descope(struct roff_man *, int, int);
static int man_ptext(struct roff_man *, int, char *, int);
static int man_pmacro(struct roff_man *, int, char *, int);
int
man_parseln(struct roff_man *man, int ln, char *buf, int offs)
{
if (man->last->type != ROFFT_EQN || ln > man->last->line)
man->flags |= MAN_NEWLINE;
return roff_getcontrol(man->roff, buf, &offs) ?
man_pmacro(man, ln, buf, offs) :
man_ptext(man, ln, buf, offs);
}
static void
man_descope(struct roff_man *man, int line, int offs)
{
/*
* 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).
*/
if (man->flags & MAN_ELINE) {
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);
}
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. */
if (man->flags & MAN_LITERAL) {
roff_word_alloc(man, line, offs, buf + offs);
man_descope(man, line, offs);
return 1;
}
for (i = offs; buf[i] == ' '; i++)
/* Skip leading whitespace. */ ;
/*
- * Blank lines are ignored in next line scope and right
- * after headings but add a single vertical space elsewhere.
+ * Blank lines are ignored in next line scope
+ * and right after headings and cancel preceding \c,
+ * but add a single vertical space elsewhere.
*/
if (buf[i] == '\0') {
- if (man->flags & (MAN_ELINE | MAN_BLINE))
+ if (man->flags & (MAN_ELINE | MAN_BLINE)) {
mandoc_msg(MANDOCERR_BLK_BLANK, man->parse,
line, 0, NULL);
- else if (man->last->tok != MAN_SH &&
- man->last->tok != MAN_SS) {
- roff_elem_alloc(man, line, offs, ROFF_sp);
- man->next = ROFF_NEXT_SIBLING;
+ 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;
+ *ep = '\0';
+ return 1;
+ default:
+ break;
+ }
+ roff_elem_alloc(man, line, offs, ROFF_sp);
+ man->next = ROFF_NEXT_SIBLING;
return 1;
}
/*
* Warn if the last un-escaped character is whitespace. Then
* strip away the remaining spaces (tabs stay!).
*/
i = (int)strlen(buf);
assert(i);
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);
for (--i; i && ' ' == buf[i]; i--)
/* Spin back to non-space. */ ;
/* Jump ahead of escaped whitespace. */
i += '\\' == buf[i] ? 2 : 1;
buf[i] = '\0';
}
roff_word_alloc(man, line, offs, buf + offs);
/*
* End-of-sentence check. If the last character is an unescaped
* EOS character, then flag the node as being the end of a
* sentence. The front-end will know how to interpret this.
*/
assert(i);
if (mandoc_eos(buf, (size_t)i))
man->last->flags |= NODE_EOS;
man_descope(man, line, offs);
return 1;
}
static int
man_pmacro(struct roff_man *man, int ln, char *buf, int offs)
{
struct roff_node *n;
const char *cp;
size_t sz;
enum roff_tok tok;
int ppos;
int bline;
/* Determine the line macro. */
ppos = offs;
tok = TOKEN_NONE;
for (sz = 0; sz < 4 && strchr(" \t\\", buf[offs]) == NULL; sz++)
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);
return 1;
}
/* Skip a leading escape sequence or tab. */
switch (buf[offs]) {
case '\\':
cp = buf + offs + 1;
mandoc_escape(&cp, NULL, NULL);
offs = cp - buf;
break;
case '\t':
offs++;
break;
default:
break;
}
/* Jump to the next non-whitespace word. */
while (buf[offs] == ' ')
offs++;
/*
* Trailing whitespace. Note that tabs are allowed to be passed
* into the parser as "text", so we only warn about spaces here.
*/
if (buf[offs] == '\0' && buf[offs - 1] == ' ')
mandoc_msg(MANDOCERR_SPACE_EOL, man->parse,
ln, offs - 1, NULL);
/*
* Some macros break next-line scopes; otherwise, remember
* whether we are in next-line scope for a block head.
*/
man_breakscope(man, tok);
bline = man->flags & MAN_BLINE;
/*
* If the line in next-line scope ends with \c, keep the
* next-line scope open for the subsequent input line.
* That is not at all portable, only groff >= 1.22.4
* does it, but *if* this weird idiom occurs in a manual
* 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;
}
/* Call to handler... */
assert(man_macros[tok].fp);
(*man_macros[tok].fp)(man, tok, ln, ppos, &offs, buf);
/* In quick mode (for mandocdb), abort after the NAME section. */
if (man->quick && tok == MAN_SH) {
n = man->last;
if (n->type == ROFFT_BODY &&
strcmp(n->prev->child->string, "NAME"))
return 2;
}
/*
* If we are in a next-line scope for a block head,
* close it out now and switch to the body,
* unless the next-line scope is allowed to continue.
*/
if ( ! bline || man->flags & MAN_ELINE ||
man_macros[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);
return 1;
}
void
man_breakscope(struct roff_man *man, int tok)
{
struct roff_node *n;
/*
* An element next line scope is open,
* and the new macro is not allowed inside elements.
* Delete the element that is being broken.
*/
if (man->flags & MAN_ELINE && (tok < MAN_TH ||
! (man_macros[tok].flags & MAN_NSCOPED))) {
n = man->last;
- assert(n->type != ROFFT_TEXT);
- if (man_macros[n->tok].flags & MAN_NSCOPED)
+ if (n->type == ROFFT_TEXT)
n = n->parent;
+ if (n->tok < MAN_TH ||
+ man_macros[n->tok].flags & 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]);
roff_node_delete(man, n);
man->flags &= ~MAN_ELINE;
}
/*
* Weird special case:
* Switching fill mode closes section headers.
*/
if (man->flags & MAN_BLINE &&
(tok == MAN_nf || tok == MAN_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;
}
/*
* A block header next line scope is open,
* and the new macro is not allowed inside block headers.
* Delete the block that is being broken.
*/
if (man->flags & MAN_BLINE && (tok < MAN_TH ||
man_macros[tok].flags & MAN_BSCOPE)) {
n = man->last;
if (n->type == ROFFT_TEXT)
n = n->parent;
- if ( ! (man_macros[n->tok].flags & MAN_BSCOPE))
+ if (n->tok < MAN_TH ||
+ (man_macros[n->tok].flags & MAN_BSCOPE) == 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);
mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse,
n->line, n->pos, "%s breaks %s",
roff_name[tok], roff_name[n->tok]);
roff_node_delete(man, n);
man->flags &= ~MAN_BLINE;
}
}
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;
}
Index: vendor/mdocml/dist/man.options.1
===================================================================
--- vendor/mdocml/dist/man.options.1 (revision 321806)
+++ vendor/mdocml/dist/man.options.1 (revision 321807)
@@ -1,1326 +1,1332 @@
-.\" $Id: man.options.1,v 1.6 2017/02/02 20:10:51 schwarze Exp $
+.\" $Id: man.options.1,v 1.7 2017/07/04 23:40:01 schwarze Exp $
.\"
.\" Copyright (c) 2017 Ingo Schwarze
.\"
.\" 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.
.\"
-.Dd $Mdocdate: February 2 2017 $
+.Dd $Mdocdate: July 4 2017 $
.Dt MAN.OPTIONS 1
.Os
.Sh NAME
.Nm man.options
.Nd assignment of option letters in manual page utilities
.\"
.\" Sources that occur repeatedly.
.\" Only use if the precise implementation time is unknown.
.\"
.de PWB
.No PWB/UNIX 1.0 Pq July 1, 1977 \\$1
..
.de At7
.At v7 Pq January 1979 \\$1
..
.de At3
.At III Pq June 1980 \\$1
..
.de Bx4
.Bx 4 Pq November 16, 1980 \\$1
..
.de At5
.At V Pq January 1983 \\$1
..
.de Bx43
.Bx 4.3 Pq June 1986 \\$1
..
.\" option was present in groff-1.01 as contained in 4.3BSD-Net/2
.\" and no mention of it could be found in the ChangeLog,
.\" so it's probably older than groff-0.4, where the log started
.de g04
.No probably before groff-0.4 Pq before July 14, 1990 \\$1
..
.de Eaton
.No Eaton Pq before July 7, 1993; 1990/91? \\$1
..
.\" man-1.5e was released on July 11, 1998.
.de man15e
.No man-1.5e Pq not before 1993, not after 1998 \\$1
..
.\" man-1.5g was released on April 7, 1999.
.de man15g
.No man-1.5g Pq not before 1993, not after 1999 \\$1
..
.\" code first seen in the initial import of man-db into CVS ,
.\" which was more or less debian man-db-2.3.17
.\" Colin Watson's first release was 2.3.18 on May 14, 2001
.\" no clue about it found in ChangeLog-2013,
.\" so it was probably already present before man-db-2.2a4
.de dbI
.No man-db probably before 2.2a4 Pq before Nov 8, 1994 \\$1
..
.\"
.\" --------------------------------------------------------------------
.\"
.Sh DESCRIPTION
This manual page lists option letters used in many different versions
of the
.Nm man ,
.Nm apropos ,
.Nm whatis ,
.Nm mandoc ,
.Nm makewhatis ,
.Nm mandb ,
.Nm makemandb ,
.Nm catman ,
and
.Nm manpath
utilities.
Option letters used by
.Nm groff ,
.Nm nroff ,
.Nm troff ,
and
.Nm roff
are also included because beginning with
.At v7 ,
many versions of
.Xr man 1
pass on unrecognized options to these programs.
.Pp
For each option letter, information is first grouped into paragraphs,
each paragraph describing similar functionality and starting with
one line briefly summarizing that functionality.
.Pp
For each program using the letter for that functionality, one line
is provided, giving the name of the program, a colon, the system
where this letter first appeared for this functionality in this
program, optionally a comma and a list of other system versions
introducing the same, a semicolon, and a list of current systems
supporting it.
If a system appears before the semicolon, it is not repeated
afterwards.
.Pp
Entries are sorted by historical precedence, except that obsolete
options are moved to the end.
Dates are commit dates where known, and release dates otherwise.
.Bl -tag -width 3n
.It Fl a
display all matching manual pages
.br
.Nm man :
.Bx 4.3 Tahoe Pq June 1988 ,
.Eaton ;
.Ox , Fx , Nx , No man-db , man-1.6 , illumos , Solaris 9-11
.br
.Nm apropos , whatis , mandoc :
.Ox 5.7 Pq August 27, 2014
.Pp
only display items that match all keywords
.br
.Nm apropos :
.No man-db Pq Aug 29, 2007
.Pp
use all directories and files for
.Xr mandoc.db 5
.br
.Nm makewhatis :
.Ox 5.6 Pq April 18, 2014
.Pp
.Bq superseded by Fl T Cm ascii
ASCII output mode
.br
.Nm troff :
.At7
.br
.Nm groff :
.g04
.It Fl B
use specified browser
.br
.Nm man :
.No man-1.6 Pq June 24, 2005
.It Fl b
print a backtrace with each warning or error message
.br
.Nm groff :
.g04
.Pp
.Bq obsolete hardware
report whether the phototypesetter is busy
.br
.Nm troff :
.At7
.It Fl C
alternate configuration file
.br
.Nm apropos , whatis :
.Bx 4.4 Lite1 Pq April 22, 1994 ,
.No man-db Pq Feb 22, 2003 ;
.Ox , Nx
.br
.Nm man :
.Nx 1.0 Pq Oct 26, 1994 ,
.man15e ;
.Ox
.br
.Nm mandb , catman , manpath :
.No man-db Pq Feb 22, 2003
.br
.Nm makemandb :
.Nx Pq Feb 7, 2012
.br
.Nm makewhatis :
.Ox 5.6 Pq April 18, 2014
.br
.Nm mandoc :
.Ox 5.7 Pq August 27, 2014
.Pp
.Bq obsolete
enable compatibility mode
.br
.Nm groff :
.No before groff-0.5 Pq before August 3, 1990
.It Fl c
do not use a pager
.br
.Nm man :
.Bx 4.3 Reno Pq June 1990 ;
.Ox , Nx
.br
.Nm apropos , whatis , mandoc :
.Ox 5.7 Pq August 27, 2014
.Pp
process given catpath
.br
.Nm makewhatis :
.Pq not before 1992, not after 1995
.Pp
recreate databases from scratch
.br
.Nm mandb :
.dbI
.Pp
produce a catpath as opposed to a manpath
.br
.Nm manpath :
.dbI
.Pp
internal option for use by
.Xr catman 1
.br
.Nm man :
.dbI
.Pp
reformat source page even if cat page exists
.br
.Nm man :
.man15e
.Pp
disable terminal color output in
.Xr grotty 1
.br
.Nm groff :
.No groff-1.18.0 Pq Oct 4, 2001
.Pp
recreate nroff versions from SGML sources
.br
.Nm catman :
.No Solaris 9-11
.Pp
.Bq obsolete
postprocess with
.Xr col 1
.br
.Nm man :
.At3 ,
.At5
.It Fl D
reset whatever was set with
.Ev MANOPT
.br
.Nm man :
.dbI
.Pp
print debugging info in addition to manual page
.br
.Nm man :
.man15e
.Pp
set default input encoding for
.Xr preconv 1
.br
.Nm groff :
.No groff-1.20 Pq August 20, 2008
.Pp
display all files added to
.Xr mandoc.db 5
.br
.Nm makewhatis :
.Ox 5.6 Pq April 18, 2014
.It Fl d
define a user-defined string
.br
.Nm groff :
.g04
.Pp
print debugging information
.br
.Nm man :
.Eaton ;
.Fx , No man-db , man-1.6 , illumos , Solaris 9-11
.br
.Nm manpath :
.Eaton ;
.Fx , No man-db
.br
.Nm apropos , whatis :
.dbI ;
.Fx
.br
.Nm mandb , catman :
.dbI
.Pp
remove and re-add a file to
.Xr mandoc.db 5
.br
.Nm makewhatis :
.Ox 2.7 Pq Feb 3, 2000
.Pp
.Bq superseded by Fl l
interpret arguments as file names
.br
.Nm man :
.At3 ,
.At5
.It Fl E
inhibit all error messages
.br
.Nm groff :
.g04
.Pp
select output encoding
.br
.Nm man :
.No man-db Pq Dec 23, 2001
.It Fl e
preprocess with
.Xr eqn 7
.br
.Nm man :
.At7
.br
.Nm groff :
.g04
.Pp
adjust text to left and right margins
.br
.Nm nroff :
.At7
.Pp
use exact matching
.br
.Nm apropos , whatis :
.dbI
.Pp
restrict search by section extension
.br
.Nm man :
.No man-db-2.3.5 Pq April 21, 1995
.It Fl F
use alternate font directory
.br
.Nm troff :
.Bx 4.2 Pq September 1983
.br
.Nm groff :
.g04
.Pp
preformat only, do not display
.br
.Nm man :
.No man-1.5g Pq April 7, 1999
.Pp
force searching dirs, do not use index (default)
.br
.Nm man :
.No illumos , Solaris 9-11
.It Fl f
.Xr whatis 1
mode
.br
.Nm man :
.Bx4 ,
.Eaton ;
.Ox , Fx , No man-db , man-1.6
.br
.Nm apropos , whatis :
.No man-db Pq Dec 2, 2010 ,
.Ox 5.7 Pq August 27, 2014
.br
.Nm mandoc :
.Ox 5.7 Pq August 27, 2014
.Pp
set the default font family
.br
.Nm groff :
.g04
.Pp
force formatting even if cat page is newer
.br
.Nm catman :
.Fx Pq March 15, 1995
.Pp
update only the entries for the given file
.br
.Nm mandb :
.No man-db Pq Feb 21, 2003
.Pp
force rebuilding the database from scratch
.br
.Nm makemandb :
.Nx Pq Feb 7, 2012
.Pp
locate manual page related to given file name
.br
.Nm man :
.No illumos , Solaris 9-11
.Pp
.Bq obsolete hardware
do not feed out paper nor stop phototypesetter
.br
.Nm troff :
.At7
.It Fl G
preprocess with
.Xr grap 1
.br
.Nm groff :
.No groff-1.16 Pq May 1, 2000
.It Fl g
produce a global manpath
.br
.Nm manpath :
.No man-db-2.2a7 Pq Nov 16, 1994
.Pp
preprocess with
.Xr grn 1
.br
.Nm groff :
.No groff-1.16 Pq Feb 20, 2000
.Pp
.Bq obsolete hardware
output to a GCOS phototypesetter
.br
.Nm troff :
.At7
.Pp
.Bq obsolete hardware
output to a DASI 300 terminal in 12-pitch mode
.br
.Nm man :
.PWB
.It Fl H
read hyphenation patterns from the given file
.br
.Nm groff :
.g04
.Pp
produce HTML output
.br
.Nm man :
.No man-db-1.3.12 to 1.3.17 Pq not before 1996, not after 2001
.Pp
use program to render HTML files as text
.br
.Nm man :
.No man-1.6 Pq June 24, 2005
.It Fl h
print a help message and exit
.br
.Nm groff :
.g04
.br
.Nm man :
.Eaton ;
.Fx , No man-db , man-1.6
.br
.Nm manpath :
.Eaton ;
.Fx , No man-db
.br
.Nm apropos , whatis , mandb , catman :
.dbI
.Pp
display the SYNOPSIS lines only
.br
.Nm man :
.Bx 4.3 Net/2 Pq August 20, 1991 ;
.Ox , Nx
.br
.Nm apropos , whatis , mandoc :
.Ox 5.7 Pq Sep 3, 2014
.Pp
turn on HTML formatting
.br
.Nm apropos :
.Nx Pq Apr 2, 2013
.Pp
.Bq obsolete
replace spaces by tabs in the output
.br
.Nm roff , nroff :
.At7
.It Fl I
input file search path for
.Xr soelim 1
.br
.Nm groff :
.No groff-1.12 Pq Sep 11, 1999
.Pp
respect case when matching manual page names
.br
.Nm man , catman :
.No man-db Pq Apr 21, 2002
.Pp
input options, in particular default operating system name
.br
.Nm mandoc :
.Ox 5.2 Pq May 24, 2012
.br
.Nm man , apropos , whatis :
.Ox 5.7 Pq August 27, 2014
.It Fl i
read standard input after the input files are exhausted
.br
.Nm nroff , troff :
.At7
.br
.Nm groff :
.g04
.Pp
ignore case when matching manual page names
.br
.Nm man , catman :
.No man-db Pq Apr 21, 2002
.Pp
turn on terminal escape code formatting
.br
.Nm apropos :
.Nx Pq March 29, 2013
.It Fl J
preprocess with
.Xr gideal 1
.br
.Nm groff :
.No groff-1.22.3 Pq June 17, 2014
.It Fl j
preprocess with
.Xr chem 1
.br
.Nm groff :
.No groff-1.22 Pq Jan 22, 2011
.It Fl K
source code full text search
.br
.Nm man :
.man15e ,
.No man-db Pq June 28, 2009 ;
.No Solaris 11
.Pp
input encoding
.br
.Nm groff :
.No groff-1.20 Pq Dec 31, 2005
.br
.Nm man , apropos , whatis , mandoc :
.Ox 5.7 Pq Oct 30, 2014
.It Fl k
.Xr apropos 1
mode
.br
.Nm man :
.Bx4 ,
.Eaton ;
.No POSIX , Ox , Fx , Nx , No man-db , man-1.6 , illumos , Solaris 9-11
.br
.Nm apropos , whatis , mandoc :
.Ox 5.7 Pq August 27, 2014
.Pp
ignore formatting errors
.br
.Nm catman :
.Nx Pq April 26, 1994
.Pp
preprocess with
.Xr preconv 1
.br
.Nm groff :
.No groff-1.20 Pq Dec 31, 2005
.Pp
.Bq obsolete hardware
display on a Tektronix 4014 terminal
.br
.Nm man :
.At7
.It Fl L
pass argument to the spooler
.br
.Nm groff :
.No groff-0.6 Pq Sep 14, 1990
.Pp
use alternate
.Xr locale 1
.br
.Nm man , apropos , whatis :
.No before man-db-2.2a13 Pq before Dec 15, 1994
.Pp
print list of locales
.br
.Nm manpath :
.Fx Pq Nov 23, 1999
.Pp
use
.Xr locale 1
specified in the environment
.br
.Nm catman :
.Fx Pq May 18, 2002
.It Fl l
spool the output
.br
.Nm groff :
.g04
.Pp
interpret arguments as file names
.br
.Nm man :
.No before man-2.2a7 Pq before Nov 16, 1994 ,
.Ox 5.7 Pq Aug 30, 2014
.br
.Nm apropos , whatis , mandoc :
.Ox 5.7 Pq Aug 30, 2014
.Pp
do not trim output to the terminal width
.br
.Nm apropos , whatis :
.No man-db Pq Aug 19, 2007
.Pp
only parse NAME sections
.br
.Nm makemandb :
.Nx Pq Feb 7, 2012
.Pp
legacy mode: search Nm,Nd, no context or formatting
.br
.Nm apropos :
.Nx Pq March 29, 2013
.Pp
list all manual pages matching name within the search path
.br
.Nm man :
.No illumos , Solaris 9-11
.It Fl M
override manual page search path
.br
.Nm man :
.Bx43 ,
.Eaton ;
.Ox , Fx , Nx , No man-db , man-1.6 , illumos , Solaris 9-11
.br
.Nm apropos , whatis :
.Bx43 ,
.No before man-db-2.2a14 Pq before Dec 16, 1994 ;
.Ox , No illumos
.br
.Nm catman :
.dbI ;
.Nx Pq July 27, 1993 ,
.No Solaris 9-11
.br
.Nm mandoc :
.Ox 5.7 Pq August 27, 2014
.Pp
prepend to macro file search path
.br
.Nm groff :
.g04
.Pp
do not show the context of the match
.br
.Nm apropos :
.Nx Pq May 22, 2016
.It Fl m
specify input macro language
.br
.Nm nroff , troff :
.At7
.br
.Nm groff :
.g04
.br
.Nm mandoc :
.Ox 4.8 Pq April 6, 2009
.Pp
augment manual page search path
.br
.Nm man , apropos , whatis :
.Bx 4.3 Reno Pq June 1990 ;
.Ox , Nx
.br
.Nm catman :
.Nx Pq Apr 4, 1999
.br
.Nm mandoc :
.Ox 5.7 Pq August 27, 2014
.Pp
override operating system
.br
.Nm man :
.Eaton ;
.No man-db , man-1.6
.br
.Nm apropos , whatis , manpath :
.dbI
.Pp
override architecture
.br
.Nm man :
.Fx Pq Jan 11, 2002
.Pp
show the context of the match
.br
.Nm apropos :
.Nx Pq May 22, 2016
.It Fl N
do not allow newlines between
.Xr eqn 7
delimiters
.br
.Nm groff :
.No groff-1.01 Pq Feb 21, 1991
.It Fl n
specify a page number for the first page
.br
.Nm troff :
.At7
.br
.Nm groff :
.g04
.Pp
.Xr nroff 1
output mode
.br
.Nm man :
.At7
.Pp
do not create the
.Xr whatis 1
database
.br
.Nm catman :
.Nx Pq July 27, 1993
.Pp
print commands instead of executing them
.br
.Nm catman :
.Fx Pq May 18, 2002 ,
.No Solaris 9-11
.Pp
limit the number of results
.br
.Nm apropos :
.Nx Pq Feb 7, 2012
.Pp
dry run simulating
.Xr mandoc.db 5
creation
.br
.Nm makewhatis :
.Ox 5.6 Pq April 18, 2014
.It Fl O
output options
.br
.Nm mandoc :
.Ox 4.8 Pq Oct 27, 2009
.br
.Nm man , apropos , whatis :
.Ox 5.7 Pq August 27, 2014
.It Fl o
select pages by numbers
.br
.Nm nroff , troff :
.At7
.br
.Nm groff :
.g04
.Pp
force use of non-localized manual pages
.br
.Nm man :
.Fx Pq June 7, 1999
.Pp
optimize index for speed and disk space
.br
.Nm makemandb :
.Nx Pq Feb 7, 2012
.It Fl P
pass argument to postprocessor
.br
.Nm groff :
.No groff-0.6 Pq Sep 14, 1990
.Pp
use specified pager
.br
.Nm man :
.Eaton ;
.Fx , No man-db , man-1.6
.Pp
turn on pager formatting
.br
.Nm apropos :
.Nx Pq Apr 2, 2013
.It Fl p
preprocess with
.Xr pic 1
.br
.Nm groff :
.g04
.Pp
use the given list of preprocessors
.br
.Nm man :
.Eaton ;
.Fx , No man-db , man-1.6
.Pp
dry run, display commands instead of executing them
.br
.Nm catman :
.Nx Pq July 27, 1993 ,
.Fx Pq March 15, 1995 to May 18, 2002 ,
.No Solaris 9-11
.Pp
print warnings when building
.Xr mandoc.db 5
.br
.Nm makewhatis :
.Ox 2.7 Pq April 23, 2000
.Pp
do not look for deleted manual pages
.br
.Nm mandb :
.No man-db Pq June 28, 2001
.Pp
print the search path for manual pages
.br
.Nm man :
.Nx Pq June 14 , 2011
.Pp
turn on pager formatting and pipe through pager
.br
.Nm apropos :
.Nx Pq Feb 7, 2012
.Pp
.Bq obsolete hardware
set phototypesetter point size
.br
.Nm troff :
.At7
.It Fl Q
print only fatal error messages
.br
.Nm makemandb :
.Nx Pq Aug 29, 2012
.Pp
quick mode of
.Xr mandoc.db 5
creation
.br
.Nm makewhatis :
.Ox 5.6 Pq April 18, 2014
.It Fl q
invoke the simultaneous input-output mode of the .rd request
.br
.Nm nroff , troff :
.At7
.Pp
issue no warnings
.br
.Nm manpath :
.Eaton ;
.Fx , No man-db
.br
.Nm mandb :
.dbI
.Pp
print only warnings and errors, no status updates
.br
.Nm makemandb :
.Nx Pq Aug 29, 2012
.It Fl R
postprocess with
.Xr refer 1
.br
.Nm groff :
.No groff-1.02 Pq June 2, 1991
.Pp
recode to the specified encoding
.br
.Nm man :
.No man-db Pq Dec 31, 2007
.It Fl r
set number register
.br
.Nm nroff , troff :
.At7
.br
.Nm groff :
.g04
.Pp
scan for and remove junk files
.br
.Nm catman :
.Fx Pq March 31, 1995
.Pp
set
.Xr less 1
prompt
.br
.Nm man :
.No man-db-2.3.5 Pq April 21, 1995
.Pp
use regular expression matching
.br
.Nm apropos , whatis :
.No man-db-2.3.5 Pq April 21, 1995
.Pp
turn off formatting
.br
.Nm apropos :
.Nx Pq Feb 10, 2013
.Pp
check for formatting errors, do not display
.br
.Nm man :
.No illumos , Solaris 9-11
.It Fl S
manual section search list
.br
.Nm man :
.Eaton ;
.Fx , No man-db , man-1.6
.Pp
safer mode
.br
.Nm groff :
.No groff-1.10 Pq May 17, 1994
.Pp
restrict architecture
.br
.Nm man :
.Ox 2.3 Pq March 9, 1998 ,
.Nx Pq May 27, 2000
.br
.Nm apropos :
.Ox 4.5 Pq Dec 24, 2008 ,
.Nx Pq May 8, 2009
.br
.Nm whatis :
.Ox 5.6 Pq April 18, 2014
.br
.Nm mandoc :
.Ox 5.7 Pq August 27, 2014
.It Fl s
preprocess with
.Xr soelim 1
.br
.Nm groff :
.g04
.Pp
silent mode, do not echo commands
.br
.Nm catman :
.Nx Pq April 26, 1994
.Pp
restrict section
.br
.Nm makewhatis :
.man15g
.br
.Nm man :
.Ox 2.3 Pq March 9, 1998 ,
.Nx Pq June 12, 2000 ;
.No illumos , Solaris 9-11
.br
.Nm apropos :
.No man-db Pq Nov 16, 2003 ,
.Ox 4.5 Pq Dec 24, 2008 ,
.Nx Pq May 8, 2009 ;
.No illumos
.br
.Nm whatis :
.No man-db Pq Nov 16, 2003 ,
.Ox 5.6 Pq April 18, 2014 ;
.No illumos
.br
.Nm mandoc :
.Ox 5.7 Pq August 27, 2014
.Pp
do not look for stray cats
.br
.Nm mandb :
.dbI
.Pp
.Bq SysV compat, recommends Fl S
manual section search list
.br
.Nm man :
.No man-db Pq Jan 1, 2008
.Pp
.Bq superseded by Fl h
display the SYNOPSIS lines only
.br
.Nm man :
.PWB
.Pp
.Bq obsolete hardware
pause before each page for paper manipulation
.br
.Nm roff :
.At7
.Pp
.Bq obsolete hardware
.Xr troff 1
output mode, small format
.br
.Nm man :
.At3 ,
.At5
.It Fl T
select terminal output format
.br
.Nm nroff :
.At7
.br
.Nm man :
.At3 ,
.At5 ,
.dbI ,
.Ox 5.7 Pq August 27, 2014
.br
.Nm groff :
.g04
.br
.Nm mandoc :
.Ox 4.8 Pq April 6, 2009
.br
.Nm apropos , whatis :
.Ox 5.7 Pq August 27, 2014
.Pp
use UTF-8 for
.Xr mandoc.db 5
.br
.Nm makewhatis :
.Ox 5.6 Pq April 18, 2014
.Pp
.Bq superseded by Fl m
use other macro package
.br
.Nm man , catman :
.No Solaris 9-11
.It Fl t
.Xr troff 1
output mode
.br
.Nm man :
.PWB ,
.At7 ,
.Bx 2 Pq May 10, 1979 ,
.At3 ,
.At5 ,
.Eaton ;
.Fx , No man-db , man-1.6 , illumos , Solaris 9-11
.br
.Nm catman :
.No Solaris 9-11
.Pp
preprocess with
.Xr tbl 7
.br
.Nm groff :
.g04
.Pp
check manual pages in the hierarchy
.br
.Nm mandb :
.No man-db-1.3.12 to 1.3.17 Pq not before 1996, not after 2001
.Pp
check files for problems related to
.Xr mandoc.db 5
.br
.Nm makewhatis :
.Ox 2.7 Pq April 23, 2000
.It Fl U
unsafe mode
.br
.Nm groff :
.No groff-1.12 Pq Dec 13, 1999
.It Fl u
update database
.br
.Nm makewhatis :
.Pq not before 1992, not after 1995
.Pp
create user databases only
.br
.Nm mandb :
.dbI
.Pp
update database cache (requires suid)
.br
.Nm man :
.No before man-db-2.2a10 Pq before Dec 6, 1994
.Pp
remove files from
.Xr mandoc.db 5
.br
.Nm makewhatis :
.Ox 3.4 Pq July 9, 2003
.It Fl V
print the pipeline on stdout instead of executing it
.br
.Nm groff :
.No groff-0.6 Pq Sep 2, 1990
.Pp
print version information
.br
.Nm man , apropos , whatis , mandb , catman , manpath :
.dbI
.It Fl v
print version number
.br
.Nm groff :
.g04
.Pp
verbose mode
.br
.Nm catman :
.Fx Pq March 15, 1995
.br
.Nm makewhatis :
.man15g
.br
.Nm apropos , whatis :
.No man-db Pq Dec 29, 2002
.Pp
print the name of every parsed file
.br
.Nm makemandb :
.Nx Pq Feb 7, 2012
.Pp
.Bq obsolete hardware
produce output on the Versatec printer
.br
.Nm man :
.PWB
.It Fl W
disable the named warning
.br
.Nm groff :
.No groff-0.5 Pq August 14, 1990
.Pp
list pathnames without additional information
.br
.Nm man :
.man15e
.Pp
list pathnames of cat files
.br
.Nm man :
.No man-db Pq Aug 13, 2002
.Pp
minimum message level to display
.br
.Nm mandoc :
.Ox 4.8 Pq April 6, 2009
.br
.Nm man , apropos , whatis :
.Ox 5.7 Pq August 27, 2014
.It Fl w
list pathnames
.br
.Nm man :
.At7 ,
.At3 ,
.At5 ,
.Eaton ;
.Ox , Fx , Nx , No man-db , man-1.6
.br
.Nm apropos , whatis , mandoc :
.Ox 5.7 Pq August 27, 2014
.Pp
enable the named warning
.br
.Nm groff :
.No groff-0.5 Pq August 14, 1990
.Pp
only create the
.Xr whatis 1
database
.br
.Nm catman :
.Nx Pq July 27, 1993 ,
.No Solaris 9-11
.Pp
use wildcard matching
.br
.Nm apropos , whatis :
.No man-db-2.3.5 Pq April 21, 1995
.Pp
use manpath obtained from man --path
.br
.Nm makewhatis :
.man15g
.Pp
update the
.Xr whatis 1
database
.br
.Nm man :
.No illumos
.Pp
.Bq obsolete hardware
wait until the phototypesetter is available
.br
.Nm troff :
.At7
.It Fl X
display with
.Xr gxditview 1
.br
.Nm groff :
.No groff-1.06 Pq Sep 1, 1992
.br
.Nm man :
.dbI
.It Fl y
use the non-compacted version of the macros
.br
.Nm man :
.At3 ,
.At5
.It Fl Z
do not run preprocessors
.br
.Nm groff :
.g04
.br
.Nm man :
.No man-db-2.2a5 Pq Nov 10, 1994
.It Fl z
suppress formatted output from
.Xr troff 1 ,
print only error messages
.br
.Nm groff :
.g04
.It Fl 7
ASCII output mode
.br
.Nm man :
.No man-db-2.3.5 Pq April 21, 1995
.It Fl \&?
print a help message and exit
.br
.Nm groff :
.g04
.br
.Nm man , manpath :
.Eaton ;
.Fx , No man-db
.br
.Nm apropos , whatis , mandb , catman :
.dbI
.El
.Pp
Multi-letter options:
.Bl -tag -width Ds
.It Fl hp
.Bq obsolete hardware
output to a Hewlett Packard terminal
.br
.Nm man :
.PWB
.It Fl 12
.Bq obsolete hardware
use 12-pitch for certain terminals
.br
.Nm man :
.At3 ,
.At5
.It Fl 450
.Bq obsolete hardware
output to a DASI 450 terminal
.br
.Nm man :
.PWB
.El
.Pp
In
.At v3 ,
.Xr man 1
had no options.
.br
The syntax was:
.Sy man Ar name Op Ar section
.Pp
In
.At v4 ,
.br
the syntax changed to:
.Sy man Oo Ar section Oc Op Ar name ...
.Sh AUTHORS
This information was assembled by
.An Ingo Schwarze Aq Mt schwarze@openbsd.org
using
.Bl -bullet -compact
.It
the Unix Archive of the Unix Heritage Society
.It
the CSRG Archive CD-ROMs
.It
-the FreeBSD SVN repository
+the
+.Fx
+SVN repository
.It
-the OpenBSD CVS repository
+the
+.Ox
+CVS repository
.It
-the NetBSD CVS repository
+the
+.Nx
+CVS repository
.It
the GNU roff (groff) git repository
.It
the 4.3BSD-Net/2 groff CHANGES file (Oct 1990 to March 1991)
.It
the 4.3BSD-Net/2 groff ChangeLog file (July 1990 to March 1991)
.It
the man-db CVS and git repositories (since April 2001)
.It
the man-db NEWS file (April 1995 to Dec 2016)
.It
the man-db ChangeLog-2013 file (Nov 1994 to Dec 2013)
.It
release tarballs man-1.5g (July 1998) to man-1.5p (Jan 2005),
man-1.6 (June 2005), and man-1.6a to man-1.6g (Dec 2010)
.It
a makewhatis release tarball without version number from 1995
.It
the illumos manual pages on the WWW
.It
and Solaris 11, SunOS 5.10, and SunOS 5.9 machines at opencsw.org.
.El
Index: vendor/mdocml/dist/man_html.c
===================================================================
--- vendor/mdocml/dist/man_html.c (revision 321806)
+++ vendor/mdocml/dist/man_html.c (revision 321807)
@@ -1,660 +1,670 @@
-/* $Id: man_html.c,v 1.143 2017/06/08 12:54:58 schwarze Exp $ */
+/* $Id: man_html.c,v 1.145 2017/06/25 11:42:02 schwarze Exp $ */
/*
* Copyright (c) 2008-2012, 2014 Kristaps Dzonsons
* Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze
*
* 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
#include
#include
#include
#include
#include
#include "mandoc_aux.h"
+#include "mandoc.h"
#include "roff.h"
#include "man.h"
#include "out.h"
#include "html.h"
#include "main.h"
/* FIXME: have PD set the default vspace width. */
#define INDENT 5
#define MAN_ARGS const struct roff_meta *man, \
const struct roff_node *n, \
struct html *h
struct htmlman {
int (*pre)(MAN_ARGS);
int (*post)(MAN_ARGS);
};
static void print_bvspace(struct html *,
const struct roff_node *);
static void print_man_head(MAN_ARGS);
static void print_man_nodelist(MAN_ARGS);
static void print_man_node(MAN_ARGS);
static int fillmode(struct html *, int);
static int a2width(const struct roff_node *,
struct roffsu *);
static int man_B_pre(MAN_ARGS);
static int man_HP_pre(MAN_ARGS);
static int man_IP_pre(MAN_ARGS);
static int man_I_pre(MAN_ARGS);
static int man_OP_pre(MAN_ARGS);
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_UR_pre(MAN_ARGS);
static int man_alt_pre(MAN_ARGS);
static int man_ign_pre(MAN_ARGS);
static int man_in_pre(MAN_ARGS);
static void man_root_post(MAN_ARGS);
static void man_root_pre(MAN_ARGS);
static const struct htmlman __mans[MAN_MAX - MAN_TH] = {
{ NULL, NULL }, /* TH */
{ man_SH_pre, NULL }, /* SH */
{ man_SS_pre, NULL }, /* SS */
{ man_IP_pre, NULL }, /* TP */
{ man_PP_pre, NULL }, /* LP */
{ man_PP_pre, NULL }, /* PP */
{ man_PP_pre, NULL }, /* P */
{ man_IP_pre, NULL }, /* IP */
{ man_HP_pre, NULL }, /* HP */
{ man_SM_pre, NULL }, /* SM */
{ man_SM_pre, NULL }, /* SB */
{ man_alt_pre, NULL }, /* BI */
{ man_alt_pre, NULL }, /* IB */
{ man_alt_pre, NULL }, /* BR */
{ man_alt_pre, NULL }, /* RB */
{ NULL, NULL }, /* R */
{ man_B_pre, NULL }, /* B */
{ 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 */
{ man_ign_pre, NULL }, /* UC */
{ man_ign_pre, NULL }, /* PD */
{ man_ign_pre, NULL }, /* AT */
{ man_in_pre, NULL }, /* in */
{ man_OP_pre, NULL }, /* OP */
{ NULL, NULL }, /* EX */
{ NULL, NULL }, /* EE */
{ man_UR_pre, NULL }, /* UR */
{ NULL, NULL }, /* UE */
+ { 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)
{
struct html *h;
struct tag *t;
h = (struct html *)arg;
if ((h->oflags & HTML_FRAGMENT) == 0) {
print_gen_decls(h);
print_otag(h, TAG_HTML, "");
t = print_otag(h, TAG_HEAD, "");
print_man_head(&man->meta, man->first, h);
print_tagq(h, t);
print_otag(h, TAG_BODY, "");
}
man_root_pre(&man->meta, man->first, h);
t = print_otag(h, TAG_DIV, "c", "manual-text");
print_man_nodelist(&man->meta, man->first->child, h);
print_tagq(h, t);
man_root_post(&man->meta, man->first, h);
print_tagq(h, NULL);
}
static void
print_man_head(MAN_ARGS)
{
char *cp;
print_gen_head(h);
mandoc_asprintf(&cp, "%s(%s)", man->title, man->msec);
print_otag(h, TAG_TITLE, "");
print_text(h, cp);
free(cp);
}
static void
print_man_nodelist(MAN_ARGS)
{
while (n != NULL) {
print_man_node(man, n, h);
n = n->next;
}
}
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;
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;
default:
break;
}
/* Produce output for this node. */
child = 1;
switch (n->type) {
case ROFFT_TEXT:
t = h->tag;
print_text(h, n->string);
break;
case ROFFT_EQN:
t = h->tag;
print_eqn(h, n->eqn);
break;
case ROFFT_TBL:
/*
* This will take care of initialising all of the table
* state data for the first table, then tearing it down
* for the last one.
*/
print_tbl(h, n->span);
return;
default:
/*
* Close out scope of font prior to opening a macro
* scope.
*/
if (HTMLFONT_NONE != h->metac) {
h->metal = h->metac;
h->metac = HTMLFONT_NONE;
}
/*
* Close out the current table, if it's open, and unset
* the "meta" table state. This will be reopened on the
* next table element.
*/
if (h->tblt)
print_tblclose(h);
t = h->tag;
if (n->tok < ROFF_MAX) {
roff_html_pre(h, n);
child = 0;
break;
}
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;
break;
}
if (child && n->child)
print_man_nodelist(man, n->child, h);
/* This will automatically close out any font scope. */
print_stagq(h, t);
if (fillmode(h, 0) == MAN_nf &&
n->next != NULL && n->next->flags & NODE_LINE)
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 int
a2width(const struct roff_node *n, struct roffsu *su)
{
if (n->type != ROFFT_TEXT)
return 0;
return a2roffsu(n->string, su, SCALE_EN) != NULL;
}
static void
man_root_pre(MAN_ARGS)
{
struct tag *t, *tt;
char *title;
assert(man->title);
assert(man->msec);
mandoc_asprintf(&title, "%s(%s)", man->title, man->msec);
t = print_otag(h, TAG_TABLE, "c", "head");
tt = print_otag(h, TAG_TR, "");
print_otag(h, TAG_TD, "c", "head-ltitle");
print_text(h, title);
print_stagq(h, tt);
print_otag(h, TAG_TD, "c", "head-vol");
if (NULL != man->vol)
print_text(h, man->vol);
print_stagq(h, tt);
print_otag(h, TAG_TD, "c", "head-rtitle");
print_text(h, title);
print_tagq(h, t);
free(title);
}
static void
man_root_post(MAN_ARGS)
{
struct tag *t, *tt;
t = print_otag(h, TAG_TABLE, "c", "foot");
tt = print_otag(h, TAG_TR, "");
print_otag(h, TAG_TD, "c", "foot-date");
print_text(h, man->date);
print_stagq(h, tt);
print_otag(h, TAG_TD, "c", "foot-os");
if (man->os)
print_text(h, man->os);
print_tagq(h, t);
}
static int
man_SH_pre(MAN_ARGS)
{
char *id;
if (n->type == ROFFT_HEAD) {
id = html_make_id(n);
print_otag(h, TAG_H1, "cTi", "Sh", id);
if (id != NULL)
print_otag(h, TAG_A, "chR", "selflink", id);
free(id);
}
return 1;
}
static int
man_alt_pre(MAN_ARGS)
{
const struct roff_node *nn;
int i;
enum htmltag fp;
struct tag *t;
for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
switch (n->tok) {
case MAN_BI:
fp = i % 2 ? TAG_I : TAG_B;
break;
case MAN_IB:
fp = i % 2 ? TAG_B : TAG_I;
break;
case MAN_RI:
fp = i % 2 ? TAG_I : TAG_MAX;
break;
case MAN_IR:
fp = i % 2 ? TAG_MAX : TAG_I;
break;
case MAN_BR:
fp = i % 2 ? TAG_MAX : TAG_B;
break;
case MAN_RB:
fp = i % 2 ? TAG_B : TAG_MAX;
break;
default:
abort();
}
if (i)
h->flags |= HTML_NOSPACE;
if (fp != TAG_MAX)
t = print_otag(h, fp, "");
print_text(h, nn->string);
if (fp != TAG_MAX)
print_tagq(h, t);
}
return 0;
}
static int
man_SM_pre(MAN_ARGS)
{
print_otag(h, TAG_SMALL, "");
if (MAN_SB == n->tok)
print_otag(h, TAG_B, "");
return 1;
}
static int
man_SS_pre(MAN_ARGS)
{
char *id;
if (n->type == ROFFT_HEAD) {
id = html_make_id(n);
print_otag(h, TAG_H2, "cTi", "Ss", id);
if (id != NULL)
print_otag(h, TAG_A, "chR", "selflink", id);
free(id);
}
return 1;
}
static int
man_PP_pre(MAN_ARGS)
{
if (n->type == ROFFT_HEAD)
return 0;
else if (n->type == ROFFT_BLOCK)
print_bvspace(h, n);
return 1;
}
static int
man_IP_pre(MAN_ARGS)
{
const struct roff_node *nn;
if (n->type == ROFFT_BODY) {
print_otag(h, TAG_DD, "c", "It-tag");
return 1;
} else if (n->type != ROFFT_HEAD) {
print_otag(h, TAG_DL, "c", "Bl-tag");
return 1;
}
/* FIXME: width specification. */
print_otag(h, TAG_DT, "c", "It-tag");
/* 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) {
nn = n->child;
while (NULL != nn && 0 == (NODE_LINE & nn->flags))
nn = nn->next;
while (NULL != nn) {
print_man_node(man, nn, h);
nn = nn->next;
}
}
return 0;
}
static int
man_HP_pre(MAN_ARGS)
{
struct roffsu sum, sui;
const struct roff_node *np;
if (n->type == ROFFT_HEAD)
return 0;
else if (n->type != ROFFT_BLOCK)
return 1;
np = n->head->child;
if (np == NULL || !a2width(np, &sum))
SCALE_HS_INIT(&sum, INDENT);
sui.unit = sum.unit;
sui.scale = -sum.scale;
print_bvspace(h, n);
print_otag(h, TAG_DIV, "csului", "Pp", &sum, &sui);
return 1;
}
static int
man_OP_pre(MAN_ARGS)
{
struct tag *tt;
print_text(h, "[");
h->flags |= HTML_NOSPACE;
tt = print_otag(h, TAG_SPAN, "c", "Op");
if (NULL != (n = n->child)) {
print_otag(h, TAG_B, "");
print_text(h, n->string);
}
print_stagq(h, tt);
if (NULL != n && NULL != n->next) {
print_otag(h, TAG_I, "");
print_text(h, n->next->string);
}
print_stagq(h, tt);
h->flags |= HTML_NOSPACE;
print_text(h, "]");
return 0;
}
static int
man_B_pre(MAN_ARGS)
{
print_otag(h, TAG_B, "");
return 1;
}
static int
man_I_pre(MAN_ARGS)
{
print_otag(h, TAG_I, "");
return 1;
}
static int
man_in_pre(MAN_ARGS)
{
print_otag(h, TAG_BR, "");
return 0;
}
static int
man_ign_pre(MAN_ARGS)
{
return 0;
}
static int
man_RS_pre(MAN_ARGS)
{
struct roffsu su;
if (n->type == ROFFT_HEAD)
return 0;
else if (n->type == ROFFT_BODY)
return 1;
SCALE_HS_INIT(&su, INDENT);
if (n->head->child)
a2width(n->head->child, &su);
print_otag(h, TAG_DIV, "sul", &su);
return 1;
}
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);
- print_otag(h, TAG_A, "cTh", "Lk", n->child->string);
+ if (n->tok == MAN_MT) {
+ mandoc_asprintf(&cp, "mailto:%s", n->child->string);
+ print_otag(h, TAG_A, "cTh", "Mt", cp);
+ free(cp);
+ } else
+ print_otag(h, TAG_A, "cTh", "Lk", n->child->string);
}
assert(n->next->type == ROFFT_BODY);
if (n->next->child != NULL)
n = n->next;
print_man_nodelist(man, n->child, h);
return 0;
}
Index: vendor/mdocml/dist/man_macro.c
===================================================================
--- vendor/mdocml/dist/man_macro.c (revision 321806)
+++ vendor/mdocml/dist/man_macro.c (revision 321807)
@@ -1,404 +1,422 @@
-/* $Id: man_macro.c,v 1.120 2017/05/05 15:17:32 schwarze Exp $ */
+/* $Id: man_macro.c,v 1.123 2017/06/25 11:45:37 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons
* Copyright (c) 2012-2015, 2017 Ingo Schwarze
* Copyright (c) 2013 Franco Fichtner
*
* 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
#include
#include
#include
#include
#include "mandoc.h"
#include "roff.h"
#include "man.h"
#include "libmandoc.h"
#include "roff_int.h"
#include "libman.h"
static void blk_close(MACRO_PROT_ARGS);
static void blk_exp(MACRO_PROT_ARGS);
static void blk_imp(MACRO_PROT_ARGS);
static void in_line_eoln(MACRO_PROT_ARGS);
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 */
{ 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, 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 */
{ in_line_eoln, 0 }, /* DT */
{ in_line_eoln, 0 }, /* UC */
{ in_line_eoln, MAN_NSCOPED }, /* PD */
{ in_line_eoln, 0 }, /* AT */
- { in_line_eoln, 0 }, /* in */
+ { in_line_eoln, MAN_NSCOPED }, /* in */
{ 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 */
};
const struct man_macro *const man_macros = __man_macros - MAN_TH;
void
man_unscope(struct roff_man *man, const struct roff_node *to)
{
struct roff_node *n;
to = to->parent;
n = man->last;
while (n != to) {
/* Reached the end of the document? */
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,
"EOF breaks %s", roff_name[n->tok]);
if (man->flags & MAN_ELINE)
man->flags &= ~MAN_ELINE;
else {
assert(n->type == ROFFT_HEAD);
n = n->parent;
man->flags &= ~MAN_BLINE;
}
man->last = n;
n = n->parent;
roff_node_delete(man, man->last);
continue;
}
if (n->type == ROFFT_BLOCK &&
man_macros[n->tok].fp == blk_exp)
mandoc_msg(MANDOCERR_BLK_NOEND,
man->parse, n->line, n->pos,
roff_name[n->tok]);
}
/*
* We might delete the man->last node
* in the post-validation phase.
* Save a pointer to the parent such that
* we know where to continue the iteration.
*/
man->last = n;
n = n->parent;
man->last->flags |= NODE_VALID;
}
/*
* If we ended up at the parent of the node we were
* supposed to rewind to, that means the target node
* got deleted, so add the next node we parse as a child
* of the parent instead of as a sibling of the target.
*/
man->next = (man->last == to) ?
ROFF_NEXT_CHILD : ROFF_NEXT_SIBLING;
}
/*
* Rewinding entails ascending the parse tree until a coherent point,
* for example, the `SH' macro will close out any intervening `SS'
* scopes. When a scope is closed, it must be validated and actioned.
*/
static void
rew_scope(struct roff_man *man, enum roff_tok tok)
{
struct roff_node *n;
/* Preserve empty paragraphs before RS. */
n = man->last;
if (tok == MAN_RS && n->child == NULL &&
(n->tok == MAN_P || n->tok == MAN_PP || n->tok == MAN_LP))
return;
for (;;) {
if (n->type == ROFFT_ROOT)
return;
if (n->flags & NODE_VALID) {
n = n->parent;
continue;
}
if (n->type != ROFFT_BLOCK) {
if (n->parent->type == ROFFT_ROOT) {
man_unscope(man, n);
return;
} else {
n = n->parent;
continue;
}
}
if (tok != MAN_SH && (n->tok == MAN_SH ||
(tok != MAN_SS && (n->tok == MAN_SS ||
man_macros[n->tok].fp == blk_exp))))
return;
man_unscope(man, n);
n = man->last;
}
}
/*
* Close out a generic explicit macro.
*/
void
blk_close(MACRO_PROT_ARGS)
{
enum roff_tok ntok;
const struct roff_node *nn;
char *p;
int nrew, target;
nrew = 1;
switch (tok) {
case MAN_RE:
ntok = MAN_RS;
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);
if (target == 0)
target = 1;
nrew -= target;
if (nrew < 1) {
mandoc_vmsg(MANDOCERR_RE_NOTOPEN, man->parse,
line, ppos, "RE %d", target);
return;
}
break;
case MAN_UE:
ntok = MAN_UR;
break;
+ case MAN_ME:
+ ntok = MAN_MT;
+ break;
default:
abort();
}
for (nn = man->last->parent; nn; nn = nn->parent)
if (nn->tok == ntok && nn->type == ROFFT_BLOCK && ! --nrew)
break;
if (nn == NULL) {
mandoc_msg(MANDOCERR_BLK_NOTOPEN, man->parse,
line, ppos, 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 && nn->head->aux > 0)
+ roff_setreg(man->roff, "an-margin",
+ nn->head->aux, '-');
+
/* Move a trailing paragraph behind the block. */
if (ntok == MAN_LP || ntok == MAN_PP || ntok == MAN_P) {
*pos = strlen(buf);
blk_imp(man, ntok, line, ppos, pos, buf);
}
}
}
void
blk_exp(MACRO_PROT_ARGS)
{
struct roff_node *head;
char *p;
int la;
rew_scope(man, tok);
roff_block_alloc(man, line, ppos, tok);
head = roff_head_alloc(man, line, ppos, tok);
la = *pos;
- if (man_args(man, line, pos, buf, &p))
+ if (man_args(man, line, pos, buf, &p)) {
roff_word_alloc(man, line, la, p);
+ if (tok == MAN_RS) {
+ if (roff_getreg(man->roff, "an-margin") == 0)
+ roff_setreg(man->roff, "an-margin",
+ 7 * 24, '=');
+ if ((head->aux = strtod(p, NULL) * 24.0) > 0)
+ roff_setreg(man->roff, "an-margin",
+ head->aux, '+');
+ }
+ }
if (buf[*pos] != '\0')
mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse, line,
*pos, "%s ... %s", roff_name[tok], buf + *pos);
man_unscope(man, head);
roff_body_alloc(man, line, ppos, tok);
}
/*
* Parse an implicit-block macro. These contain a ROFFT_HEAD and a
* ROFFT_BODY contained within a ROFFT_BLOCK. Rules for closing out other
* scopes, such as `SH' closing out an `SS', are defined in the rew
* routines.
*/
void
blk_imp(MACRO_PROT_ARGS)
{
int la;
char *p;
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;
n = roff_head_alloc(man, line, ppos, tok);
/* Add line arguments. */
for (;;) {
la = *pos;
if ( ! man_args(man, line, pos, buf, &p))
break;
roff_word_alloc(man, line, la, p);
}
/*
* For macros having optional next-line scope,
* keep the head open if there were no arguments.
* For `TP', always keep the head open.
*/
if (man_macros[tok].flags & MAN_SCOPED &&
(tok == MAN_TP || n == man->last)) {
man->flags |= MAN_BLINE;
return;
}
/* Close out the head and open the body. */
man_unscope(man, n);
roff_body_alloc(man, line, ppos, tok);
}
void
in_line_eoln(MACRO_PROT_ARGS)
{
int la;
char *p;
struct roff_node *n;
roff_elem_alloc(man, line, ppos, tok);
n = man->last;
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);
break;
}
la = *pos;
if ( ! man_args(man, line, pos, buf, &p))
break;
if (man_macros[tok].flags & MAN_JOIN &&
man->last->type == ROFFT_TEXT)
roff_word_append(man, p);
else
roff_word_alloc(man, line, la, p);
}
/*
* Append NODE_EOS in case the last snipped argument
* ends with a dot, e.g. `.IR syslog (3).'
*/
if (n != man->last &&
mandoc_eos(man->last->string, strlen(man->last->string)))
man->last->flags |= NODE_EOS;
/*
* If no arguments are specified and this is MAN_SCOPED (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));
man->flags |= MAN_ELINE;
return;
}
assert(man->last->type != ROFFT_ROOT);
man->next = ROFF_NEXT_SIBLING;
/* Rewind our element scope. */
for ( ; man->last; man->last = man->last->parent) {
man_state(man, man->last);
if (man->last == n)
break;
}
}
void
man_endparse(struct roff_man *man)
{
man_unscope(man, man->first);
man->flags &= ~MAN_LITERAL;
}
static int
man_args(struct roff_man *man, int line, int *pos, char *buf, char **v)
{
char *start;
assert(*pos);
*v = start = buf + *pos;
assert(' ' != *start);
if ('\0' == *start)
return 0;
*v = mandoc_getarg(man->parse, v, line, pos);
return 1;
}
Index: vendor/mdocml/dist/man_term.c
===================================================================
--- vendor/mdocml/dist/man_term.c (revision 321806)
+++ vendor/mdocml/dist/man_term.c (revision 321807)
@@ -1,1096 +1,1101 @@
-/* $Id: man_term.c,v 1.204 2017/06/08 12:54:58 schwarze Exp $ */
+/* $Id: man_term.c,v 1.208 2017/06/25 11:42:02 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons
* Copyright (c) 2010-2015, 2017 Ingo Schwarze
*
* 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
#include
#include
#include
#include
#include
#include
#include "mandoc_aux.h"
#include "mandoc.h"
#include "roff.h"
#include "man.h"
#include "out.h"
#include "term.h"
#include "main.h"
#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 */
size_t offset; /* default offset to visible page */
int pardist; /* vert. space before par., unit: [v] */
};
#define DECL_ARGS struct termp *p, \
struct mtermp *mt, \
struct roff_node *n, \
const struct roff_meta *meta
struct termact {
int (*pre)(DECL_ARGS);
void (*post)(DECL_ARGS);
int flags;
#define MAN_NOTEXT (1 << 0) /* Never has text children. */
};
static void print_man_nodelist(DECL_ARGS);
static void print_man_node(DECL_ARGS);
static void print_man_head(struct termp *,
const struct roff_meta *);
static void print_man_foot(struct termp *,
const struct roff_meta *);
static void print_bvspace(struct termp *,
const struct roff_node *, int);
static int pre_B(DECL_ARGS);
static int pre_DT(DECL_ARGS);
static int pre_HP(DECL_ARGS);
static int pre_I(DECL_ARGS);
static int pre_IP(DECL_ARGS);
static int pre_OP(DECL_ARGS);
static int pre_PD(DECL_ARGS);
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_TP(DECL_ARGS);
static int pre_UR(DECL_ARGS);
static int pre_alternate(DECL_ARGS);
static int pre_ign(DECL_ARGS);
static int pre_in(DECL_ARGS);
static int pre_literal(DECL_ARGS);
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_TP(DECL_ARGS);
static void post_UR(DECL_ARGS);
static const struct termact __termacts[MAN_MAX - MAN_TH] = {
{ NULL, NULL, 0 }, /* TH */
{ pre_SH, post_SH, 0 }, /* SH */
{ pre_SS, post_SS, 0 }, /* SS */
{ pre_TP, post_TP, 0 }, /* TP */
{ pre_PP, NULL, 0 }, /* LP */
{ pre_PP, NULL, 0 }, /* PP */
{ pre_PP, NULL, 0 }, /* P */
{ pre_IP, post_IP, 0 }, /* IP */
{ pre_HP, post_HP, 0 }, /* HP */
{ NULL, NULL, 0 }, /* SM */
{ pre_B, NULL, 0 }, /* SB */
{ pre_alternate, NULL, 0 }, /* BI */
{ pre_alternate, NULL, 0 }, /* IB */
{ pre_alternate, NULL, 0 }, /* BR */
{ pre_alternate, NULL, 0 }, /* RB */
{ NULL, NULL, 0 }, /* R */
{ pre_B, NULL, 0 }, /* B */
{ 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 */
{ pre_ign, NULL, MAN_NOTEXT }, /* UC */
{ pre_PD, NULL, MAN_NOTEXT }, /* PD */
{ pre_ign, NULL, 0 }, /* AT */
{ pre_in, NULL, MAN_NOTEXT }, /* in */
{ pre_OP, NULL, 0 }, /* OP */
{ pre_literal, NULL, 0 }, /* EX */
{ pre_literal, NULL, 0 }, /* EE */
{ pre_UR, post_UR, 0 }, /* UR */
{ NULL, NULL, 0 }, /* UE */
+ { pre_UR, post_UR, 0 }, /* MT */
+ { NULL, NULL, 0 }, /* ME */
};
static const struct termact *termacts = __termacts - MAN_TH;
void
terminal_man(void *arg, const struct roff_man *man)
{
struct termp *p;
struct roff_node *n;
struct mtermp mt;
size_t save_defindent;
p = (struct termp *)arg;
+ save_defindent = p->defindent;
+ if (p->synopsisonly == 0 && p->defindent == 0)
+ p->defindent = 7;
p->tcol->rmargin = p->maxrmargin = p->defrmargin;
term_tab_set(p, NULL);
term_tab_set(p, "T");
term_tab_set(p, ".5i");
memset(&mt, 0, sizeof(struct mtermp));
mt.lmargin[mt.lmargincur] = term_len(p, p->defindent);
mt.offset = term_len(p, p->defindent);
mt.pardist = 1;
n = man->first->child;
if (p->synopsisonly) {
while (n != NULL) {
if (n->tok == MAN_SH &&
n->child->child->type == ROFFT_TEXT &&
!strcmp(n->child->child->string, "SYNOPSIS")) {
if (n->child->next->child != NULL)
print_man_nodelist(p, &mt,
n->child->next->child,
&man->meta);
term_newln(p);
break;
}
n = n->next;
}
} else {
- save_defindent = p->defindent;
- if (p->defindent == 0)
- p->defindent = 7;
term_begin(p, print_man_head, print_man_foot, &man->meta);
p->flags |= TERMP_NOSPACE;
if (n != NULL)
print_man_nodelist(p, &mt, n, &man->meta);
term_end(p);
- p->defindent = save_defindent;
}
+ p->defindent = save_defindent;
}
/*
* 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 termp *p, const struct roff_node *n, int pardist)
{
int i;
term_newln(p);
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;
for (i = 0; i < pardist; i++)
term_vspace(p);
}
static int
pre_ign(DECL_ARGS)
{
return 0;
}
static int
pre_I(DECL_ARGS)
{
term_fontrepl(p, TERMFONT_UNDER);
return 1;
}
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,
* indentation has to be set up explicitly.
*/
if (n->parent->tok == MAN_HP && p->tcol->rmargin < p->maxrmargin) {
p->tcol->offset = p->tcol->rmargin;
p->tcol->rmargin = p->maxrmargin;
p->trailspace = 0;
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
p->flags |= TERMP_NOSPACE;
}
return 0;
}
static int
pre_PD(DECL_ARGS)
{
struct roffsu su;
n = n->child;
if (n == NULL) {
mt->pardist = 1;
return 0;
}
assert(n->type == ROFFT_TEXT);
if (a2roffsu(n->string, &su, SCALE_VS) != NULL)
mt->pardist = term_vspan(p, &su);
return 0;
}
static int
pre_alternate(DECL_ARGS)
{
enum termfont font[2];
struct roff_node *nn;
int savelit, i;
switch (n->tok) {
case MAN_RB:
font[0] = TERMFONT_NONE;
font[1] = TERMFONT_BOLD;
break;
case MAN_RI:
font[0] = TERMFONT_NONE;
font[1] = TERMFONT_UNDER;
break;
case MAN_BR:
font[0] = TERMFONT_BOLD;
font[1] = TERMFONT_NONE;
break;
case MAN_BI:
font[0] = TERMFONT_BOLD;
font[1] = TERMFONT_UNDER;
break;
case MAN_IR:
font[0] = TERMFONT_UNDER;
font[1] = TERMFONT_NONE;
break;
case MAN_IB:
font[0] = TERMFONT_UNDER;
font[1] = TERMFONT_BOLD;
break;
default:
abort();
}
savelit = MANT_LITERAL & mt->fl;
mt->fl &= ~MANT_LITERAL;
for (i = 0, nn = n->child; nn; 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_NOSPACE;
}
return 0;
}
static int
pre_B(DECL_ARGS)
{
term_fontrepl(p, TERMFONT_BOLD);
return 1;
}
static int
pre_OP(DECL_ARGS)
{
term_word(p, "[");
p->flags |= TERMP_NOSPACE;
if (NULL != (n = n->child)) {
term_fontrepl(p, TERMFONT_BOLD);
term_word(p, n->string);
}
if (NULL != n && NULL != n->next) {
term_fontrepl(p, TERMFONT_UNDER);
term_word(p, n->next->string);
}
term_fontrepl(p, TERMFONT_NONE);
p->flags |= TERMP_NOSPACE;
term_word(p, "]");
return 0;
}
static int
pre_in(DECL_ARGS)
{
struct roffsu su;
const char *cp;
size_t v;
int less;
term_newln(p);
if (n->child == NULL) {
p->tcol->offset = mt->offset;
return 0;
}
cp = n->child->string;
less = 0;
if ('-' == *cp)
less = -1;
else if ('+' == *cp)
less = 1;
else
cp--;
if (a2roffsu(++cp, &su, SCALE_EN) == NULL)
return 0;
- v = (term_hspan(p, &su) + 11) / 24;
+ v = term_hen(p, &su);
if (less < 0)
p->tcol->offset -= p->tcol->offset > v ? v : p->tcol->offset;
else if (less > 0)
p->tcol->offset += v;
else
p->tcol->offset = v;
if (p->tcol->offset > SHRT_MAX)
p->tcol->offset = term_len(p, p->defindent);
return 0;
}
static int
pre_DT(DECL_ARGS)
{
term_tab_set(p, NULL);
term_tab_set(p, "T");
term_tab_set(p, ".5i");
return 0;
}
static int
pre_HP(DECL_ARGS)
{
struct roffsu su;
const struct roff_node *nn;
int len;
switch (n->type) {
case ROFFT_BLOCK:
print_bvspace(p, n, mt->pardist);
return 1;
case ROFFT_BODY:
break;
default:
return 0;
}
if ( ! (MANT_LITERAL & mt->fl)) {
p->flags |= TERMP_NOBREAK | TERMP_BRIND;
p->trailspace = 2;
}
/* Calculate offset. */
if ((nn = n->parent->head->child) != NULL &&
a2roffsu(nn->string, &su, SCALE_EN) != NULL) {
- len = term_hspan(p, &su) / 24;
+ len = term_hen(p, &su);
if (len < 0 && (size_t)(-len) > mt->offset)
len = -mt->offset;
else if (len > SHRT_MAX)
len = term_len(p, p->defindent);
mt->lmargin[mt->lmargincur] = len;
} else
len = mt->lmargin[mt->lmargincur];
p->tcol->offset = mt->offset;
p->tcol->rmargin = mt->offset + len;
return 1;
}
static void
post_HP(DECL_ARGS)
{
switch (n->type) {
case ROFFT_BODY:
term_newln(p);
/*
* Compatibility with a groff bug.
* The .HP macro uses the undocumented .tag request
* which causes a line break and cancels no-space
* mode even if there isn't any output.
*/
if (n->child == NULL)
term_vspace(p);
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
p->trailspace = 0;
p->tcol->offset = mt->offset;
p->tcol->rmargin = p->maxrmargin;
break;
default:
break;
}
}
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:
p->tcol->offset = mt->offset;
break;
}
return n->type != ROFFT_HEAD;
}
static int
pre_IP(DECL_ARGS)
{
struct roffsu su;
const struct roff_node *nn;
int len, savelit;
switch (n->type) {
case ROFFT_BODY:
p->flags |= TERMP_NOSPACE;
break;
case ROFFT_HEAD:
p->flags |= TERMP_NOBREAK;
p->trailspace = 1;
break;
case ROFFT_BLOCK:
print_bvspace(p, n, mt->pardist);
/* FALLTHROUGH */
default:
return 1;
}
/* Calculate the offset from the optional second argument. */
if ((nn = n->parent->head->child) != NULL &&
(nn = nn->next) != NULL &&
a2roffsu(nn->string, &su, SCALE_EN) != NULL) {
- len = term_hspan(p, &su) / 24;
+ len = term_hen(p, &su);
if (len < 0 && (size_t)(-len) > mt->offset)
len = -mt->offset;
else if (len > SHRT_MAX)
len = term_len(p, p->defindent);
mt->lmargin[mt->lmargincur] = len;
} else
len = mt->lmargin[mt->lmargincur];
switch (n->type) {
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)
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;
}
return 1;
}
static void
post_IP(DECL_ARGS)
{
switch (n->type) {
case ROFFT_HEAD:
term_flushln(p);
p->flags &= ~TERMP_NOBREAK;
p->trailspace = 0;
p->tcol->rmargin = p->maxrmargin;
break;
case ROFFT_BODY:
term_newln(p);
p->tcol->offset = mt->offset;
break;
default:
break;
}
}
static int
pre_TP(DECL_ARGS)
{
struct roffsu su;
struct roff_node *nn;
int len, savelit;
switch (n->type) {
case ROFFT_HEAD:
p->flags |= TERMP_NOBREAK | TERMP_BRTRSP;
p->trailspace = 1;
break;
case ROFFT_BODY:
p->flags |= TERMP_NOSPACE;
break;
case ROFFT_BLOCK:
print_bvspace(p, n, mt->pardist);
/* FALLTHROUGH */
default:
return 1;
}
/* Calculate offset. */
if ((nn = n->parent->head->child) != NULL &&
nn->string != NULL && ! (NODE_LINE & nn->flags) &&
a2roffsu(nn->string, &su, SCALE_EN) != NULL) {
- len = term_hspan(p, &su) / 24;
+ len = term_hen(p, &su);
if (len < 0 && (size_t)(-len) > mt->offset)
len = -mt->offset;
else if (len > SHRT_MAX)
len = term_len(p, p->defindent);
mt->lmargin[mt->lmargincur] = len;
} else
len = mt->lmargin[mt->lmargincur];
switch (n->type) {
case ROFFT_HEAD:
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))
nn = nn->next;
while (NULL != nn) {
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;
p->tcol->rmargin = p->maxrmargin;
p->trailspace = 0;
p->flags &= ~(TERMP_NOBREAK | TERMP_BRTRSP);
break;
default:
break;
}
return 1;
}
static void
post_TP(DECL_ARGS)
{
switch (n->type) {
case ROFFT_HEAD:
term_flushln(p);
break;
case ROFFT_BODY:
term_newln(p);
p->tcol->offset = mt->offset;
break;
default:
break;
}
}
static int
pre_SS(DECL_ARGS)
{
int i;
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);
/*
* No vertical space before the first subsection
* and after an empty subsection.
*/
do {
n = n->prev;
} while (n != NULL && n->tok != TOKEN_NONE &&
termacts[n->tok].flags & MAN_NOTEXT);
if (n == NULL || (n->tok == MAN_SS && n->body->child == NULL))
break;
for (i = 0; i < mt->pardist; i++)
term_vspace(p);
break;
case ROFFT_HEAD:
term_fontrepl(p, TERMFONT_BOLD);
p->tcol->offset = term_len(p, 3);
p->tcol->rmargin = mt->offset;
p->trailspace = mt->offset;
p->flags |= TERMP_NOBREAK | TERMP_BRIND;
break;
case ROFFT_BODY:
p->tcol->offset = mt->offset;
p->tcol->rmargin = p->maxrmargin;
p->trailspace = 0;
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
break;
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)
{
int i;
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);
/*
* No vertical space before the first section
* and after an empty section.
*/
do {
n = n->prev;
} while (n != NULL && n->tok != TOKEN_NONE &&
termacts[n->tok].flags & MAN_NOTEXT);
if (n == NULL || (n->tok == MAN_SH && n->body->child == NULL))
break;
for (i = 0; i < mt->pardist; i++)
term_vspace(p);
break;
case ROFFT_HEAD:
term_fontrepl(p, TERMFONT_BOLD);
p->tcol->offset = 0;
p->tcol->rmargin = mt->offset;
p->trailspace = mt->offset;
p->flags |= TERMP_NOBREAK | TERMP_BRIND;
break;
case ROFFT_BODY:
p->tcol->offset = mt->offset;
p->tcol->rmargin = p->maxrmargin;
p->trailspace = 0;
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
break;
default:
break;
}
return 1;
}
static void
post_SH(DECL_ARGS)
{
switch (n->type) {
case ROFFT_HEAD:
term_newln(p);
break;
case ROFFT_BODY:
term_newln(p);
break;
default:
break;
}
}
static int
pre_RS(DECL_ARGS)
{
struct roffsu su;
switch (n->type) {
case ROFFT_BLOCK:
term_newln(p);
return 1;
case ROFFT_HEAD:
return 0;
default:
break;
}
n = n->parent->head;
n->aux = SHRT_MAX + 1;
if (n->child == NULL)
n->aux = mt->lmargin[mt->lmargincur];
else if (a2roffsu(n->child->string, &su, SCALE_EN) != NULL)
- n->aux = term_hspan(p, &su) / 24;
+ n->aux = term_hen(p, &su);
if (n->aux < 0 && (size_t)(-n->aux) > mt->offset)
n->aux = -mt->offset;
else if (n->aux > SHRT_MAX)
n->aux = term_len(p, p->defindent);
mt->offset += n->aux;
p->tcol->offset = mt->offset;
p->tcol->rmargin = p->maxrmargin;
if (++mt->lmarginsz < MAXMARGINS)
mt->lmargincur = mt->lmarginsz;
mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
return 1;
}
static void
post_RS(DECL_ARGS)
{
switch (n->type) {
case ROFFT_BLOCK:
return;
case ROFFT_HEAD:
return;
default:
term_newln(p);
break;
}
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)
{
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)
print_man_node(p, mt, n->child->child, meta);
p->flags |= TERMP_NOSPACE;
term_word(p, ">");
}
static void
print_man_node(DECL_ARGS)
{
int c;
switch (n->type) {
case ROFFT_TEXT:
/*
* If we have a blank line, output a vertical space.
* If we have a space as the first character, break
* before printing the line's data.
*/
if (*n->string == '\0') {
- term_vspace(p);
+ if (p->flags & TERMP_NONEWLINE)
+ term_newln(p);
+ else
+ term_vspace(p);
return;
} else if (*n->string == ' ' && n->flags & NODE_LINE &&
(p->flags & TERMP_NONEWLINE) == 0)
term_newln(p);
term_word(p, n->string);
goto out;
case ROFFT_EQN:
if ( ! (n->flags & NODE_LINE))
p->flags |= TERMP_NOSPACE;
term_eqn(p, n->eqn);
if (n->next != NULL && ! (n->next->flags & NODE_LINE))
p->flags |= TERMP_NOSPACE;
return;
case ROFFT_TBL:
if (p->tbl.cols == NULL)
term_vspace(p);
term_tbl(p, n->span);
return;
default:
break;
}
if (n->tok < ROFF_MAX) {
roff_term_pre(p, n);
return;
}
assert(n->tok >= MAN_TH && n->tok <= MAN_MAX);
if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
term_fontrepl(p, TERMFONT_NONE);
c = 1;
if (termacts[n->tok].pre)
c = (*termacts[n->tok].pre)(p, mt, n, meta);
if (c && n->child)
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))
term_fontrepl(p, TERMFONT_NONE);
out:
/*
* If we're in a literal context, make sure that words
* together on the same line stay together. This is a
* POST-printing call, so we check the NEXT word. Since
* -man doesn't have nested macros, we don't need to be
* more specific than this.
*/
if (mt->fl & MANT_LITERAL &&
! (p->flags & (TERMP_NOBREAK | TERMP_NONEWLINE)) &&
(n->next == NULL || n->next->flags & NODE_LINE)) {
p->flags |= TERMP_BRNEVER | TERMP_NOSPACE;
if (n->string != NULL && *n->string != '\0')
term_flushln(p);
else
term_newln(p);
p->flags &= ~TERMP_BRNEVER;
if (p->tcol->rmargin < p->maxrmargin &&
n->parent->tok == MAN_HP) {
p->tcol->offset = p->tcol->rmargin;
p->tcol->rmargin = p->maxrmargin;
}
}
if (NODE_EOS & n->flags)
p->flags |= TERMP_SENTENCE;
}
static void
print_man_nodelist(DECL_ARGS)
{
while (n != NULL) {
print_man_node(p, mt, n, meta);
n = n->next;
}
}
static void
print_man_foot(struct termp *p, const struct roff_meta *meta)
{
char *title;
size_t datelen, titlen;
assert(meta->title);
assert(meta->msec);
assert(meta->date);
term_fontrepl(p, TERMFONT_NONE);
if (meta->hasbody)
term_vspace(p);
/*
* Temporary, undocumented option to imitate mdoc(7) output.
* In the bottom right corner, use the operating system
* instead of the title.
*/
if ( ! p->mdocstyle) {
if (meta->hasbody) {
term_vspace(p);
term_vspace(p);
}
mandoc_asprintf(&title, "%s(%s)",
meta->title, meta->msec);
} else if (meta->os) {
title = mandoc_strdup(meta->os);
} else {
title = mandoc_strdup("");
}
datelen = term_strlen(p, meta->date);
/* Bottom left corner: operating system. */
p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
p->trailspace = 1;
p->tcol->offset = 0;
p->tcol->rmargin = p->maxrmargin > datelen ?
(p->maxrmargin + term_len(p, 1) - datelen) / 2 : 0;
if (meta->os)
term_word(p, meta->os);
term_flushln(p);
/* At the bottom in the middle: manual date. */
p->tcol->offset = p->tcol->rmargin;
titlen = term_strlen(p, title);
p->tcol->rmargin = p->maxrmargin > titlen ?
p->maxrmargin - titlen : 0;
p->flags |= TERMP_NOSPACE;
term_word(p, meta->date);
term_flushln(p);
/* Bottom right corner: manual title and section. */
p->flags &= ~TERMP_NOBREAK;
p->flags |= TERMP_NOSPACE;
p->trailspace = 0;
p->tcol->offset = p->tcol->rmargin;
p->tcol->rmargin = p->maxrmargin;
term_word(p, title);
term_flushln(p);
free(title);
}
static void
print_man_head(struct termp *p, const struct roff_meta *meta)
{
const char *volume;
char *title;
size_t vollen, titlen;
assert(meta->title);
assert(meta->msec);
volume = NULL == meta->vol ? "" : meta->vol;
vollen = term_strlen(p, volume);
/* Top left corner: manual title and section. */
mandoc_asprintf(&title, "%s(%s)", meta->title, meta->msec);
titlen = term_strlen(p, title);
p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
p->trailspace = 1;
p->tcol->offset = 0;
p->tcol->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ?
(p->maxrmargin - vollen + term_len(p, 1)) / 2 :
vollen < p->maxrmargin ? p->maxrmargin - vollen : 0;
term_word(p, title);
term_flushln(p);
/* At the top in the middle: manual volume. */
p->flags |= TERMP_NOSPACE;
p->tcol->offset = p->tcol->rmargin;
p->tcol->rmargin = p->tcol->offset + vollen + titlen <
p->maxrmargin ? p->maxrmargin - titlen : p->maxrmargin;
term_word(p, volume);
term_flushln(p);
/* Top right corner: title and section, again. */
p->flags &= ~TERMP_NOBREAK;
p->trailspace = 0;
if (p->tcol->rmargin + titlen <= p->maxrmargin) {
p->flags |= TERMP_NOSPACE;
p->tcol->offset = p->tcol->rmargin;
p->tcol->rmargin = p->maxrmargin;
term_word(p, title);
term_flushln(p);
}
p->flags &= ~TERMP_NOSPACE;
p->tcol->offset = 0;
p->tcol->rmargin = p->maxrmargin;
/*
* Groff prints three blank lines before the content.
* Do the same, except in the temporary, undocumented
* mode imitating mdoc(7) output.
*/
term_vspace(p);
if ( ! p->mdocstyle) {
term_vspace(p);
term_vspace(p);
}
free(title);
}
Index: vendor/mdocml/dist/man_validate.c
===================================================================
--- vendor/mdocml/dist/man_validate.c (revision 321806)
+++ vendor/mdocml/dist/man_validate.c (revision 321807)
@@ -1,465 +1,494 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons
* Copyright (c) 2010, 2012-2017 Ingo Schwarze
*
* 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
#include
#include
#include
#include
#include
#include
#include
#include
#include "mandoc_aux.h"
#include "mandoc.h"
#include "roff.h"
#include "man.h"
#include "libmandoc.h"
#include "roff_int.h"
#include "libman.h"
#define CHKARGS struct roff_man *man, struct roff_node *n
typedef void (*v_check)(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_IP(CHKARGS);
-static void post_vs(CHKARGS);
static void post_OP(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] = {
post_TH, /* TH */
NULL, /* SH */
NULL, /* SS */
NULL, /* TP */
check_par, /* LP */
check_par, /* PP */
check_par, /* P */
post_IP, /* IP */
NULL, /* HP */
NULL, /* SM */
NULL, /* SB */
NULL, /* BI */
NULL, /* IB */
NULL, /* BR */
NULL, /* RB */
NULL, /* R */
NULL, /* B */
NULL, /* I */
NULL, /* IR */
NULL, /* RI */
NULL, /* nf */
NULL, /* fi */
NULL, /* RE */
check_part, /* RS */
NULL, /* DT */
post_UC, /* UC */
NULL, /* PD */
post_AT, /* AT */
- NULL, /* in */
+ post_in, /* in */
post_OP, /* OP */
NULL, /* EX */
NULL, /* EE */
post_UR, /* UR */
NULL, /* UE */
+ post_UR, /* MT */
+ NULL, /* ME */
};
static const v_check *man_valids = __man_valids - MAN_TH;
void
man_node_validate(struct roff_man *man)
{
struct roff_node *n;
const v_check *cp;
n = man->last;
man->last = man->last->child;
while (man->last != NULL) {
man_node_validate(man);
if (man->last == n)
man->last = man->last->child;
else
man->last = man->last->next;
}
man->last = n;
man->next = ROFF_NEXT_SIBLING;
switch (n->type) {
case ROFFT_TEXT:
check_text(man, n);
break;
case ROFFT_ROOT:
check_root(man, n);
break;
case ROFFT_EQN:
case ROFFT_TBL:
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;
}
break;
}
assert(n->tok >= MAN_TH && n->tok < MAN_MAX);
cp = man_valids + n->tok;
if (*cp)
(*cp)(man, n);
if (man->last == n)
man_state(man, n);
break;
}
}
static void
check_root(CHKARGS)
{
assert((man->flags & (MAN_BLINE | MAN_ELINE)) == 0);
if (NULL == man->first->child)
mandoc_msg(MANDOCERR_DOC_EMPTY, man->parse,
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);
/*
* If a title hasn't been set, do so now (by
* implication, date and section also aren't set).
*/
man->meta.title = mandoc_strdup("");
man->meta.msec = mandoc_strdup("");
man->meta.date = man->quick ? mandoc_strdup("") :
- mandoc_normdate(man->parse, NULL, n->line, n->pos);
+ mandoc_normdate(man, NULL, n->line, n->pos);
}
+
+ if (man->meta.os_e &&
+ (man->meta.rcsids & (1 << man->meta.os_e)) == 0)
+ mandoc_msg(MANDOCERR_RCS_MISSING, man->parse, 0, 0,
+ man->meta.os_e == MANDOC_OS_OPENBSD ?
+ "(OpenBSD)" : "(NetBSD)");
}
static void
check_text(CHKARGS)
{
char *cp, *p;
if (MAN_LITERAL & man->flags)
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);
}
static void
post_OP(CHKARGS)
{
if (n->child == NULL)
mandoc_msg(MANDOCERR_OP_EMPTY, man->parse,
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,
n->line, n->pos, "OP ... %s", n->string);
}
}
static void
post_UR(CHKARGS)
{
-
if (n->type == ROFFT_HEAD && n->child == NULL)
- mandoc_vmsg(MANDOCERR_UR_NOHEAD, man->parse,
- n->line, n->pos, "UR");
+ mandoc_msg(MANDOCERR_UR_NOHEAD, man->parse,
+ n->line, n->pos, roff_name[n->tok]);
check_part(man, n);
}
static void
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]);
}
static void
check_par(CHKARGS)
{
switch (n->type) {
case ROFFT_BLOCK:
if (n->body->child == NULL)
roff_node_delete(man, n);
break;
case ROFFT_BODY:
if (n->child == NULL)
mandoc_vmsg(MANDOCERR_PAR_SKIP,
man->parse, 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",
roff_name[n->tok], n->child->string,
n->child->next != NULL ? " ..." : "");
break;
default:
break;
}
}
static void
post_IP(CHKARGS)
{
switch (n->type) {
case ROFFT_BLOCK:
if (n->head->child == NULL && n->body->child == NULL)
roff_node_delete(man, n);
break;
case ROFFT_BODY:
if (n->parent->head->child == NULL && n->child == NULL)
mandoc_vmsg(MANDOCERR_PAR_SKIP,
man->parse, n->line, n->pos,
"%s empty", roff_name[n->tok]);
break;
default:
break;
}
}
static void
post_TH(CHKARGS)
{
struct roff_node *nb;
const char *p;
free(man->meta.title);
free(man->meta.vol);
free(man->meta.os);
free(man->meta.msec);
free(man->meta.date);
man->meta.title = man->meta.vol = man->meta.date =
man->meta.msec = man->meta.os = NULL;
nb = n;
/* ->TITLE<- MSEC DATE OS VOL */
n = n->child;
if (n && n->string) {
for (p = n->string; '\0' != *p; p++) {
/* 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),
"TH %s", n->string);
break;
}
}
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");
}
/* TITLE ->MSEC<- DATE OS VOL */
if (n)
n = n->next;
if (n && n->string)
man->meta.msec = mandoc_strdup(n->string);
else {
man->meta.msec = mandoc_strdup("");
mandoc_vmsg(MANDOCERR_MSEC_MISSING, man->parse,
nb->line, nb->pos, "TH %s", man->meta.title);
}
/* TITLE MSEC ->DATE<- OS VOL */
if (n)
n = n->next;
if (n && n->string && '\0' != n->string[0]) {
man->meta.date = man->quick ?
mandoc_strdup(n->string) :
- mandoc_normdate(man->parse, n->string,
- n->line, n->pos);
+ mandoc_normdate(man, n->string, n->line, n->pos);
} else {
man->meta.date = mandoc_strdup("");
mandoc_msg(MANDOCERR_DATE_MISSING, man->parse,
n ? n->line : nb->line,
n ? n->pos : nb->pos, "TH");
}
/* TITLE MSEC DATE ->OS<- VOL */
if (n && (n = n->next))
man->meta.os = mandoc_strdup(n->string);
- else if (man->defos != NULL)
- man->meta.os = mandoc_strdup(man->defos);
+ else if (man->os_s != NULL)
+ man->meta.os = mandoc_strdup(man->os_s);
+ if (man->meta.os_e == MANDOC_OS_OTHER && man->meta.os != NULL) {
+ if (strstr(man->meta.os, "OpenBSD") != NULL)
+ man->meta.os_e = MANDOC_OS_OPENBSD;
+ else if (strstr(man->meta.os, "NetBSD") != NULL)
+ man->meta.os_e = MANDOC_OS_NETBSD;
+ }
/* TITLE MSEC DATE OS ->VOL<- */
/* If missing, use the default VOL name for MSEC. */
if (n && (n = n->next))
man->meta.vol = mandoc_strdup(n->string);
else if ('\0' != man->meta.msec[0] &&
(NULL != (p = mandoc_a2msec(man->meta.msec))))
man->meta.vol = mandoc_strdup(p);
if (n != NULL && (n = n->next) != NULL)
mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse,
n->line, n->pos, "TH ... %s", n->string);
/*
* Remove the `TH' node after we've processed it for our
* meta-data.
*/
roff_node_delete(man, man->last);
}
static void
post_UC(CHKARGS)
{
static const char * const bsd_versions[] = {
"3rd Berkeley Distribution",
"4th Berkeley Distribution",
"4.2 Berkeley Distribution",
"4.3 Berkeley Distribution",
"4.4 Berkeley Distribution",
};
const char *p, *s;
n = n->child;
if (n == NULL || n->type != ROFFT_TEXT)
p = bsd_versions[0];
else {
s = n->string;
if (0 == strcmp(s, "3"))
p = bsd_versions[0];
else if (0 == strcmp(s, "4"))
p = bsd_versions[1];
else if (0 == strcmp(s, "5"))
p = bsd_versions[2];
else if (0 == strcmp(s, "6"))
p = bsd_versions[3];
else if (0 == strcmp(s, "7"))
p = bsd_versions[4];
else
p = bsd_versions[0];
}
free(man->meta.os);
man->meta.os = mandoc_strdup(p);
}
static void
post_AT(CHKARGS)
{
static const char * const unix_versions[] = {
"7th Edition",
"System III",
"System V",
"System V Release 2",
};
struct roff_node *nn;
const char *p, *s;
n = n->child;
if (n == NULL || n->type != ROFFT_TEXT)
p = unix_versions[0];
else {
s = n->string;
if (0 == strcmp(s, "3"))
p = unix_versions[0];
else if (0 == strcmp(s, "4"))
p = unix_versions[1];
else if (0 == strcmp(s, "5")) {
nn = n->next;
if (nn != NULL &&
nn->type == ROFFT_TEXT &&
nn->string[0] != '\0')
p = unix_versions[3];
else
p = unix_versions[2];
} else
p = unix_versions[0];
}
free(man->meta.os);
man->meta.os = mandoc_strdup(p);
+}
+
+static void
+post_in(CHKARGS)
+{
+ char *s;
+
+ if (n->parent->tok != MAN_TP ||
+ n->parent->type != ROFFT_HEAD ||
+ n->child == NULL ||
+ *n->child->string == '+' ||
+ *n->child->string == '-')
+ return;
+ mandoc_asprintf(&s, "+%s", n->child->string);
+ 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;
}
}
Index: vendor/mdocml/dist/manconf.h
===================================================================
--- vendor/mdocml/dist/manconf.h (revision 321806)
+++ vendor/mdocml/dist/manconf.h (revision 321807)
@@ -1,49 +1,50 @@
-/* $OpenBSD$ */
+/* $Id: manconf.h,v 1.5 2017/07/01 09:47:30 schwarze Exp $ */
/*
- * Copyright (c) 2011, 2015 Ingo Schwarze
+ * Copyright (c) 2011, 2015, 2017 Ingo Schwarze
* Copyright (c) 2011 Kristaps Dzonsons
*
* 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.
*/
/* List of unique, absolute paths to manual trees. */
struct manpaths {
char **paths;
size_t sz;
};
/* Data from -O options and man.conf(5) output directives. */
struct manoutput {
char *includes;
char *man;
char *paper;
char *style;
size_t indent;
size_t width;
int fragment;
int mdoc;
int synopsisonly;
int noval;
};
struct manconf {
struct manoutput output;
struct manpaths manpath;
};
void manconf_parse(struct manconf *, const char *, char *, char *);
int manconf_output(struct manoutput *, const char *, int);
void manconf_free(struct manconf *);
+void manpath_base(struct manpaths *);
Index: vendor/mdocml/dist/mandoc.1
===================================================================
--- vendor/mdocml/dist/mandoc.1 (revision 321806)
+++ vendor/mdocml/dist/mandoc.1 (revision 321807)
@@ -1,1972 +1,2140 @@
-.\" $Id: mandoc.1,v 1.196 2017/06/08 00:23:30 schwarze Exp $
+.\" $Id: mandoc.1,v 1.217 2017/07/20 15:26:41 schwarze Exp $
.\"
.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons
.\" Copyright (c) 2012, 2014-2017 Ingo Schwarze
.\"
.\" 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.
.\"
-.Dd $Mdocdate: June 8 2017 $
+.Dd $Mdocdate: July 20 2017 $
.Dt MANDOC 1
.Os
.Sh NAME
.Nm mandoc
.Nd format manual pages
.Sh SYNOPSIS
.Nm mandoc
.Op Fl ac
.Op Fl I Cm os Ns = Ns Ar name
.Op Fl K Ar encoding
.Op Fl mdoc | man
.Op Fl O Ar options
.Op Fl T Ar output
.Op Fl W Ar level
.Op Ar
.Sh DESCRIPTION
The
.Nm
utility formats
.Ux
manual pages for display.
.Pp
By default,
.Nm
reads
.Xr mdoc 7
or
.Xr man 7
text from stdin and produces
.Fl T Cm locale
output.
.Pp
The options are as follows:
.Bl -tag -width Ds
.It Fl a
If the standard output is a terminal device and
.Fl c
is not specified, use
.Xr more 1
to paginate the output, just like
.Xr man 1
would.
.It Fl c
Copy the formatted manual pages to the standard output without using
.Xr more 1
to paginate them.
This is the default.
It can be specified to override
.Fl a .
.It Fl I Cm os Ns = Ns Ar name
Override the default operating system
.Ar name
for the
.Xr mdoc 7
.Ic \&Os
and for the
.Xr man 7
.Ic \&TH
macro.
-This can also be used to perform style checks according to the
-conventions of one operating system while running on a different
-operating system; see
-.Sx Style messages
-for details.
.It Fl K Ar encoding
Specify the input encoding.
The supported
.Ar encoding
arguments are
.Cm us-ascii ,
.Cm iso-8859-1 ,
and
.Cm utf-8 .
If not specified, autodetection uses the first match in the following
list:
.Bl -enum
.It
If the first three bytes of the input file are the UTF-8 byte order
mark (BOM, 0xefbbbf), input is interpreted as
.Cm utf-8 .
.It
If the first or second line of the input file matches the
.Sy emacs
mode line format
.Pp
.D1 .\e" -*- Oo ...; Oc coding: Ar encoding ; No -*-
.Pp
then input is interpreted according to
.Ar encoding .
.It
If the first non-ASCII byte in the file introduces a valid UTF-8
sequence, input is interpreted as
.Cm utf-8 .
.It
Otherwise, input is interpreted as
.Cm iso-8859-1 .
.El
.It Fl mdoc | man
With
.Fl mdoc ,
all input files are interpreted as
.Xr mdoc 7 .
With
.Fl man ,
all input files are interpreted as
.Xr man 7 .
By default, the input language is automatically detected for each file:
if the the first macro is
.Ic \&Dd
or
.Ic \&Dt ,
the
.Xr mdoc 7
parser is used; otherwise, the
.Xr man 7
parser is used.
With other arguments,
.Fl m
is silently ignored.
.It Fl O Ar options
Comma-separated output options.
.It Fl T Ar output
Output format.
See
.Sx Output Formats
for available formats.
Defaults to
.Fl T Cm locale .
.It Fl W Ar level
Specify the minimum message
.Ar level
to be reported on the standard error output and to affect the exit status.
The
.Ar level
can be
+.Cm base ,
.Cm style ,
.Cm warning ,
.Cm error ,
or
-.Cm unsupp ;
+.Cm unsupp .
+The
+.Cm base
+level automatically derives the operating system from the contents of the
+.Ic \&Os
+macro, from the
+.Fl Ios
+command line option, or from the
+.Xr uname 3
+return value.
+The levels
+.Cm openbsd
+and
+.Cm netbsd
+are variants of
+.Cm base
+that bypass autodetection and request validation of base system
+conventions for a particular operating system.
+The level
.Cm all
is an alias for
-.Cm style .
+.Cm base .
By default,
.Nm
is silent.
See
.Sx EXIT STATUS
and
.Sx DIAGNOSTICS
for details.
.Pp
The special option
.Fl W Cm stop
tells
.Nm
to exit after parsing a file that causes warnings or errors of at least
the requested level.
No formatted output will be produced from that file.
If both a
.Ar level
and
.Cm stop
are requested, they can be joined with a comma, for example
.Fl W Cm error , Ns Cm stop .
.It Ar file
Read input from zero or more files.
If unspecified, reads from stdin.
If multiple files are specified,
.Nm
will halt with the first failed parse.
.El
.Pp
The options
.Fl fhklw
are also supported and are documented in man(1).
In
.Fl f
and
.Fl k
mode,
.Nm
also supports the options
.Fl CMmOSs
described in the
.Xr apropos 1
manual.
The options
.Fl fkl
are mutually exclusive and override each other.
.Ss Output Formats
The
.Nm
utility accepts the following
.Fl T
arguments, which correspond to output modes:
.Bl -tag -width "-T markdown"
.It Fl T Cm ascii
Produce 7-bit ASCII output.
See
.Sx ASCII Output .
.It Fl T Cm html
Produce HTML5, CSS1, and MathML output.
See
.Sx HTML Output .
.It Fl T Cm lint
Parse only: produce no output.
Implies
-.Fl W Cm style .
+.Fl W Cm all
+and redirects parser messages, which usually appear
+on standard error output, to standard output.
.It Fl T Cm locale
Encode output using the current locale.
This is the default.
See
.Sx Locale Output .
.It Fl T Cm man
Produce
.Xr man 7
format output.
See
.Sx Man Output .
.It Fl T Cm markdown
Produce output in
.Sy markdown
format.
See
.Sx Markdown Output .
.It Fl T Cm pdf
Produce PDF output.
See
.Sx PDF Output .
.It Fl T Cm ps
Produce PostScript output.
See
.Sx PostScript Output .
.It Fl T Cm tree
Produce an indented parse tree.
See
.Sx Syntax tree output .
.It Fl T Cm utf8
Encode output in the UTF\-8 multi-byte format.
See
.Sx UTF\-8 Output .
.El
.Pp
If multiple input files are specified, these will be processed by the
corresponding filter in-order.
.Ss ASCII Output
Output produced by
.Fl T Cm ascii
is rendered in standard 7-bit ASCII documented in
.Xr ascii 7 .
.Pp
Font styles are applied by using back-spaced encoding such that an
underlined character
.Sq c
is rendered as
.Sq _ Ns \e[bs] Ns c ,
where
.Sq \e[bs]
is the back-space character number 8.
Emboldened characters are rendered as
.Sq c Ns \e[bs] Ns c .
.Pp
The special characters documented in
.Xr mandoc_char 7
are rendered best-effort in an ASCII equivalent.
.Pp
Output width is limited to 78 visible columns unless literal input lines
exceed this limit.
.Pp
The following
.Fl O
arguments are accepted:
.Bl -tag -width Ds
.It Cm indent Ns = Ns Ar indent
The left margin for normal text is set to
.Ar indent
blank characters instead of the default of five for
.Xr mdoc 7
and seven for
.Xr man 7 .
Increasing this is not recommended; it may result in degraded formatting,
for example overfull lines or ugly line breaks.
.It Cm width Ns = Ns Ar width
The output width is set to
-.Ar width ,
-which will normalise to \(>=58.
+.Ar width .
.El
.Ss HTML Output
Output produced by
.Fl T Cm html
conforms to HTML5 using optional self-closing tags.
Default styles use only CSS1.
Equations rendered from
.Xr eqn 7
blocks use MathML.
.Pp
The
.Pa mandoc.css
file documents style-sheet classes available for customising output.
If a style-sheet is not specified with
.Fl O Cm style ,
.Fl T Cm html
defaults to simple output (via an embedded style-sheet)
readable in any graphical or text-based web
browser.
.Pp
Special characters are rendered in decimal-encoded UTF\-8.
.Pp
The following
.Fl O
arguments are accepted:
.Bl -tag -width Ds
.It Cm fragment
Omit the declaration and the , , and
elements and only emit the subtree below the element.
The
.Cm style
argument will be ignored.
This is useful when embedding manual content within existing documents.
.It Cm includes Ns = Ns Ar fmt
The string
.Ar fmt ,
for example,
.Ar ../src/%I.html ,
is used as a template for linked header files (usually via the
.Ic \&In
macro).
Instances of
.Sq \&%I
are replaced with the include filename.
The default is not to present a
hyperlink.
.It Cm man Ns = Ns Ar fmt
The string
.Ar fmt ,
for example,
.Ar ../html%S/%N.%S.html ,
is used as a template for linked manuals (usually via the
.Ic \&Xr
macro).
Instances of
.Sq \&%N
and
.Sq %S
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.
.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.
.El
.Ss Locale Output
Locale-depending output encoding is triggered with
.Fl T Cm locale .
This is the default.
.Pp
This option is not available on all systems: systems without locale
support, or those whose internal representation is not natively UCS-4,
will fall back to
.Fl T Cm ascii .
See
.Sx ASCII Output
for font style specification and available command-line arguments.
.Ss Man Output
Translate input format into
.Xr man 7
output format.
This is useful for distributing manual sources to legacy systems
lacking
.Xr mdoc 7
formatters.
.Pp
If
.Xr mdoc 7
is passed as input, it is translated into
.Xr man 7 .
If the input format is
.Xr man 7 ,
the input is copied to the output, expanding any
.Xr roff 7
.Ic so
requests.
The parser is also run, and as usual, the
.Fl W
level controls which
.Sx DIAGNOSTICS
are displayed before copying the input to the output.
.Ss Markdown Output
Translate
.Xr mdoc 7
input to the
.Sy markdown
format conforming to
.Lk http://daringfireball.net/projects/markdown/syntax.text\
"John Gruber's 2004 specification" .
The output also almost conforms to the
.Lk http://commonmark.org/ CommonMark
specification.
.Pp
The character set used for the markdown output is ASCII.
Non-ASCII characters are encoded as HTML entities.
Since that is not possible in literal font contexts, because these
are rendered as code spans and code blocks in the markdown output,
non-ASCII characters are transliterated to ASCII approximations in
these contexts.
.Pp
Markdown is a very weak markup language, so all semantic markup is
lost, and even part of the presentational markup may be lost.
Do not use this as an intermediate step in converting to HTML;
instead, use
.Fl T Cm html
directly.
.Pp
The
.Xr man 7 ,
.Xr tbl 7 ,
and
.Xr eqn 7
input languages are not supported by
.Fl T Cm markdown
output mode.
.Ss PDF Output
PDF-1.1 output may be generated by
.Fl T Cm pdf .
See
.Sx PostScript Output
for
.Fl O
arguments and defaults.
.Ss PostScript Output
PostScript
.Qq Adobe-3.0
Level-2 pages may be generated by
.Fl T Cm ps .
Output pages default to letter sized and are rendered in the Times font
family, 11-point.
Margins are calculated as 1/9 the page length and width.
Line-height is 1.4m.
.Pp
Special characters are rendered as in
.Sx ASCII Output .
.Pp
The following
.Fl O
arguments are accepted:
.Bl -tag -width Ds
.It Cm paper Ns = Ns Ar name
The paper size
.Ar name
may be one of
.Ar a3 ,
.Ar a4 ,
.Ar a5 ,
.Ar legal ,
or
.Ar letter .
You may also manually specify dimensions as
.Ar NNxNN ,
width by height in millimetres.
If an unknown value is encountered,
.Ar letter
is used.
.El
.Ss UTF\-8 Output
Use
.Fl T Cm utf8
to force a UTF\-8 locale.
See
.Sx Locale Output
for details and options.
.Ss Syntax tree output
Use
.Fl T Cm tree
to show a human readable representation of the syntax tree.
It is useful for debugging the source code of manual pages.
The exact format is subject to change, so don't write parsers for it.
.Pp
The first paragraph shows meta data found in the
.Xr mdoc 7
prologue, on the
.Xr man 7
.Ic \&TH
line, or the fallbacks used.
.Pp
In the tree dump, each output line shows one syntax tree node.
Child nodes are indented with respect to their parent node.
The columns are:
.Pp
.Bl -enum -compact
.It
For macro nodes, the macro name; for text and
.Xr tbl 7
nodes, the content.
There is a special format for
.Xr eqn 7
nodes.
.It
Node type (text, elem, block, head, body, body-end, tail, tbl, eqn).
.It
Flags:
.Bl -dash -compact
.It
An opening parenthesis if the node is an opening delimiter.
.It
An asterisk if the node starts a new input line.
.It
The input line number (starting at one).
.It
A colon.
.It
The input column number (starting at one).
.It
A closing parenthesis if the node is a closing delimiter.
.It
A full stop if the node ends a sentence.
.It
BROKEN if the node is a block broken by another block.
.It
NOSRC if the node is not in the input file,
but automatically generated from macros.
.It
NOPRT if the node is not supposed to generate output
for any output format.
.El
.El
.Pp
The following
.Fl O
argument is accepted:
.Bl -tag -width Ds
.It Cm noval
Skip validation and show the unvalidated syntax tree.
This can help to find out whether a given behaviour is caused by
the parser or by the validator.
Meta data is not available in this case.
.El
.Sh ENVIRONMENT
.Bl -tag -width MANPAGER
.It Ev MANPAGER
Any non-empty value of the environment variable
.Ev MANPAGER
is used instead of the standard pagination program,
.Xr more 1 ;
see
.Xr man 1
for details.
Only used if
.Fl a
or
.Fl l
is specified.
.It Ev PAGER
Specifies the pagination program to use when
.Ev MANPAGER
is not defined.
If neither PAGER nor MANPAGER is defined,
.Xr more 1
.Fl s
is used.
Only used if
.Fl a
or
.Fl l
is specified.
.El
.Sh EXIT STATUS
The
.Nm
utility exits with one of the following values, controlled by the message
.Ar level
associated with the
.Fl W
option:
.Pp
.Bl -tag -width Ds -compact
.It 0
-No style suggestions, warnings or errors occurred, or those that
-did were ignored because they were lower than the requested
+No base system convention violations, style suggestions, warnings,
+or errors occurred, or those that did were ignored because they
+were lower than the requested
.Ar level .
.It 1
-At least one style suggestion occurred, but no warning or error, and
+At least one base system convention violation or style suggestion
+occurred, but no warning or error, and
+.Fl W Cm base
+or
.Fl W Cm style
was specified.
.It 2
At least one warning occurred, but no error, and
.Fl W Cm warning
-or
-.Fl W Cm style
-was specified.
+or a lower
+.Ar level
+was requested.
.It 3
At least one parsing error occurred,
but no unsupported feature was encountered, and
.Fl W Cm error
or a lower
.Ar level
was requested.
.It 4
At least one unsupported feature was encountered, and
.Fl W Cm unsupp
or a lower
.Ar level
was requested.
.It 5
Invalid command line arguments were specified.
No input files have been read.
.It 6
An operating system error occurred, for example exhaustion
of memory, file descriptors, or process table entries.
Such errors cause
.Nm
to exit at once, possibly in the middle of parsing or formatting a file.
.El
.Pp
Note that selecting
.Fl T Cm lint
output mode implies
-.Fl W Cm style .
+.Fl W Cm all .
.Sh EXAMPLES
To page manuals to the terminal:
.Pp
.Dl $ mandoc -l mandoc.1 man.1 apropos.1 makewhatis.8
.Pp
To produce HTML manuals with
.Pa mandoc.css
as the style-sheet:
.Pp
.Dl $ mandoc \-T html -O style=mandoc.css mdoc.7 \*(Gt mdoc.7.html
.Pp
To check over a large set of manuals:
.Pp
.Dl $ mandoc \-T lint \(gafind /usr/src -name \e*\e.[1-9]\(ga
.Pp
To produce a series of PostScript manuals for A4 paper:
.Pp
.Dl $ mandoc \-T ps \-O paper=a4 mdoc.7 man.7 \*(Gt manuals.ps
.Pp
Convert a modern
.Xr mdoc 7
manual to the older
.Xr man 7
format, for use on systems lacking an
.Xr mdoc 7
parser:
.Pp
.Dl $ mandoc \-T man foo.mdoc \*(Gt 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
+.Pq Ar os
+.Ed
.Pp
-.D1 Nm Ns : Ar file : Ns Ar line : Ns Ar column : level : message : macro args
-.Pp
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.
+The
+.Ar os
+operating system specifier is omitted for messages that are relevant
+for all operating systems.
Fatal messages about invalid command line arguments
or operating system errors, for example when memory is exhausted,
may also omit the
.Ar file
and
.Ar level
fields.
.Pp
Message levels have the following meanings:
.Bl -tag -width "warning"
.It Cm unsupp
An input file uses unsupported low-level
.Xr roff 7
features.
The output may be incomplete and/or misformatted,
so using GNU troff instead of
.Nm
to process the file may be preferable.
.It Cm error
-An input file contains invalid syntax that cannot be safely interpreted.
-By discarding part of the input or inserting missing tokens,
-the parser is able to continue, and the error does not prevent
-generation of formatted output, but typically, preparing that
-output involves information loss, broken document structure
-or unintended formatting, no matter whether
-.Nm
-or GNU troff is used.
-In many cases, the output of
-.Nm
-and GNU troff is identical, but in some,
-.Nm
-is more resilient than GNU troff with respect to malformed input.
-.Pp
-Non-existent or unreadable input files are also reported on the
-.Cm error
-level.
-In that case, the parser cannot even be started and no output
-is produced from those input files.
+Indicates a risk of information loss or severe misformatting,
+in most cases caused by serious syntax errors.
.It Cm warning
-An input file uses obsolete, discouraged or non-portable syntax.
-All the same, the meaning of the input is unambiguous and a correct
-rendering can be produced.
-Documents causing warnings may render poorly when using other
-formatting tools instead of
-.Nm .
+Indicates a risk that the information shown or its formatting
+may mismatch the author's intent in minor ways.
+Additionally, syntax errors are classified at least as warnings,
+even if they do not usually cause misformatting.
.It Cm style
An input file uses dubious or discouraged style.
This is not a complaint about the syntax, and probably neither
formatting nor portability are in danger.
While great care is taken to avoid false positives on the higher
message levels, the
.Cm style
level tries to reduce the probability that issues go unnoticed,
so it may occasionally issue bogus suggestions.
Please use your good judgement to decide whether any particular
.Cm style
suggestion really justifies a change to the input file.
+.It Cm base
+A convertion used in the base system of a specific operating system
+is not adhered to.
+These are not markup mistakes, and neither the quality of formatting
+nor portability are in danger.
+Messages of the
+.Cm base
+level are printed with the more intuitive
+.Cm style
+.Ar level
+tag.
.El
.Pp
Messages of the
+.Cm base ,
.Cm style ,
.Cm warning ,
.Cm error ,
and
.Cm unsupp
levels except those about non-existent or unreadable input files
are hidden unless their level, or a lower level, is requested using a
.Fl W
option or
.Fl T Cm lint
output mode.
-.Ss Style messages
-As indicated below, some style checks are only performed if a
-specific operating system name occurs in the arguments of the
+.Pp
+As indicated below, all
+.Cm base
+and some
+.Cm style
+checks are only performed if a specific operating system name occurs
+in the arguments of the
+.Fl W
+command line option, of the
.Ic \&Os
macro, of the
.Fl Ios
command line option, or, if neither are present, in the return value
of the
.Xr uname 3
function.
+.Ss Conventions for base system manuals
.Bl -ohang
+.It Sy "Mdocdate found"
+.Pq mdoc , Nx
+The
+.Ic \&Dd
+macro uses CVS
+.Ic Mdocdate
+keyword substitution, which is not supported by the
+.Nx
+base system.
+Consider using the conventional
+.Dq "Month dd, yyyy"
+format instead.
+.It Sy "Mdocdate missing"
+.Pq mdoc , Ox
+The
+.Ic \&Dd
+macro does not use CVS
+.Ic Mdocdate
+keyword substitution, but using it is conventionally expected in the
+.Ox
+base system.
+.It Sy "unknown architecture"
+.Pq mdoc , Ox , Nx
+The third argument of the
+.Ic \&Dt
+macro does not match any of the architectures this operating system
+is running on.
+.It Sy "operating system explicitly specified"
+.Pq mdoc , Ox , Nx
+The
+.Ic \&Os
+macro has an argument.
+In the base system, it is conventionally left blank.
+.It Sy "RCS id missing"
+.Pq Ox , Nx
+The manual page lacks the comment line with the RCS identifier
+generated by CVS
+.Ic OpenBSD
+or
+.Ic NetBSD
+keyword substitution as conventionally used in these operating systems.
+.It Sy "referenced manual not found"
+.Pq mdoc
+An
+.Ic \&Xr
+macro references a manual page that is not found in the base system.
+The path to look for base system manuals is configurable at compile
+time and defaults to
+.Pa /usr/share/man : /usr/X11R6/man .
+.El
+.Ss Style suggestions
+.Bl -ohang
+.It Sy "legacy man(7) date format"
+.Pq mdoc
+The
+.Ic \&Dd
+macro uses the legacy
+.Xr man 7
+date format
+.Dq yyyy-dd-mm .
+Consider using the conventional
+.Xr mdoc 7
+date format
+.Dq "Month dd, yyyy"
+instead.
+.It Sy "lower case character in document title"
+.Pq mdoc , man
+The title is still used as given in the
+.Ic \&Dt
+or
+.Ic \&TH
+macro.
+.It Sy "duplicate RCS id"
+A single manual page contains two copies of the RCS identifier for
+the same operating system.
+Consider deleting the later instance and moving the first one up
+to the top of the page.
+.It Sy "typo in section name"
+.Pq mdoc
+Fuzzy string matching revealed that the argument of an
+.Ic \&Sh
+macro is similar, but not identical to a standard section name.
+.It Sy "unterminated quoted argument"
+.Pq roff
+Macro arguments can be enclosed in double quote characters
+such that space characters and macro names contained in the quoted
+argument need not be escaped.
+The closing quote of the last argument of a macro can be omitted.
+However, omitting it is not recommended because it makes the code
+harder to read.
.It Sy "useless macro"
.Pq mdoc
A
.Ic \&Bt ,
.Ic \&Tn ,
or
.Ic \&Ud
macro was found.
Simply delete it: it serves no useful purpose.
.It Sy "consider using OS macro"
.Pq mdoc
A string was found in plain text or in a
.Ic \&Bx
macro that could be represented using
.Ic \&Ox ,
.Ic \&Nx ,
.Ic \&Fx ,
or
.Ic \&Dx .
.It Sy "errnos out of order"
.Pq mdoc, Nx
The
.Ic \&Er
items in a
.Ic \&Bl
list are not in alphabetical order.
.It Sy "duplicate errno"
.Pq mdoc, Nx
A
.Ic \&Bl
list contains two consecutive
.Ic \&It
entries describing the same
.Ic \&Er
number.
-.It Sy "description line ends with a full stop"
+.It Sy "trailing delimiter"
.Pq mdoc
-Do not use punctuation at the end of an
-.Ic \&Nd
-block.
+The last argument of an
+.Ic \&Ex , \&Fo , \&Nd , \&Nm , \&Os , \&Sh , \&Ss , \&St ,
+or
+.Ic \&Sx
+macro ends with a trailing delimiter.
+This is usually bad style and often indicates typos.
+Most likely, the delimiter can be removed.
+.It Sy "no blank before trailing delimiter"
+.Pq mdoc
+The last argument of a macro that supports trailing delimiter
+arguments is longer than one byte and ends with a trailing delimiter.
+Consider inserting a blank such that the delimiter becomes a separate
+argument, thus moving it out of the scope of the macro.
+.It Sy "fill mode already enabled, skipping"
+.Pq man
+A
+.Ic \&fi
+request occurs even though the document is still in fill mode,
+or already switched back to fill mode.
+It has no effect.
+.It Sy "fill mode already disabled, skipping"
+.Pq man
+An
+.Ic \&nf
+request occurs even though the document already switched to no-fill mode
+and did not switch back to fill mode yet.
+It has no effect.
+.It Sy "function name without markup"
+.Pq mdoc
+A word followed by an empty pair of parentheses occurs on a text line.
+Consider using an
+.Ic \&Fn
+or
+.Ic \&Xr
+macro.
+.It Sy "whitespace at end of input line"
+.Pq mdoc , man , roff
+Whitespace at the end of input lines is almost never semantically
+significant \(em but in the odd case where it might be, it is
+extremely confusing when reviewing and maintaining documents.
+.It Sy "bad comment style"
+.Pq roff
+Comment lines start with a dot, a backslash, and a double-quote character.
+The
+.Nm
+utility treats the line as a comment line even without the backslash,
+but leaving out the backslash might not be portable.
.El
.Ss Warnings related to the document prologue
.Bl -ohang
.It Sy "missing manual title, using UNTITLED"
.Pq mdoc
A
.Ic \&Dt
macro has no arguments, or there is no
.Ic \&Dt
macro before the first non-prologue macro.
.It Sy "missing manual title, using \(dq\(dq"
.Pq man
There is no
.Ic \&TH
macro, or it has no arguments.
-.It Sy "lower case character in document title"
-.Pq mdoc , man
-The title is still used as given in the
-.Ic \&Dt
-or
-.Ic \&TH
-macro.
.It Sy "missing manual section, using \(dq\(dq"
.Pq mdoc , man
A
.Ic \&Dt
or
.Ic \&TH
macro lacks the mandatory section argument.
.It Sy "unknown manual section"
.Pq mdoc
The section number in a
.Ic \&Dt
line is invalid, but still used.
.It Sy "missing date, using today's date"
.Pq mdoc, man
The document was parsed as
.Xr mdoc 7
and it has no
.Ic \&Dd
macro, or the
.Ic \&Dd
macro has no arguments or only empty arguments;
or the document was parsed as
.Xr man 7
and it has no
.Ic \&TH
macro, or the
.Ic \&TH
macro has less than three arguments or its third argument is empty.
.It Sy "cannot parse date, using it verbatim"
.Pq mdoc , man
The date given in a
.Ic \&Dd
or
.Ic \&TH
macro does not follow the conventional format.
+.It Sy "date in the future, using it anyway"
+.Pq mdoc , man
+The date given in a
+.Ic \&Dd
+or
+.Ic \&TH
+macro is more than a day ahead of the current system
+.Xr time 3 .
.It Sy "missing Os macro, using \(dq\(dq"
.Pq mdoc
The default or current system is not shown in this case.
-.It Sy "duplicate prologue macro"
-.Pq mdoc
-One of the prologue macros occurs more than once.
-The last instance overrides all previous ones.
.It Sy "late prologue macro"
.Pq mdoc
A
.Ic \&Dd
or
.Ic \&Os
macro occurs after some non-prologue macro, but still takes effect.
-.It Sy "skipping late title macro"
-.Pq mdoc
-The
-.Ic \&Dt
-macro appears after the first non-prologue macro.
-Traditional formatters cannot handle this because
-they write the page header before parsing the document body.
-Even though this technical restriction does not apply to
-.Nm ,
-traditional semantics is preserved.
-The late macro is discarded including its arguments.
.It Sy "prologue macros out of order"
.Pq mdoc
The prologue macros are not given in the conventional order
.Ic \&Dd ,
.Ic \&Dt ,
.Ic \&Os .
All three macros are used even when given in another order.
.El
.Ss Warnings regarding document structure
.Bl -ohang
.It Sy ".so is fragile, better use ln(1)"
.Pq roff
Including files only works when the parser program runs with the correct
current working directory.
.It Sy "no document body"
.Pq mdoc , man
The document body contains neither text nor macros.
An empty document is shown, consisting only of a header and a footer line.
.It Sy "content before first section header"
.Pq mdoc , man
Some macros or text precede the first
.Ic \&Sh
or
.Ic \&SH
section header.
The offending macros and text are parsed and added to the top level
of the syntax tree, outside any section block.
.It Sy "first section is not NAME"
.Pq mdoc
The argument of the first
.Ic \&Sh
macro is not
.Sq NAME .
This may confuse
.Xr makewhatis 8
and
.Xr apropos 1 .
.It Sy "NAME section without Nm before Nd"
.Pq mdoc
The NAME section does not contain any
.Ic \&Nm
child macro before the first
.Ic \&Nd
macro.
.It Sy "NAME section without description"
.Pq mdoc
The NAME section lacks the mandatory
.Ic \&Nd
child macro.
.It Sy "description not at the end of NAME"
.Pq mdoc
The NAME section does contain an
.Ic \&Nd
child macro, but other content follows it.
.It Sy "bad NAME section content"
.Pq mdoc
The NAME section contains plain text or macros other than
.Ic \&Nm
and
.Ic \&Nd .
.It Sy "missing comma before name"
.Pq mdoc
The NAME section contains an
.Ic \&Nm
macro that is neither the first one nor preceded by a comma.
.It Sy "missing description line, using \(dq\(dq"
.Pq mdoc
The
.Ic \&Nd
macro lacks the required argument.
The title line of the manual will end after the dash.
.It Sy "description line outside NAME section"
.Pq mdoc
An
.Ic \&Nd
macro appears outside the NAME section.
The arguments are printed anyway and the following text is used for
.Xr apropos 1 ,
but none of that behaviour is portable.
.It Sy "sections out of conventional order"
.Pq mdoc
A standard section occurs after another section it usually precedes.
All section titles are used as given,
and the order of sections is not changed.
.It Sy "duplicate section title"
.Pq mdoc
The same standard section title occurs more than once.
.It Sy "unexpected section"
.Pq mdoc
A standard section header occurs in a section of the manual
where it normally isn't useful.
+.It Sy "cross reference to self"
+.Pq mdoc
+An
+.Ic \&Xr
+macro refers to a name and section matching the section of the present
+manual page and a name mentioned in an
+.Ic \&Nm
+macro in the NAME or SYNOPSIS section, or in an
+.Ic \&Fn
+or
+.Ic \&Fo
+macro in the SYNOPSIS.
+Consider using
+.Ic \&Nm
+or
+.Ic \&Fn
+instead of
+.Ic \&Xr .
.It Sy "unusual Xr order"
.Pq mdoc
In the SEE ALSO section, an
.Ic \&Xr
macro with a lower section number follows one with a higher number,
or two
.Ic \&Xr
macros referring to the same section are out of alphabetical order.
.It Sy "unusual Xr punctuation"
.Pq mdoc
In the SEE ALSO section, punctuation between two
.Ic \&Xr
macros differs from a single comma, or there is trailing punctuation
after the last
.Ic \&Xr
macro.
.It Sy "AUTHORS section without An macro"
.Pq mdoc
An AUTHORS sections contains no
.Ic \&An
macros, or only empty ones.
Probably, there are author names lacking markup.
.El
.Ss "Warnings related to macros and nesting"
.Bl -ohang
.It Sy "obsolete macro"
.Pq mdoc
See the
.Xr mdoc 7
manual for replacements.
.It Sy "macro neither callable nor escaped"
.Pq mdoc
The name of a macro that is not callable appears on a macro line.
It is printed verbatim.
If the intention is to call it, move it to its own input line;
otherwise, escape it by prepending
.Sq \e& .
.It Sy "skipping paragraph macro"
In
.Xr mdoc 7
documents, this happens
.Bl -dash -compact
.It
at the beginning and end of sections and subsections
.It
right before non-compact lists and displays
.It
at the end of items in non-column, non-compact lists
.It
and for multiple consecutive paragraph macros.
.El
In
.Xr man 7
documents, it happens
.Bl -dash -compact
.It
for empty
.Ic \&P ,
.Ic \&PP ,
and
.Ic \&LP
macros
.It
for
.Ic \&IP
macros having neither head nor body arguments
.It
for
.Ic \&br
or
.Ic \&sp
right after
.Ic \&SH
or
.Ic \&SS
.El
.It Sy "moving paragraph macro out of list"
.Pq mdoc
A list item in a
.Ic \&Bl
list contains a trailing paragraph macro.
The paragraph macro is moved after the end of the list.
.It Sy "skipping no-space macro"
.Pq mdoc
An input line begins with an
.Ic \&Ns
-macro.
+macro, or the next argument after an
+.Ic \&Ns
+macro is an isolated closing delimiter.
The macro is ignored.
.It Sy "blocks badly nested"
.Pq mdoc
If two blocks intersect, one should completely contain the other.
Otherwise, rendered output is likely to look strange in any output
format, and rendering in SGML-based output formats is likely to be
outright wrong because such languages do not support badly nested
blocks at all.
Typical examples of badly nested blocks are
.Qq Ic \&Ao \&Bo \&Ac \&Bc
and
.Qq Ic \&Ao \&Bq \&Ac .
In these examples,
.Ic \&Ac
breaks
.Ic \&Bo
and
.Ic \&Bq ,
respectively.
.It Sy "nested displays are not portable"
.Pq mdoc
A
.Ic \&Bd ,
.Ic \&D1 ,
or
.Ic \&Dl
display occurs nested inside another
.Ic \&Bd
display.
This works with
.Nm ,
but fails with most other implementations.
.It Sy "moving content out of list"
.Pq mdoc
A
.Ic \&Bl
list block contains text or macros before the first
.Ic \&It
macro.
The offending children are moved before the beginning of the list.
-.It Sy "fill mode already enabled, skipping"
-.Pq man
-A
-.Ic \&fi
-request occurs even though the document is still in fill mode,
-or already switched back to fill mode.
-It has no effect.
-.It Sy "fill mode already disabled, skipping"
-.Pq man
-An
-.Ic \&nf
-request occurs even though the document already switched to no-fill mode
-and did not switch back to fill mode yet.
-It has no effect.
+.It Sy "first macro on line"
+Inside a
+.Ic \&Bl Fl column
+list, a
+.Ic \&Ta
+macro occurs as the first macro on a line, which is not portable.
.It Sy "line scope broken"
.Pq man
While parsing the next-line scope of the previous macro,
another macro is found that prematurely terminates the previous one.
The previous, interrupted macro is deleted from the parse tree.
.El
.Ss "Warnings related to missing arguments"
.Bl -ohang
.It Sy "skipping empty request"
.Pq roff , eqn
The macro name is missing from a macro definition request,
or an
.Xr eqn 7
control statement or operation keyword lacks its required argument.
.It Sy "conditional request controls empty scope"
.Pq roff
A conditional request is only useful if any of the following
follows it on the same logical input line:
.Bl -dash -compact
.It
The
.Sq \e{
keyword to open a multi-line scope.
.It
A request or macro or some text, resulting in a single-line scope.
.It
The immediate end of the logical line without any intervening whitespace,
resulting in next-line scope.
.El
Here, a conditional request is followed by trailing whitespace only,
and there is no other content on its logical input line.
Note that it doesn't matter whether the logical input line is split
across multiple physical input lines using
.Sq \e
line continuation characters.
This is one of the rare cases
where trailing whitespace is syntactically significant.
The conditional request controls a scope containing whitespace only,
so it is unlikely to have a significant effect,
except that it may control a following
.Ic \&el
clause.
.It Sy "skipping empty macro"
.Pq mdoc
The indicated macro has no arguments and hence no effect.
.It Sy "empty block"
.Pq mdoc , man
A
.Ic \&Bd ,
.Ic \&Bk ,
.Ic \&Bl ,
.Ic \&D1 ,
.Ic \&Dl ,
+.Ic \&MT ,
.Ic \&RS ,
or
.Ic \&UR
block contains nothing in its body and will produce no output.
.It Sy "empty argument, using 0n"
.Pq mdoc
The required width is missing after
.Ic \&Bd
or
.Ic \&Bl
.Fl offset
or
.Fl width .
.It Sy "missing display type, using -ragged"
.Pq mdoc
The
.Ic \&Bd
macro is invoked without the required display type.
.It Sy "list type is not the first argument"
.Pq mdoc
In a
.Ic \&Bl
macro, at least one other argument precedes the type argument.
The
.Nm
utility copes with any argument order, but some other
.Xr mdoc 7
implementations do not.
.It Sy "missing -width in -tag list, using 8n"
.Pq mdoc
Every
.Ic \&Bl
macro having the
.Fl tag
argument requires
.Fl width ,
too.
.It Sy "missing utility name, using \(dq\(dq"
.Pq mdoc
The
.Ic \&Ex Fl std
macro is called without an argument before
.Ic \&Nm
has first been called with an argument.
.It Sy "missing function name, using \(dq\(dq"
.Pq mdoc
The
.Ic \&Fo
macro is called without an argument.
No function name is printed.
.It Sy "empty head in list item"
.Pq mdoc
In a
.Ic \&Bl
.Fl diag ,
.Fl hang ,
.Fl inset ,
.Fl ohang ,
or
.Fl tag
list, an
.Ic \&It
macro lacks the required argument.
The item head is left empty.
.It Sy "empty list item"
.Pq mdoc
In a
.Ic \&Bl
.Fl bullet ,
.Fl dash ,
.Fl enum ,
or
.Fl hyphen
list, an
.Ic \&It
block is empty.
An empty list item is shown.
+.It Sy "missing argument, using next line"
+.Pq mdoc
+An
+.Ic \&It
+macro in a
+.Ic \&Bd Fl column
+list has no arguments.
+While
+.Nm
+uses the text or macros of the following line, if any, for the cell,
+other formatters may misformat the list.
.It Sy "missing font type, using \efR"
.Pq mdoc
A
.Ic \&Bf
macro has no argument.
It switches to the default font.
.It Sy "unknown font type, using \efR"
.Pq mdoc
The
.Ic \&Bf
argument is invalid.
The default font is used instead.
.It Sy "nothing follows prefix"
.Pq mdoc
A
.Ic \&Pf
macro has no argument, or only one argument and no macro follows
on the same input line.
This defeats its purpose; in particular, spacing is not suppressed
before the text or macros following on the next input line.
.It Sy "empty reference block"
.Pq mdoc
An
.Ic \&Rs
macro is immediately followed by an
.Ic \&Re
macro on the next input line.
Such an empty block does not produce any output.
.It Sy "missing section argument"
.Pq mdoc
An
.Ic \&Xr
macro lacks its second, section number argument.
The first argument, i.e. the name, is printed, but without subsequent
parentheses.
.It Sy "missing -std argument, adding it"
.Pq mdoc
An
.Ic \&Ex
or
.Ic \&Rv
macro lacks the required
.Fl std
argument.
The
.Nm
utility assumes
.Fl std
even when it is not specified, but other implementations may not.
.It Sy "missing option string, using \(dq\(dq"
.Pq man
The
.Ic \&OP
macro is invoked without any argument.
An empty pair of square brackets is shown.
.It Sy "missing resource identifier, using \(dq\(dq"
.Pq man
The
+.Ic \&MT
+or
.Ic \&UR
macro is invoked without any argument.
An empty pair of angle brackets is shown.
.It Sy "missing eqn box, using \(dq\(dq"
.Pq eqn
A diacritic mark or a binary operator is found,
but there is nothing to the left of it.
An empty box is inserted.
.El
.Ss "Warnings related to bad macro arguments"
.Bl -ohang
-.It Sy "unterminated quoted argument"
-.Pq roff
-Macro arguments can be enclosed in double quote characters
-such that space characters and macro names contained in the quoted
-argument need not be escaped.
-The closing quote of the last argument of a macro can be omitted.
-However, omitting it is not recommended because it makes the code
-harder to read.
.It Sy "duplicate argument"
.Pq mdoc
A
.Ic \&Bd
or
.Ic \&Bl
macro has more than one
.Fl compact ,
more than one
.Fl offset ,
or more than one
.Fl width
argument.
All but the last instances of these arguments are ignored.
.It Sy "skipping duplicate argument"
.Pq mdoc
An
.Ic \&An
macro has more than one
.Fl split
or
.Fl nosplit
argument.
All but the first of these arguments are ignored.
.It Sy "skipping duplicate display type"
.Pq mdoc
A
.Ic \&Bd
macro has more than one type argument; the first one is used.
.It Sy "skipping duplicate list type"
.Pq mdoc
A
.Ic \&Bl
macro has more than one type argument; the first one is used.
.It Sy "skipping -width argument"
.Pq mdoc
A
.Ic \&Bl
.Fl column ,
.Fl diag ,
.Fl ohang ,
.Fl inset ,
or
.Fl item
list has a
.Fl width
argument.
That has no effect.
.It Sy "wrong number of cells"
In a line of a
.Ic \&Bl Fl column
list, the number of tabs or
.Ic \&Ta
macros is less than the number expected from the list header line
or exceeds the expected number by more than one.
Missing cells remain empty, and all cells exceeding the number of
columns are joined into one single cell.
.It Sy "unknown AT&T UNIX version"
.Pq mdoc
An
.Ic \&At
macro has an invalid argument.
It is used verbatim, with
.Qq "AT&T UNIX "
prefixed to it.
.It Sy "comma in function argument"
.Pq mdoc
An argument of an
.Ic \&Fa
or
.Ic \&Fn
macro contains a comma; it should probably be split into two arguments.
.It Sy "parenthesis in function name"
.Pq mdoc
The first argument of an
.Ic \&Fc
or
.Ic \&Fn
macro contains an opening or closing parenthesis; that's probably wrong,
parentheses are added automatically.
.It Sy "unknown library name"
.Pq mdoc, not on Ox
An
.Ic \&Lb
macro has an unknown name argument and will be rendered as
.Qq library Dq Ar name .
.It Sy "invalid content in Rs block"
.Pq mdoc
An
.Ic \&Rs
block contains plain text or non-% macros.
The bogus content is left in the syntax tree.
Formatting may be poor.
.It Sy "invalid Boolean argument"
.Pq mdoc
An
.Ic \&Sm
macro has an argument other than
.Cm on
or
.Cm off .
The invalid argument is moved out of the macro, which leaves the macro
empty, causing it to toggle the spacing mode.
.It Sy "unknown font, skipping request"
.Pq man , tbl
A
.Xr roff 7
.Ic \&ft
request or a
.Xr tbl 7
.Ic \&f
layout modifier has an unknown
.Ar font
argument.
.It Sy "odd number of characters in request"
.Pq roff
A
.Ic \&tr
request contains an odd number of characters.
The last character is mapped to the blank character.
.El
.Ss "Warnings related to plain text"
.Bl -ohang
.It Sy "blank line in fill mode, using .sp"
.Pq mdoc
The meaning of blank input lines is only well-defined in non-fill mode:
In fill mode, line breaks of text input lines are not supposed to be
significant.
However, for compatibility with groff, blank lines in fill mode
are replaced with
.Ic \&sp
requests.
.It Sy "tab in filled text"
.Pq mdoc , man
The meaning of tab characters is only well-defined in non-fill mode:
In fill mode, whitespace is not supposed to be significant
on text input lines.
As an implementation dependent choice, tab characters on text lines
are passed through to the formatters in any case.
Given that the text before the tab character will be filled,
it is hard to predict which tab stop position the tab will advance to.
-.It Sy "whitespace at end of input line"
-.Pq mdoc , man , roff
-Whitespace at the end of input lines is almost never semantically
-significant \(em but in the odd case where it might be, it is
-extremely confusing when reviewing and maintaining documents.
.It Sy "new sentence, new line"
.Pq mdoc
A new sentence starts in the middle of a text line.
Start it on a new input line to help formatters produce correct spacing.
-.It Sy "bad comment style"
-.Pq roff
-Comment lines start with a dot, a backslash, and a double-quote character.
-The
-.Nm
-utility treats the line as a comment line even without the backslash,
-but leaving out the backslash might not be portable.
.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.
If the argument is incomplete,
.Ic \e*
and
.Ic \en
expand to an empty string,
.Ic \eB
to the digit
.Sq 0 ,
and
.Ic \ew
to the length of the incomplete argument.
All other invalid escape sequences are ignored.
.It Sy "undefined string, using \(dq\(dq"
.Pq roff
If a string is used without being defined before,
its value is implicitly set to the empty string.
However, defining strings explicitly before use
keeps the code more readable.
.El
.Ss "Warnings related to tables"
.Bl -ohang
.It Sy "tbl line starts with span"
.Pq tbl
The first cell in a table layout line is a horizontal span
.Pq Sq Cm s .
Data provided for this cell is ignored, and nothing is printed in the cell.
.It Sy "tbl column starts with span"
.Pq tbl
The first line of a table layout specification
requests a vertical span
.Pq Sq Cm ^ .
Data provided for this cell is ignored, and nothing is printed in the cell.
.It Sy "skipping vertical bar in tbl layout"
.Pq tbl
A table layout specification contains more than two consecutive vertical bars.
A double bar is printed, all additional bars are discarded.
.El
.Ss "Errors related to tables"
.Bl -ohang
.It Sy "non-alphabetic character in tbl options"
.Pq tbl
The table options line contains a character other than a letter,
blank, or comma where the beginning of an option name is expected.
The character is ignored.
.It Sy "skipping unknown tbl option"
.Pq tbl
The table options line contains a string of letters that does not
match any known option name.
The word is ignored.
.It Sy "missing tbl option argument"
.Pq tbl
A table option that requires an argument is not followed by an
opening parenthesis, or the opening parenthesis is immediately
followed by a closing parenthesis.
The option is ignored.
.It Sy "wrong tbl option argument size"
.Pq tbl
A table option argument contains an invalid number of characters.
Both the option and the argument are ignored.
.It Sy "empty tbl layout"
.Pq tbl
A table layout specification is completely empty,
specifying zero lines and zero columns.
As a fallback, a single left-justified column is used.
.It Sy "invalid character in tbl layout"
.Pq tbl
A table layout specification contains a character that can neither
be interpreted as a layout key character nor as a layout modifier,
or a modifier precedes the first key.
The invalid character is discarded.
.It Sy "unmatched parenthesis in tbl layout"
.Pq tbl
A table layout specification contains an opening parenthesis,
but no matching closing parenthesis.
The rest of the input line, starting from the parenthesis, has no effect.
.It Sy "tbl without any data cells"
.Pq tbl
A table does not contain any data cells.
It will probably produce no output.
.It Sy "ignoring data in spanned tbl cell"
.Pq tbl
A table cell is marked as a horizontal span
.Pq Sq Cm s
or vertical span
.Pq Sq Cm ^
in the table layout, but it contains data.
The data is ignored.
.It Sy "ignoring extra tbl data cells"
.Pq tbl
A data line contains more cells than the corresponding layout line.
The data in the extra cells is ignored.
.It Sy "data block open at end of tbl"
.Pq tbl
A data block is opened with
.Cm T{ ,
but never closed with a matching
.Cm T} .
The remaining data lines of the table are all put into one cell,
and any remaining cells stay empty.
.El
.Ss "Errors related to roff, mdoc, and man code"
.Bl -ohang
+.It Sy "duplicate prologue macro"
+.Pq mdoc
+One of the prologue macros occurs more than once.
+The last instance overrides all previous ones.
+.It Sy "skipping late title macro"
+.Pq mdoc
+The
+.Ic \&Dt
+macro appears after the first non-prologue macro.
+Traditional formatters cannot handle this because
+they write the page header before parsing the document body.
+Even though this technical restriction does not apply to
+.Nm ,
+traditional semantics is preserved.
+The late macro is discarded including its arguments.
.It Sy "input stack limit exceeded, infinite loop?"
.Pq roff
Explicit recursion limits are implemented for the following features,
in order to prevent infinite loops:
.Bl -dash -compact
.It
expansion of nested escape sequences
including expansion of strings and number registers,
.It
expansion of nested user-defined macros,
.It
and
.Ic \&so
file inclusion.
.El
When a limit is hit, the output is incorrect, typically losing
some content, but the parser can continue.
.It Sy "skipping bad character"
.Pq mdoc , man , roff
The input file contains a byte that is not a printable
.Xr ascii 7
character.
The message mentions the character number.
The offending byte is replaced with a question mark
.Pq Sq \&? .
Consider editing the input file to replace the byte with an ASCII
transliteration of the intended character.
.It Sy "skipping unknown macro"
.Pq mdoc , man , roff
The first identifier on a request or macro line is neither recognized as a
.Xr roff 7
request, nor as a user-defined macro, nor, respectively, as an
.Xr mdoc 7
or
.Xr man 7
macro.
It may be mistyped or unsupported.
The request or macro is discarded including its arguments.
.It Sy "skipping insecure request"
.Pq roff
An input file attempted to run a shell command
or to read or write an external file.
Such attempts are denied for security reasons.
.It Sy "skipping item outside list"
.Pq mdoc , eqn
An
.Ic \&It
macro occurs outside any
.Ic \&Bl
list, or an
.Xr eqn 7
.Ic above
delimiter occurs outside any pile.
It is discarded including its arguments.
.It Sy "skipping column outside column list"
.Pq mdoc
A
.Ic \&Ta
macro occurs outside any
.Ic \&Bl Fl column
block.
It is discarded including its arguments.
.It Sy "skipping end of block that is not open"
.Pq mdoc , man , eqn , tbl , roff
Various syntax elements can only be used to explicitly close blocks
that have previously been opened.
An
.Xr mdoc 7
block closing macro, a
.Xr man 7
-.Ic \&RE
+.Ic \&ME , \&RE
or
.Ic \&UE
macro, an
.Xr eqn 7
right delimiter or closing brace, or the end of an equation, table, or
.Xr roff 7
conditional request is encountered but no matching block is open.
The offending request or macro is discarded.
.It Sy "fewer RS blocks open, skipping"
.Pq man
The
.Ic \&RE
macro is invoked with an argument, but less than the specified number of
.Ic \&RS
blocks is open.
The
.Ic \&RE
macro is discarded.
.It Sy "inserting missing end of block"
.Pq mdoc , tbl
Various
.Xr mdoc 7
macros as well as tables require explicit closing by dedicated macros.
A block that doesn't support bad nesting
ends before all of its children are properly closed.
The open child nodes are closed implicitly.
.It Sy "appending missing end of block"
.Pq mdoc , man , eqn , tbl , roff
At the end of the document, an explicit
.Xr mdoc 7
block, a
.Xr man 7
next-line scope or
-.Ic \&RS
+.Ic \&MT , \&RS
or
.Ic \&UR
block, an equation, table, or
.Xr roff 7
conditional or ignore block is still open.
The open block is closed implicitly.
.It Sy "escaped character not allowed in a name"
.Pq roff
Macro, string and register identifiers consist of printable,
non-whitespace ASCII characters.
Escape sequences and characters and strings expressed in terms of them
cannot form part of a name.
The first argument of an
.Ic \&am ,
.Ic \&as ,
.Ic \&de ,
.Ic \&ds ,
.Ic \&nr ,
or
.Ic \&rr
request, or any argument of an
.Ic \&rm
request, or the name of a request or user defined macro being called,
is terminated by an escape sequence.
In the cases of
.Ic \&as ,
.Ic \&ds ,
and
.Ic \&nr ,
the request has no effect at all.
In the cases of
.Ic \&am ,
.Ic \&de ,
.Ic \&rr ,
and
.Ic \&rm ,
what was parsed up to this point is used as the arguments to the request,
and the rest of the input line is discarded including the escape sequence.
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 "NOT IMPLEMENTED: Bd -file"
.Pq mdoc
For security reasons, the
.Ic \&Bd
macro does not support the
.Fl file
argument.
By requesting the inclusion of a sensitive file, a malicious document
might otherwise trick a privileged user into inadvertently displaying
the file on the screen, revealing the file content to bystanders.
The argument is ignored including the file name following it.
.It Sy "skipping display without arguments"
.Pq mdoc
A
.Ic \&Bd
block macro does not have any arguments.
The block is discarded, and the block content is displayed in
whatever mode was active before the block.
.It Sy "missing list type, using -item"
.Pq mdoc
A
.Ic \&Bl
macro fails to specify the list type.
.It Sy "argument is not numeric, using 1"
.Pq roff
The argument of a
.Ic \&ce
request is not a number.
.It Sy "missing manual name, using \(dq\(dq"
.Pq mdoc
The first call to
.Ic \&Nm ,
or any call in the NAME section, lacks the required argument.
.It Sy "uname(3) system call failed, using UNKNOWN"
.Pq mdoc
The
.Ic \&Os
macro is called without arguments, and the
.Xr uname 3
system call failed.
As a workaround,
.Nm
can be compiled with
.Sm off
.Fl D Cm OSNAME=\(dq\e\(dq Ar string Cm \e\(dq\(dq .
.Sm on
.It Sy "unknown standard specifier"
.Pq mdoc
An
.Ic \&St
macro has an unknown argument and is discarded.
.It Sy "skipping request without numeric argument"
.Pq roff , eqn
An
.Ic \&it
request or an
.Xr eqn 7
.Ic \&size
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 "NOT IMPLEMENTED: .so with absolute path or \(dq..\(dq"
.Pq roff
For security reasons,
.Nm
allows
.Ic \&so
file inclusion requests only with relative paths
and only without ascending to any parent directory.
By requesting the inclusion of a sensitive file, a malicious document
might otherwise trick a privileged user into inadvertently displaying
the file on the screen, revealing the file content to bystanders.
.Nm
only shows the path as it appears behind
.Ic \&so .
.It Sy ".so request failed"
.Pq roff
Servicing a
.Ic \&so
request requires reading an external file, but the file could not be
opened.
.Nm
only shows the path as it appears behind
.Ic \&so .
.It Sy "skipping all arguments"
.Pq mdoc , man , eqn , roff
An
.Xr mdoc 7
.Ic \&Bt ,
.Ic \&Ed ,
.Ic \&Ef ,
.Ic \&Ek ,
.Ic \&El ,
.Ic \&Lp ,
.Ic \&Pp ,
.Ic \&Re ,
.Ic \&Rs ,
or
.Ic \&Ud
macro, an
.Ic \&It
macro in a list that don't support item heads, a
.Xr man 7
.Ic \&LP ,
.Ic \&P ,
or
.Ic \&PP
macro, an
.Xr eqn 7
.Ic \&EQ
or
.Ic \&EN
macro, or a
.Xr roff 7
.Ic \&br ,
.Ic \&fi ,
or
.Ic \&nf
request or
.Sq \&..
block closing request is invoked with at least one argument.
All arguments are ignored.
.It Sy "skipping excess arguments"
.Pq mdoc , man , roff
A macro or request is invoked with too many arguments:
.Bl -dash -offset 2n -width 2n -compact
.It
.Ic \&Fo ,
+.Ic \&MT ,
.Ic \&PD ,
.Ic \&RS ,
.Ic \&UR ,
.Ic \&ft ,
or
.Ic \&sp
with more than one argument
.It
.Ic \&An
with another argument after
.Fl split
or
.Fl nosplit
.It
.Ic \&RE
with more than one argument or with a non-integer argument
.It
.Ic \&OP
or a request of the
.Ic \&de
family with more than two arguments
.It
.Ic \&Dt
with more than three arguments
.It
.Ic \&TH
with more than five arguments
.It
.Ic \&Bd ,
.Ic \&Bk ,
or
.Ic \&Bl
with invalid arguments
.El
The excess arguments are ignored.
.El
.Ss Unsupported features
.Bl -ohang
.It Sy "input too large"
.Pq mdoc , man
Currently,
.Nm
cannot handle input files larger than its arbitrary size limit
of 2^31 bytes (2 Gigabytes).
Since useful manuals are always small, this is not a problem in practice.
Parsing is aborted as soon as the condition is detected.
.It Sy "unsupported control character"
.Pq roff
An ASCII control character supported by other
.Xr roff 7
implementations but not by
.Nm
was found in an input file.
It is replaced by a question mark.
.It Sy "unsupported roff request"
.Pq roff
An input file contains a
.Xr roff 7
request 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 "eqn delim option in tbl"
.Pq eqn , tbl
The options line of a table defines equation delimiters.
Any equation source code contained in the table will be printed unformatted.
.It Sy "unsupported table layout modifier"
.Pq tbl
A table layout specification contains an
.Sq Cm m
modifier.
The modifier is discarded.
.It Sy "ignoring macro in table"
.Pq tbl , mdoc , man
A table contains an invocation of an
.Xr mdoc 7
or
.Xr man 7
macro or of an undefined macro.
The macro is ignored, and its arguments are handled
as if they were a text line.
.El
.Sh SEE ALSO
.Xr apropos 1 ,
.Xr man 1 ,
.Xr eqn 7 ,
.Xr man 7 ,
.Xr mandoc_char 7 ,
.Xr mdoc 7 ,
.Xr roff 7 ,
.Xr tbl 7
.Sh HISTORY
The
.Nm
utility first appeared in
.Ox 4.8 .
The option
.Fl I
appeared in
.Ox 5.2 ,
and
.Fl aCcfhKklMSsw
in
.Ox 5.7 .
.Sh AUTHORS
.An -nosplit
The
.Nm
utility was written by
.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
and is maintained by
.An Ingo Schwarze Aq Mt schwarze@openbsd.org .
Index: vendor/mdocml/dist/mandoc.3
===================================================================
--- vendor/mdocml/dist/mandoc.3 (revision 321806)
+++ vendor/mdocml/dist/mandoc.3 (revision 321807)
@@ -1,700 +1,713 @@
-.\" $Id: mandoc.3,v 1.39 2017/05/17 23:39:31 schwarze Exp $
+.\" $Id: mandoc.3,v 1.41 2017/07/04 23:40:01 schwarze Exp $
.\"
.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons
.\" Copyright (c) 2010-2017 Ingo Schwarze
.\"
.\" 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.
.\"
-.Dd $Mdocdate: May 17 2017 $
+.Dd $Mdocdate: July 4 2017 $
.Dt MANDOC 3
.Os
.Sh NAME
.Nm mandoc ,
.Nm deroff ,
.Nm mandocmsg ,
.Nm man_mparse ,
.Nm man_validate ,
.Nm mdoc_validate ,
.Nm mparse_alloc ,
.Nm mparse_free ,
.Nm mparse_getkeep ,
.Nm mparse_keep ,
.Nm mparse_open ,
.Nm mparse_readfd ,
.Nm mparse_reset ,
.Nm mparse_result ,
.Nm mparse_strerror ,
.Nm mparse_strlevel ,
-.Nm mparse_updaterc
+.Nm mparse_updaterc
.Nd mandoc macro compiler library
.Sh SYNOPSIS
.In sys/types.h
.In mandoc.h
.Pp
.Fd "#define ASCII_NBRSP"
.Fd "#define ASCII_HYPH"
.Fd "#define ASCII_BREAK"
.Ft struct mparse *
.Fo mparse_alloc
.Fa "int options"
-.Fa "enum mandoclevel wlevel"
+.Fa "enum mandocerr mmin"
.Fa "mandocmsg mmsg"
-.Fa "char *defos"
+.Fa "enum mandoc_os oe_e"
+.Fa "char *os_s"
.Fc
.Ft void
.Fo (*mandocmsg)
.Fa "enum mandocerr errtype"
.Fa "enum mandoclevel level"
.Fa "const char *file"
.Fa "int line"
.Fa "int col"
.Fa "const char *msg"
.Fc
.Ft void
.Fo mparse_free
.Fa "struct mparse *parse"
.Fc
.Ft const char *
.Fo mparse_getkeep
.Fa "const struct mparse *parse"
.Fc
.Ft void
.Fo mparse_keep
.Fa "struct mparse *parse"
.Fc
.Ft int
.Fo mparse_open
.Fa "struct mparse *parse"
.Fa "const char *fname"
.Fc
.Ft "enum mandoclevel"
.Fo mparse_readfd
.Fa "struct mparse *parse"
.Fa "int fd"
.Fa "const char *fname"
.Fc
.Ft void
.Fo mparse_reset
.Fa "struct mparse *parse"
.Fc
.Ft void
.Fo mparse_result
.Fa "struct mparse *parse"
.Fa "struct roff_man **man"
.Fa "char **sodest"
.Fc
.Ft "const char *"
.Fo mparse_strerror
.Fa "enum mandocerr"
.Fc
.Ft "const char *"
.Fo mparse_strlevel
.Fa "enum mandoclevel"
.Fc
.Ft void
.Fo mparse_updaterc
.Fa "struct mparse *parse"
.Fa "enum mandoclevel *rc"
.Fc
.In roff.h
.Ft void
.Fo deroff
.Fa "char **dest"
.Fa "const struct roff_node *node"
.Fc
.In sys/types.h
.In mandoc.h
.In mdoc.h
.Vt extern const char * const * mdoc_argnames;
.Vt extern const char * const * mdoc_macronames;
.Ft void
.Fo mdoc_validate
.Fa "struct roff_man *mdoc"
.Fc
.In sys/types.h
.In mandoc.h
.In man.h
.Vt extern const char * const * man_macronames;
.Ft "const struct mparse *"
.Fo man_mparse
.Fa "const struct roff_man *man"
.Fc
.Ft void
.Fo man_validate
.Fa "struct roff_man *man"
.Fc
.Sh DESCRIPTION
The
.Nm mandoc
library parses a
.Ux
manual into an abstract syntax tree (AST).
.Ux
manuals are composed of
.Xr mdoc 7
or
.Xr man 7 ,
and may be mixed with
.Xr roff 7 ,
.Xr tbl 7 ,
and
.Xr eqn 7
invocations.
.Pp
The following describes a general parse sequence:
.Bl -enum
.It
initiate a parsing sequence with
.Xr mchars_alloc 3
and
.Fn mparse_alloc ;
.It
open a file with
.Xr open 2
or
.Fn mparse_open ;
.It
parse it with
.Fn mparse_readfd ;
.It
close it with
.Xr close 2 ;
.It
retrieve the syntax tree with
.Fn mparse_result ;
.It
depending on whether the
.Fa macroset
member of the returned
.Vt struct roff_man
is
.Dv MACROSET_MDOC
or
.Dv MACROSET_MAN ,
validate it with
.Fn mdoc_validate
or
.Fn man_validate ,
respectively;
.It
if information about the validity of the input is needed, fetch it with
.Fn mparse_updaterc ;
.It
iterate over parse nodes with starting from the
.Fa first
member of the returned
.Vt struct roff_man ;
.It
free all allocated memory with
.Fn mparse_free
and
.Xr mchars_free 3 ,
or invoke
.Fn mparse_reset
and go back to step 2 to parse new files.
.El
.Sh REFERENCE
This section documents the functions, types, and variables available
via
.In mandoc.h ,
with the exception of those documented in
.Xr mandoc_escape 3
and
.Xr mchars_alloc 3 .
.Ss Types
.Bl -ohang
.It Vt "enum mandocerr"
An error or warning message during parsing.
.It Vt "enum mandoclevel"
A classification of an
.Vt "enum mandocerr"
as regards system operation.
See the DIAGNOSTICS section in
.Xr mandoc 1
regarding the meanings of the levels.
.It Vt "struct mparse"
An opaque pointer to a running parse sequence.
Created with
.Fn mparse_alloc
and freed with
.Fn mparse_free .
This may be used across parsed input if
.Fn mparse_reset
is called between parses.
.It Vt "mandocmsg"
A prototype for a function to handle error and warning
messages emitted by the parser.
.El
.Ss Functions
.Bl -ohang
.It Fn deroff
Obtain a text-only representation of a
.Vt struct roff_node ,
including text contained in its child nodes.
To be used on children of the
.Fa first
member of
.Vt struct roff_man .
When it is no longer needed, the pointer returned from
.Fn deroff
can be passed to
.Xr free 3 .
.It Fn man_mparse
Get the parser used for the current output.
Declared in
.In man.h ,
implemented in
.Pa man.c .
.It Fn man_validate
Validate the
.Dv MACROSET_MAN
parse tree obtained with
.Fn mparse_result .
Declared in
.In man.h ,
implemented in
.Pa man.c .
.It Fn mdoc_validate
Validate the
.Dv MACROSET_MDOC
parse tree obtained with
.Fn mparse_result .
Declared in
.In mdoc.h ,
implemented in
.Pa mdoc.c .
.It Fn mparse_alloc
Allocate a parser.
The arguments have the following effect:
.Bl -tag -offset 5n -width inttype
.It Ar options
When the
.Dv MPARSE_MDOC
or
.Dv MPARSE_MAN
bit is set, only that parser is used.
Otherwise, the document type is automatically detected.
.Pp
When the
.Dv MPARSE_SO
bit is set,
.Xr roff 7
.Ic \&so
file inclusion requests are always honoured.
Otherwise, if the request is the only content in an input file,
only the file name is remembered, to be returned in the
.Fa sodest
argument of
.Fn mparse_result .
.Pp
When the
.Dv MPARSE_QUICK
bit is set, parsing is aborted after the NAME section.
This is for example useful in
.Xr makewhatis 8
.Fl Q
to quickly build minimal databases.
-.It Ar wlevel
+.It Ar mmin
Can be set to
-.Dv MANDOCLEVEL_BADARG ,
-.Dv MANDOCLEVEL_ERROR ,
+.Dv MANDOCERR_BASE ,
+.Dv MANDOCERR_STYLE ,
+.Dv MANDOCERR_WARNING ,
+.Dv MANDOCERR_ERROR ,
+.Dv MANDOCERR_UNSUPP ,
or
-.Dv MANDOCLEVEL_WARNING .
+.Dv MANDOCERR_MAX .
Messages below the selected level will be suppressed.
.It Ar mmsg
A callback function to handle errors and warnings.
See
.Pa main.c
for an example.
If printing of error messages is not desired,
.Dv NULL
may be passed.
-.It Ar defos
+.It Ar os_e
+Operating system to check base system conventions for.
+If
+.Dv MANDOC_OS_OTHER ,
+the system is automatically detected from
+.Ic \&Os ,
+.Fl Ios ,
+or
+.Xr uname 3 .
+.It Ar os_s
A default string for the
.Xr mdoc 7
-.Sq \&Os
+.Ic \&Os
macro, overriding the
.Dv OSNAME
preprocessor definition and the results of
.Xr uname 3 .
Passing
.Dv NULL
sets no default.
.El
.Pp
The same parser may be used for multiple files so long as
.Fn mparse_reset
is called between parses.
.Fn mparse_free
must be called to free the memory allocated by this function.
Declared in
.In mandoc.h ,
implemented in
.Pa read.c .
.It Fn mparse_free
Free all memory allocated by
.Fn mparse_alloc .
Declared in
.In mandoc.h ,
implemented in
.Pa read.c .
.It Fn mparse_getkeep
Acquire the keep buffer.
Must follow a call of
.Fn mparse_keep .
Declared in
.In mandoc.h ,
implemented in
.Pa read.c .
.It Fn mparse_keep
Instruct the parser to retain a copy of its parsed input.
This can be acquired with subsequent
.Fn mparse_getkeep
calls.
Declared in
.In mandoc.h ,
implemented in
.Pa read.c .
.It Fn mparse_open
Open the file for reading.
If that fails and
.Fa fname
does not already end in
.Ql .gz ,
try again after appending
.Ql .gz .
Save the information whether the file is zipped or not.
Return a file descriptor open for reading or -1 on failure.
It can be passed to
.Fn mparse_readfd
or used directly.
Declared in
.In mandoc.h ,
implemented in
.Pa read.c .
.It Fn mparse_readfd
Parse a file descriptor opened with
.Xr open 2
or
.Fn mparse_open .
Pass the associated filename in
.Va fname .
This function may be called multiple times with different parameters; however,
.Xr close 2
and
.Fn mparse_reset
should be invoked between parses.
Declared in
.In mandoc.h ,
implemented in
.Pa read.c .
.It Fn mparse_reset
Reset a parser so that
.Fn mparse_readfd
may be used again.
Declared in
.In mandoc.h ,
implemented in
.Pa read.c .
.It Fn mparse_result
Obtain the result of a parse.
One of the two pointers will be filled in.
Declared in
.In mandoc.h ,
implemented in
.Pa read.c .
.It Fn mparse_strerror
Return a statically-allocated string representation of an error code.
Declared in
.In mandoc.h ,
implemented in
.Pa read.c .
.It Fn mparse_strlevel
Return a statically-allocated string representation of a level code.
Declared in
.In mandoc.h ,
implemented in
.Pa read.c .
.It Fn mparse_updaterc
If the highest warning or error level that occurred during the current
.Fa parse
is higher than
.Pf * Fa rc ,
update
.Pf * Fa rc
accordingly.
This is useful after calling
.Fn mdoc_validate
or
.Fn man_validate .
Declared in
.In mandoc.h ,
implemented in
.Pa read.c .
.El
.Ss Variables
.Bl -ohang
.It Va man_macronames
The string representation of a
.Xr man 7
macro as indexed by
.Vt "enum mant" .
.It Va mdoc_argnames
The string representation of an
.Xr mdoc 7
macro argument as indexed by
.Vt "enum mdocargt" .
.It Va mdoc_macronames
The string representation of an
.Xr mdoc 7
macro as indexed by
.Vt "enum mdoct" .
.El
.Sh IMPLEMENTATION NOTES
This section consists of structural documentation for
.Xr mdoc 7
and
.Xr man 7
syntax trees and strings.
.Ss Man and Mdoc Strings
Strings may be extracted from mdoc and man meta-data, or from text
nodes (MDOC_TEXT and MAN_TEXT, respectively).
These strings have special non-printing formatting cues embedded in the
text itself, as well as
.Xr roff 7
escapes preserved from input.
Implementing systems will need to handle both situations to produce
human-readable text.
In general, strings may be assumed to consist of 7-bit ASCII characters.
.Pp
The following non-printing characters may be embedded in text strings:
.Bl -tag -width Ds
.It Dv ASCII_NBRSP
A non-breaking space character.
.It Dv ASCII_HYPH
A soft hyphen.
.It Dv ASCII_BREAK
A breakable zero-width space.
.El
.Pp
Escape characters are also passed verbatim into text strings.
An escape character is a sequence of characters beginning with the
backslash
.Pq Sq \e .
To construct human-readable text, these should be intercepted with
.Xr mandoc_escape 3
and converted with one the functions described in
.Xr mchars_alloc 3 .
.Ss Man Abstract Syntax Tree
This AST is governed by the ontological rules dictated in
.Xr man 7
and derives its terminology accordingly.
.Pp
The AST is composed of
.Vt struct roff_node
nodes with element, root and text types as declared by the
.Va type
field.
Each node also provides its parse point (the
.Va line ,
.Va pos ,
and
.Va sec
fields), its position in the tree (the
.Va parent ,
.Va child ,
.Va next
and
.Va prev
fields) and some type-specific data.
.Pp
The tree itself is arranged according to the following normal form,
where capitalised non-terminals represent nodes.
.Pp
.Bl -tag -width "ELEMENTXX" -compact
.It ROOT
\(<- mnode+
.It mnode
\(<- ELEMENT | TEXT | BLOCK
.It BLOCK
\(<- HEAD BODY
.It HEAD
\(<- mnode*
.It BODY
\(<- mnode*
.It ELEMENT
\(<- ELEMENT | TEXT*
.It TEXT
\(<- [[:ascii:]]*
.El
.Pp
The only elements capable of nesting other elements are those with
next-line scope as documented in
.Xr man 7 .
.Ss Mdoc Abstract Syntax Tree
This AST is governed by the ontological
rules dictated in
.Xr mdoc 7
and derives its terminology accordingly.
.Qq In-line
elements described in
.Xr mdoc 7
are described simply as
.Qq elements .
.Pp
The AST is composed of
.Vt struct roff_node
nodes with block, head, body, element, root and text types as declared
by the
.Va type
field.
Each node also provides its parse point (the
.Va line ,
.Va pos ,
and
.Va sec
fields), its position in the tree (the
.Va parent ,
.Va child ,
.Va last ,
.Va next
and
.Va prev
fields) and some type-specific data, in particular, for nodes generated
from macros, the generating macro in the
.Va tok
field.
.Pp
The tree itself is arranged according to the following normal form,
where capitalised non-terminals represent nodes.
.Pp
.Bl -tag -width "ELEMENTXX" -compact
.It ROOT
\(<- mnode+
.It mnode
\(<- BLOCK | ELEMENT | TEXT
.It BLOCK
\(<- HEAD [TEXT] (BODY [TEXT])+ [TAIL [TEXT]]
.It ELEMENT
\(<- TEXT*
.It HEAD
\(<- mnode*
.It BODY
\(<- mnode* [ENDBODY mnode*]
.It TAIL
\(<- mnode*
.It TEXT
\(<- [[:ascii:]]*
.El
.Pp
Of note are the TEXT nodes following the HEAD, BODY and TAIL nodes of
the BLOCK production: these refer to punctuation marks.
Furthermore, although a TEXT node will generally have a non-zero-length
string, in the specific case of
.Sq \&.Bd \-literal ,
an empty line will produce a zero-length string.
Multiple body parts are only found in invocations of
.Sq \&Bl \-column ,
where a new body introduces a new phrase.
.Pp
The
.Xr mdoc 7
syntax tree accommodates for broken block structures as well.
The ENDBODY node is available to end the formatting associated
with a given block before the physical end of that block.
It has a non-null
.Va end
field, is of the BODY
.Va type ,
has the same
.Va tok
as the BLOCK it is ending, and has a
.Va pending
field pointing to that BLOCK's BODY node.
It is an indirect child of that BODY node
and has no children of its own.
.Pp
An ENDBODY node is generated when a block ends while one of its child
blocks is still open, like in the following example:
.Bd -literal -offset indent
\&.Ao ao
\&.Bo bo ac
\&.Ac bc
\&.Bc end
.Ed
.Pp
This example results in the following block structure:
.Bd -literal -offset indent
BLOCK Ao
HEAD Ao
BODY Ao
TEXT ao
BLOCK Bo, pending -> Ao
HEAD Bo
BODY Bo
TEXT bo
TEXT ac
ENDBODY Ao, pending -> Ao
TEXT bc
TEXT end
.Ed
.Pp
Here, the formatting of the
-.Sq \&Ao
+.Ic \&Ao
block extends from TEXT ao to TEXT ac,
while the formatting of the
-.Sq \&Bo
+.Ic \&Bo
block extends from TEXT bo to TEXT bc.
It renders as follows in
.Fl T Ns Cm ascii
mode:
.Pp
.Dl bc] end
.Pp
Support for badly-nested blocks is only provided for backward
compatibility with some older
.Xr mdoc 7
implementations.
Using badly-nested blocks is
.Em strongly discouraged ;
for example, the
.Fl T Ns Cm html
front-end to
.Xr mandoc 1
is unable to render them in any meaningful way.
Furthermore, behaviour when encountering badly-nested blocks is not
consistent across troff implementations, especially when using multiple
levels of badly-nested blocks.
.Sh SEE ALSO
.Xr mandoc 1 ,
.Xr man.cgi 3 ,
.Xr mandoc_escape 3 ,
.Xr mandoc_headers 3 ,
.Xr mandoc_malloc 3 ,
.Xr mansearch 3 ,
.Xr mchars_alloc 3 ,
.Xr tbl 3 ,
.Xr eqn 7 ,
.Xr man 7 ,
.Xr mandoc_char 7 ,
.Xr mdoc 7 ,
.Xr roff 7 ,
.Xr tbl 7
.Sh AUTHORS
.An -nosplit
The
.Nm
library was written by
.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
and is maintained by
.An Ingo Schwarze Aq Mt schwarze@openbsd.org .
Index: vendor/mdocml/dist/mandoc.c
===================================================================
--- vendor/mdocml/dist/mandoc.c (revision 321806)
+++ vendor/mdocml/dist/mandoc.c (revision 321807)
@@ -1,616 +1,630 @@
-/* $Id: mandoc.c,v 1.100 2017/06/02 19:21:23 schwarze Exp $ */
+/* $Id: mandoc.c,v 1.103 2017/07/03 13:40:19 schwarze Exp $ */
/*
* Copyright (c) 2008-2011, 2014 Kristaps Dzonsons
* Copyright (c) 2011-2015, 2017 Ingo Schwarze
*
* 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
#include
#include
#include
#include
#include
#include
#include
#include
-#include "mandoc.h"
#include "mandoc_aux.h"
+#include "mandoc.h"
+#include "roff.h"
#include "libmandoc.h"
static int a2time(time_t *, const char *, const char *);
static char *time2a(time_t);
enum mandoc_esc
mandoc_escape(const char **end, const char **start, int *sz)
{
const char *local_start;
int local_sz;
char term;
enum mandoc_esc gly;
/*
* When the caller doesn't provide return storage,
* use local storage.
*/
if (NULL == start)
start = &local_start;
if (NULL == sz)
sz = &local_sz;
/*
* 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.
*/
gly = ESCAPE_ERROR;
*start = ++*end;
*sz = 0;
term = '\0';
switch ((*start)[-1]) {
/*
* First the glyphs. There are several different forms of
* these, but each eventually returns a substring of the glyph
* name.
*/
case '(':
gly = ESCAPE_SPECIAL;
*sz = 2;
break;
case '[':
gly = ESCAPE_SPECIAL;
term = ']';
break;
case 'C':
if ('\'' != **start)
return ESCAPE_ERROR;
*start = ++*end;
gly = ESCAPE_SPECIAL;
term = '\'';
break;
/*
* Escapes taking no arguments at all.
*/
case 'd':
case 'u':
case ',':
case '/':
return ESCAPE_IGNORE;
+ case 'p':
+ return ESCAPE_BREAK;
/*
* The \z escape is supposed to output the following
* character without advancing the cursor position.
* Since we are mostly dealing with terminal mode,
* let us just skip the next character.
*/
case 'z':
return ESCAPE_SKIPCHAR;
/*
* Handle all triggers matching \X(xy, \Xx, and \X[xxxx], where
* 'X' is the trigger. These have opaque sub-strings.
*/
case 'F':
case 'g':
case 'k':
case 'M':
case 'm':
case 'n':
case 'V':
case 'Y':
gly = ESCAPE_IGNORE;
/* FALLTHROUGH */
case 'f':
if (ESCAPE_ERROR == gly)
gly = ESCAPE_FONT;
switch (**start) {
case '(':
*start = ++*end;
*sz = 2;
break;
case '[':
*start = ++*end;
term = ']';
break;
default:
*sz = 1;
break;
}
break;
/*
* These escapes are of the form \X'Y', where 'X' is the trigger
* and 'Y' is any string. These have opaque sub-strings.
* The \B and \w escapes are handled in roff.c, roff_res().
*/
case 'A':
case 'b':
case 'D':
case 'R':
case 'X':
case 'Z':
gly = ESCAPE_IGNORE;
/* FALLTHROUGH */
case 'o':
if (**start == '\0')
return ESCAPE_ERROR;
if (gly == ESCAPE_ERROR)
gly = ESCAPE_OVERSTRIKE;
term = **start;
*start = ++*end;
break;
/*
* These escapes are of the form \X'N', where 'X' is the trigger
* and 'N' resolves to a numerical expression.
*/
case 'h':
case 'H':
case 'L':
case 'l':
case 'S':
case 'v':
case 'x':
if (strchr(" %&()*+-./0123456789:<=>", **start)) {
if ('\0' != **start)
++*end;
return ESCAPE_ERROR;
}
switch ((*start)[-1]) {
case 'h':
gly = ESCAPE_HORIZ;
break;
case 'l':
gly = ESCAPE_HLINE;
break;
default:
gly = ESCAPE_IGNORE;
break;
}
term = **start;
*start = ++*end;
break;
/*
* Special handling for the numbered character escape.
* XXX Do any other escapes need similar handling?
*/
case 'N':
if ('\0' == **start)
return ESCAPE_ERROR;
(*end)++;
if (isdigit((unsigned char)**start)) {
*sz = 1;
return ESCAPE_IGNORE;
}
(*start)++;
while (isdigit((unsigned char)**end))
(*end)++;
*sz = *end - *start;
if ('\0' != **end)
(*end)++;
return ESCAPE_NUMBERED;
/*
* Sizes get a special category of their own.
*/
case 's':
gly = ESCAPE_IGNORE;
/* See +/- counts as a sign. */
if ('+' == **end || '-' == **end || ASCII_HYPH == **end)
*start = ++*end;
switch (**end) {
case '(':
*start = ++*end;
*sz = 2;
break;
case '[':
*start = ++*end;
term = ']';
break;
case '\'':
*start = ++*end;
term = '\'';
break;
case '3':
case '2':
case '1':
*sz = (*end)[-1] == 's' &&
isdigit((unsigned char)(*end)[1]) ? 2 : 1;
break;
default:
*sz = 1;
break;
}
break;
/*
* Anything else is assumed to be a glyph.
* In this case, pass back the character after the backslash.
*/
default:
gly = ESCAPE_SPECIAL;
*start = --*end;
*sz = 1;
break;
}
assert(ESCAPE_ERROR != gly);
/*
* Read up to the terminating character,
* paying attention to nested escapes.
*/
if ('\0' != term) {
while (**end != term) {
switch (**end) {
case '\0':
return ESCAPE_ERROR;
case '\\':
(*end)++;
if (ESCAPE_ERROR ==
mandoc_escape(end, NULL, NULL))
return ESCAPE_ERROR;
break;
default:
(*end)++;
break;
}
}
*sz = (*end)++ - *start;
} else {
assert(*sz > 0);
if ((size_t)*sz > strlen(*start))
return ESCAPE_ERROR;
*end += *sz;
}
/* Run post-processors. */
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;
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;
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
* a valid Unicode codepoint. Here, however, only
* check the length and range.
*/
if (**start != 'u' || *sz < 5 || *sz > 7)
break;
if (*sz == 7 && ((*start)[1] != '1' || (*start)[2] != '0'))
break;
if (*sz == 6 && (*start)[1] == '0')
break;
if (*sz == 5 && (*start)[1] == 'D' &&
strchr("89ABCDEF", (*start)[2]) != NULL)
break;
if ((int)strspn(*start + 1, "0123456789ABCDEFabcdef")
+ 1 == *sz)
gly = ESCAPE_UNICODE;
break;
default:
break;
}
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)
{
struct tm tm;
char *pp;
memset(&tm, 0, sizeof(struct tm));
pp = NULL;
#if HAVE_STRPTIME
pp = strptime(p, fmt, &tm);
#endif
if (NULL != pp && '\0' == *pp) {
*t = mktime(&tm);
return 1;
}
return 0;
}
static char *
time2a(time_t t)
{
struct tm *tm;
char *buf, *p;
size_t ssz;
int isz;
tm = localtime(&t);
if (tm == NULL)
return NULL;
/*
* Reserve space:
* up to 9 characters for the month (September) + blank
* up to 2 characters for the day + comma + blank
* 4 characters for the year and a terminating '\0'
*/
p = buf = mandoc_malloc(10 + 4 + 4 + 1);
if ((ssz = strftime(p, 10 + 1, "%B ", tm)) == 0)
goto fail;
p += (int)ssz;
/*
* The output format is just "%d" here, not "%2d" or "%02d".
* That's also the reason why we can't just format the
* date as a whole with "%B %e, %Y" or "%B %d, %Y".
* Besides, the present approach is less prone to buffer
* overflows, in case anybody should ever introduce the bug
* of looking at LC_TIME.
*/
if ((isz = snprintf(p, 4 + 1, "%d, ", tm->tm_mday)) == -1)
goto fail;
p += isz;
if (strftime(p, 4 + 1, "%Y", tm) == 0)
goto fail;
return buf;
fail:
free(buf);
return NULL;
}
char *
-mandoc_normdate(struct mparse *parse, char *in, int ln, int pos)
+mandoc_normdate(struct roff_man *man, char *in, int ln, int pos)
{
+ char *cp;
time_t t;
/* No date specified: use today's date. */
if (in == NULL || *in == '\0' || strcmp(in, "$" "Mdocdate$") == 0) {
- mandoc_msg(MANDOCERR_DATE_MISSING, parse, ln, pos, NULL);
+ mandoc_msg(MANDOCERR_DATE_MISSING, man->parse, ln, pos, NULL);
return time2a(time(NULL));
}
/* Valid mdoc(7) date format. */
if (a2time(&t, "$" "Mdocdate: %b %d %Y $", in) ||
- a2time(&t, "%b %d, %Y", in))
- return time2a(t);
+ a2time(&t, "%b %d, %Y", in)) {
+ cp = time2a(t);
+ if (t > time(NULL) + 86400)
+ mandoc_msg(MANDOCERR_DATE_FUTURE, man->parse,
+ ln, pos, cp);
+ return cp;
+ }
- /* Do not warn about the legacy man(7) format. */
+ /* In man(7), do not warn about the legacy format. */
- if ( ! a2time(&t, "%Y-%m-%d", in))
- mandoc_msg(MANDOCERR_DATE_BAD, parse, ln, pos, in);
+ if (a2time(&t, "%Y-%m-%d", in) == 0)
+ mandoc_msg(MANDOCERR_DATE_BAD, man->parse, ln, pos, 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);
/* Use any non-mdoc(7) date verbatim. */
return mandoc_strdup(in);
}
int
mandoc_eos(const char *p, size_t sz)
{
const char *q;
int enclosed, found;
if (0 == sz)
return 0;
/*
* End-of-sentence recognition must include situations where
* some symbols, such as `)', allow prior EOS punctuation to
* propagate outward.
*/
enclosed = found = 0;
for (q = p + (int)sz - 1; q >= p; q--) {
switch (*q) {
case '\"':
case '\'':
case ']':
case ')':
if (0 == found)
enclosed = 1;
break;
case '.':
case '!':
case '?':
found = 1;
break;
default:
return found &&
(!enclosed || isalnum((unsigned char)*q));
}
}
return found && !enclosed;
}
/*
* Convert a string to a long that may not be <0.
* If the string is invalid, or is less than 0, return -1.
*/
int
mandoc_strntoi(const char *p, size_t sz, int base)
{
char buf[32];
char *ep;
long v;
if (sz > 31)
return -1;
memcpy(buf, p, sz);
buf[(int)sz] = '\0';
errno = 0;
v = strtol(buf, &ep, base);
if (buf[0] == '\0' || *ep != '\0')
return -1;
if (v > INT_MAX)
v = INT_MAX;
if (v < INT_MIN)
v = INT_MIN;
return (int)v;
}
Index: vendor/mdocml/dist/mandoc.css
===================================================================
--- vendor/mdocml/dist/mandoc.css (revision 321806)
+++ vendor/mdocml/dist/mandoc.css (revision 321807)
@@ -1,194 +1,203 @@
-/* $Id: mandoc.css,v 1.18 2017/03/13 20:22:18 schwarze Exp $ */
+/* $Id: mandoc.css,v 1.22 2017/07/16 18:45:00 schwarze Exp $ */
/*
* Standard style sheet for mandoc(1) -Thtml and man.cgi(8).
*/
/* Global defaults. */
html { max-width: 100ex; }
body { font-family: Helvetica,Arial,sans-serif; }
table { margin-top: 0em;
margin-bottom: 0em; }
td { vertical-align: top; }
ul, ol, dl { margin-top: 0em;
margin-bottom: 0em; }
li, dt { margin-top: 1em; }
a.selflink { border-bottom: thin dotted;
color: inherit;
font: inherit;
text-decoration: inherit; }
+* { clear: both }
/* Search form and search results. */
fieldset { border: thin solid silver;
border-radius: 1em;
text-align: center; }
input[name=expr] {
width: 25%; }
table.results { margin-top: 1em;
margin-left: 2em;
font-size: smaller; }
/* Header and footer lines. */
table.head { width: 100%;
border-bottom: 1px dotted #808080;
margin-bottom: 1em;
font-size: smaller; }
td.head-vol { text-align: center; }
td.head-rtitle {
text-align: right; }
span.Nd { }
table.foot { width: 100%;
border-top: 1px dotted #808080;
margin-top: 1em;
font-size: smaller; }
td.foot-os { text-align: right; }
/* Sections and paragraphs. */
div.manual-text {
margin-left: 5ex; }
h1.Sh { margin-top: 2ex;
margin-bottom: 1ex;
margin-left: -4ex;
font-size: 110%; }
h2.Ss { margin-top: 2ex;
margin-bottom: 1ex;
margin-left: -2ex;
font-size: 105%; }
div.Pp { margin: 1ex 0ex; }
a.Sx { }
a.Xr { }
/* Displays and lists. */
div.Bd { }
div.D1 { margin-left: 5ex; }
ul.Bl-bullet { list-style-type: disc;
padding-left: 1em; }
li.It-bullet { }
ul.Bl-dash { list-style-type: none;
padding-left: 0em; }
li.It-dash:before {
content: "\2014 "; }
ul.Bl-item { list-style-type: none;
padding-left: 0em; }
li.It-item { }
+ul.Bl-compact > li {
+ margin-top: 0ex; }
ol.Bl-enum { padding-left: 2em; }
li.It-enum { }
+ol.Bl-compact > li {
+ margin-top: 0ex; }
dl.Bl-diag { }
dt.It-diag { }
-dd.It-diag { }
+dd.It-diag { margin-left: 0ex; }
b.It-diag { font-style: normal; }
dl.Bl-hang { }
dt.It-hang { }
-dd.It-hang { }
+dd.It-hang { margin-left: 10.2ex; }
dl.Bl-inset { }
dt.It-inset { }
-dd.It-inset { }
+dd.It-inset { margin-left: 0ex; }
dl.Bl-ohang { }
dt.It-ohang { }
dd.It-ohang { margin-left: 0ex; }
-dl.Bl-tag { margin-left: 8ex; }
+dl.Bl-tag { margin-left: 10.2ex; }
dt.It-tag { float: left;
- clear: both;
margin-top: 0ex;
- margin-left: -8ex;
+ margin-left: -10.2ex;
padding-right: 2ex;
vertical-align: top; }
-dd.It-tag { width: 100%;
+dd.It-tag { clear: right;
+ width: 100%;
margin-top: 0ex;
margin-left: 0ex;
vertical-align: top;
overflow: auto; }
+dl.Bl-compact > dt {
+ margin-top: 0ex; }
table.Bl-column { }
tr.It-column { }
td.It-column { margin-top: 1em; }
+table.Bl-compact > tbody > tr > td {
+ margin-top: 0ex; }
cite.Rs { font-style: normal;
font-weight: normal; }
span.RsA { }
i.RsB { font-weight: normal; }
span.RsC { }
span.RsD { }
i.RsI { font-weight: normal; }
i.RsJ { font-weight: normal; }
span.RsN { }
span.RsO { }
span.RsP { }
span.RsQ { }
span.RsR { }
span.RsT { text-decoration: underline; }
a.RsU { }
span.RsV { }
span.eqn { }
table.tbl { }
/* Semantic markup for command line utilities. */
table.Nm { }
b.Nm { font-style: normal; }
b.Fl { font-style: normal; }
b.Cm { font-style: normal; }
var.Ar { font-style: italic;
font-weight: normal; }
span.Op { }
b.Ic { font-style: normal; }
code.Ev { font-style: normal;
font-weight: normal;
font-family: monospace; }
i.Pa { font-weight: normal; }
/* Semantic markup for function libraries. */
span.Lb { }
b.In { font-style: normal; }
a.In { }
b.Fd { font-style: normal; }
var.Ft { font-style: italic;
font-weight: normal; }
b.Fn { font-style: normal; }
var.Fa { font-style: italic;
font-weight: normal; }
var.Vt { font-style: italic;
font-weight: normal; }
var.Va { font-style: italic;
font-weight: normal; }
code.Dv { font-style: normal;
font-weight: normal;
font-family: monospace; }
code.Er { font-style: normal;
font-weight: normal;
font-family: monospace; }
/* Various semantic markup. */
span.An { }
a.Lk { }
a.Mt { }
b.Cd { font-style: normal; }
i.Ad { font-weight: normal; }
b.Ms { font-style: normal; }
span.St { }
a.Ux { }
/* Physical markup. */
.No { font-style: normal;
font-weight: normal; }
.Em { font-style: italic;
font-weight: normal; }
.Sy { font-style: normal;
font-weight: bold; }
.Li { font-style: normal;
font-weight: normal;
font-family: monospace; }
Index: vendor/mdocml/dist/mandoc.h
===================================================================
--- vendor/mdocml/dist/mandoc.h (revision 321806)
+++ vendor/mdocml/dist/mandoc.h (revision 321807)
@@ -1,456 +1,469 @@
-/* $Id: mandoc.h,v 1.226 2017/06/08 18:11:22 schwarze Exp $ */
+/* $Id: mandoc.h,v 1.245 2017/07/08 14:51:04 schwarze Exp $ */
/*
* Copyright (c) 2010, 2011, 2014 Kristaps Dzonsons
* Copyright (c) 2010-2017 Ingo Schwarze
*
* 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.
*/
#define ASCII_NBRSP 31 /* non-breaking space */
#define ASCII_HYPH 30 /* breakable hyphen */
#define ASCII_BREAK 29 /* breakable zero-width space */
/*
* Status level. This refers to both internal status (i.e., whilst
* running, when warnings/errors are reported) and an indicator of a
* threshold of when to halt (when said internal state exceeds the
* threshold).
*/
enum mandoclevel {
MANDOCLEVEL_OK = 0,
MANDOCLEVEL_STYLE, /* style suggestions */
MANDOCLEVEL_WARNING, /* warnings: syntax, whitespace, etc. */
MANDOCLEVEL_ERROR, /* input has been thrown away */
MANDOCLEVEL_UNSUPP, /* input needs unimplemented features */
MANDOCLEVEL_BADARG, /* bad argument in invocation */
MANDOCLEVEL_SYSERR, /* system error */
MANDOCLEVEL_MAX
};
/*
* All possible things that can go wrong within a parse, be it libroff,
* libmdoc, or libman.
*/
enum mandocerr {
MANDOCERR_OK,
+ MANDOCERR_BASE, /* ===== start of base system conventions ===== */
+
+ MANDOCERR_MDOCDATE, /* Mdocdate found: Dd ... */
+ MANDOCERR_MDOCDATE_MISSING, /* Mdocdate missing: Dd ... */
+ MANDOCERR_ARCH_BAD, /* unknown architecture: Dt ... arch */
+ MANDOCERR_OS_ARG, /* operating system explicitly specified: Os ... */
+ MANDOCERR_RCS_MISSING, /* RCS id missing */
+ MANDOCERR_XR_BAD, /* referenced manual not found: Xr name sec */
+
MANDOCERR_STYLE, /* ===== start of style suggestions ===== */
+ MANDOCERR_DATE_LEGACY, /* legacy man(7) date format: Dd ... */
+ MANDOCERR_TITLE_CASE, /* lower case character in document title */
+ MANDOCERR_RCS_REP, /* duplicate RCS id: ... */
+ MANDOCERR_SEC_TYPO, /* typo in section name: Sh ... */
+ MANDOCERR_ARG_QUOTE, /* unterminated quoted argument */
MANDOCERR_MACRO_USELESS, /* useless macro: macro */
MANDOCERR_BX, /* consider using OS macro: macro */
MANDOCERR_ER_ORDER, /* errnos out of order: Er ... */
MANDOCERR_ER_REP, /* duplicate errno: Er ... */
- MANDOCERR_ND_DOT, /* description line ends with a full stop */
+ MANDOCERR_DELIM, /* trailing delimiter: macro ... */
+ MANDOCERR_DELIM_NB, /* no blank before trailing delimiter: macro ... */
+ MANDOCERR_FI_SKIP, /* fill mode already enabled, skipping: fi */
+ MANDOCERR_NF_SKIP, /* fill mode already disabled, skipping: nf */
+ MANDOCERR_FUNC, /* function name without markup: name() */
+ MANDOCERR_SPACE_EOL, /* whitespace at end of input line */
+ MANDOCERR_COMMENT_BAD, /* bad comment style */
MANDOCERR_WARNING, /* ===== start of warnings ===== */
/* related to the prologue */
MANDOCERR_DT_NOTITLE, /* missing manual title, using UNTITLED: line */
MANDOCERR_TH_NOTITLE, /* missing manual title, using "": [macro] */
- MANDOCERR_TITLE_CASE, /* lower case character in document title */
MANDOCERR_MSEC_MISSING, /* missing manual section, using "": macro */
MANDOCERR_MSEC_BAD, /* unknown manual section: Dt ... section */
MANDOCERR_DATE_MISSING, /* missing date, using today's date */
MANDOCERR_DATE_BAD, /* cannot parse date, using it verbatim: date */
+ MANDOCERR_DATE_FUTURE, /* date in the future, using it anyway: date */
MANDOCERR_OS_MISSING, /* missing Os macro, using "" */
- MANDOCERR_PROLOG_REP, /* duplicate prologue macro: macro */
MANDOCERR_PROLOG_LATE, /* late prologue macro: macro */
- MANDOCERR_DT_LATE, /* skipping late title macro: Dt args */
MANDOCERR_PROLOG_ORDER, /* prologue macros out of order: macros */
/* related to document structure */
MANDOCERR_SO, /* .so is fragile, better use ln(1): so path */
MANDOCERR_DOC_EMPTY, /* no document body */
MANDOCERR_SEC_BEFORE, /* content before first section header: macro */
MANDOCERR_NAMESEC_FIRST, /* first section is not NAME: Sh title */
MANDOCERR_NAMESEC_NONM, /* NAME section without Nm before Nd */
MANDOCERR_NAMESEC_NOND, /* NAME section without description */
MANDOCERR_NAMESEC_ND, /* description not at the end of NAME */
MANDOCERR_NAMESEC_BAD, /* bad NAME section content: macro */
MANDOCERR_NAMESEC_PUNCT, /* missing comma before name: Nm name */
MANDOCERR_ND_EMPTY, /* missing description line, using "" */
MANDOCERR_ND_LATE, /* description line outside NAME section */
MANDOCERR_SEC_ORDER, /* sections out of conventional order: Sh title */
MANDOCERR_SEC_REP, /* duplicate section title: Sh title */
MANDOCERR_SEC_MSEC, /* unexpected section: Sh title for ... only */
+ MANDOCERR_XR_SELF, /* cross reference to self: Xr name sec */
MANDOCERR_XR_ORDER, /* unusual Xr order: ... after ... */
MANDOCERR_XR_PUNCT, /* unusual Xr punctuation: ... after ... */
MANDOCERR_AN_MISSING, /* AUTHORS section without An macro */
/* related to macros and nesting */
MANDOCERR_MACRO_OBS, /* obsolete macro: macro */
MANDOCERR_MACRO_CALL, /* macro neither callable nor escaped: macro */
MANDOCERR_PAR_SKIP, /* skipping paragraph macro: macro ... */
MANDOCERR_PAR_MOVE, /* moving paragraph macro out of list: macro */
MANDOCERR_NS_SKIP, /* skipping no-space macro */
MANDOCERR_BLK_NEST, /* blocks badly nested: macro ... */
MANDOCERR_BD_NEST, /* nested displays are not portable: macro ... */
MANDOCERR_BL_MOVE, /* moving content out of list: macro */
- MANDOCERR_FI_SKIP, /* fill mode already enabled, skipping: fi */
- MANDOCERR_NF_SKIP, /* fill mode already disabled, skipping: nf */
+ MANDOCERR_TA_LINE, /* first macro on line: Ta */
MANDOCERR_BLK_LINE, /* line scope broken: macro breaks macro */
MANDOCERR_BLK_BLANK, /* skipping blank line in line scope */
/* related to missing arguments */
MANDOCERR_REQ_EMPTY, /* skipping empty request: request */
MANDOCERR_COND_EMPTY, /* conditional request controls empty scope */
MANDOCERR_MACRO_EMPTY, /* skipping empty macro: macro */
MANDOCERR_BLK_EMPTY, /* empty block: macro */
MANDOCERR_ARG_EMPTY, /* empty argument, using 0n: macro arg */
MANDOCERR_BD_NOTYPE, /* missing display type, using -ragged: Bd */
MANDOCERR_BL_LATETYPE, /* list type is not the first argument: Bl arg */
MANDOCERR_BL_NOWIDTH, /* missing -width in -tag list, using 6n */
MANDOCERR_EX_NONAME, /* missing utility name, using "": Ex */
MANDOCERR_FO_NOHEAD, /* missing function name, using "": Fo */
MANDOCERR_IT_NOHEAD, /* empty head in list item: Bl -type It */
MANDOCERR_IT_NOBODY, /* empty list item: Bl -type It */
+ MANDOCERR_IT_NOARG, /* missing argument, using next line: Bl -c It */
MANDOCERR_BF_NOFONT, /* missing font type, using \fR: Bf */
MANDOCERR_BF_BADFONT, /* unknown font type, using \fR: Bf font */
MANDOCERR_PF_SKIP, /* nothing follows prefix: Pf arg */
MANDOCERR_RS_EMPTY, /* empty reference block: Rs */
MANDOCERR_XR_NOSEC, /* missing section argument: Xr arg */
MANDOCERR_ARG_STD, /* missing -std argument, adding it: macro */
MANDOCERR_OP_EMPTY, /* missing option string, using "": OP */
MANDOCERR_UR_NOHEAD, /* missing resource identifier, using "": UR */
MANDOCERR_EQN_NOBOX, /* missing eqn box, using "": op */
/* related to bad arguments */
- MANDOCERR_ARG_QUOTE, /* unterminated quoted argument */
MANDOCERR_ARG_REP, /* duplicate argument: macro arg */
MANDOCERR_AN_REP, /* skipping duplicate argument: An -arg */
MANDOCERR_BD_REP, /* skipping duplicate display type: Bd -type */
MANDOCERR_BL_REP, /* skipping duplicate list type: Bl -type */
MANDOCERR_BL_SKIPW, /* skipping -width argument: Bl -type */
MANDOCERR_BL_COL, /* wrong number of cells */
MANDOCERR_AT_BAD, /* unknown AT&T UNIX version: At version */
MANDOCERR_FA_COMMA, /* comma in function argument: arg */
MANDOCERR_FN_PAREN, /* parenthesis in function name: arg */
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_FT_BAD, /* unknown font, skipping request: ft font */
MANDOCERR_TR_ODD, /* odd number of characters in request: tr char */
/* related to plain text */
MANDOCERR_FI_BLANK, /* blank line in fill mode, using .sp */
MANDOCERR_FI_TAB, /* tab in filled text */
- MANDOCERR_SPACE_EOL, /* whitespace at end of input line */
MANDOCERR_EOS, /* new sentence, new line */
- MANDOCERR_COMMENT_BAD, /* bad comment style */
MANDOCERR_ESC_BAD, /* invalid escape sequence: esc */
MANDOCERR_STR_UNDEF, /* undefined string, using "": name */
/* related to tables */
MANDOCERR_TBLLAYOUT_SPAN, /* tbl line starts with span */
MANDOCERR_TBLLAYOUT_DOWN, /* tbl column starts with span */
MANDOCERR_TBLLAYOUT_VERT, /* skipping vertical bar in tbl layout */
MANDOCERR_ERROR, /* ===== start of errors ===== */
/* related to tables */
MANDOCERR_TBLOPT_ALPHA, /* non-alphabetic character in tbl options */
MANDOCERR_TBLOPT_BAD, /* skipping unknown tbl option: option */
MANDOCERR_TBLOPT_NOARG, /* missing tbl option argument: option */
MANDOCERR_TBLOPT_ARGSZ, /* wrong tbl option argument size: option */
MANDOCERR_TBLLAYOUT_NONE, /* empty tbl layout */
MANDOCERR_TBLLAYOUT_CHAR, /* invalid character in tbl layout: char */
MANDOCERR_TBLLAYOUT_PAR, /* unmatched parenthesis in tbl layout */
MANDOCERR_TBLDATA_NONE, /* tbl without any data cells */
MANDOCERR_TBLDATA_SPAN, /* ignoring data in spanned tbl cell: data */
MANDOCERR_TBLDATA_EXTRA, /* ignoring extra tbl data cells: data */
MANDOCERR_TBLDATA_BLK, /* data block open at end of tbl: macro */
/* related to document structure and macros */
MANDOCERR_FILE, /* cannot open file */
+ MANDOCERR_PROLOG_REP, /* duplicate prologue macro: macro */
+ MANDOCERR_DT_LATE, /* skipping late title macro: Dt args */
MANDOCERR_ROFFLOOP, /* input stack limit exceeded, infinite loop? */
MANDOCERR_CHAR_BAD, /* skipping bad character: number */
MANDOCERR_MACRO, /* skipping unknown macro: 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 */
MANDOCERR_BLK_NOTOPEN, /* skipping end of block that is not open */
MANDOCERR_RE_NOTOPEN, /* fewer RS blocks open, skipping: RE arg */
MANDOCERR_BLK_BROKEN, /* inserting missing end of block: macro ... */
MANDOCERR_BLK_NOEND, /* appending missing end of block: macro */
/* related to request and macro arguments */
MANDOCERR_NAMESC, /* escaped character not allowed in a name: name */
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_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_SO_PATH, /* NOT IMPLEMENTED: .so with absolute path or ".." */
MANDOCERR_SO_FAIL, /* .so request failed */
MANDOCERR_ARG_SKIP, /* skipping all arguments: macro args */
MANDOCERR_ARG_EXCESS, /* skipping excess arguments: macro ... args */
MANDOCERR_DIVZERO, /* divide by zero */
MANDOCERR_UNSUPP, /* ===== start of unsupported features ===== */
MANDOCERR_TOOLARGE, /* input too large */
MANDOCERR_CHAR_UNSUPP, /* unsupported control character: number */
MANDOCERR_REQ_UNSUPP, /* unsupported roff request: request */
MANDOCERR_TBLOPT_EQN, /* eqn delim option in tbl: arg */
MANDOCERR_TBLLAYOUT_MOD, /* unsupported tbl layout modifier: m */
MANDOCERR_TBLMACRO, /* ignoring macro in table: macro */
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_ROOT, /* root of parse tree */
EQN_TEXT, /* text (number, variable, whatever) */
EQN_SUBEXPR, /* nested `eqn' subexpression */
EQN_LIST, /* list (braces, etc.) */
- EQN_LISTONE, /* singleton list */
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 */
};
/*
- * An equation consists of a tree of expressions starting at a given
- * line and position.
- */
-struct eqn {
- char *name; /* identifier (or NULL) */
- struct eqn_box *root; /* root mathematical expression */
- int ln; /* invocation line */
- int pos; /* invocation position */
-};
-
-/*
* 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_IGNORE, /* escape to be ignored */
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_FONTPREV, /* previous font mode */
ESCAPE_NUMBERED, /* a numbered glyph */
ESCAPE_UNICODE, /* a unicode codepoint */
+ ESCAPE_BREAK, /* break the output line */
ESCAPE_NOSPACE, /* suppress space if the last on a line */
ESCAPE_HORIZ, /* horizontal movement */
ESCAPE_HLINE, /* horizontal line drawing */
ESCAPE_SKIPCHAR, /* skip the next character */
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_escape(const char **, const char **, int *);
void mchars_alloc(void);
void mchars_free(void);
int mchars_num2char(const char *, size_t);
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 mandoclevel, mandocmsg, const char *);
+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 *);
Index: vendor/mdocml/dist/mandoc_aux.c
===================================================================
--- vendor/mdocml/dist/mandoc_aux.c (revision 321806)
+++ vendor/mdocml/dist/mandoc_aux.c (revision 321807)
@@ -1,111 +1,118 @@
-/* $Id: mandoc_aux.c,v 1.9 2015/11/07 14:22:29 schwarze Exp $ */
+/* $Id: mandoc_aux.c,v 1.10 2017/06/12 19:05:47 schwarze Exp $ */
/*
* Copyright (c) 2009, 2011 Kristaps Dzonsons
- * Copyright (c) 2014 Ingo Schwarze
+ * Copyright (c) 2014, 2015, 2017 Ingo Schwarze
*
* 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
#if HAVE_ERR
#include
#endif
#include
#include
#include
#include
#include "mandoc.h"
#include "mandoc_aux.h"
int
mandoc_asprintf(char **dest, const char *fmt, ...)
{
va_list ap;
int ret;
va_start(ap, fmt);
ret = vasprintf(dest, fmt, ap);
va_end(ap);
if (ret == -1)
err((int)MANDOCLEVEL_SYSERR, NULL);
return ret;
}
void *
mandoc_calloc(size_t num, size_t size)
{
void *ptr;
ptr = calloc(num, size);
if (ptr == NULL)
err((int)MANDOCLEVEL_SYSERR, NULL);
return ptr;
}
void *
mandoc_malloc(size_t size)
{
void *ptr;
ptr = malloc(size);
if (ptr == NULL)
err((int)MANDOCLEVEL_SYSERR, NULL);
return ptr;
}
void *
mandoc_realloc(void *ptr, size_t size)
{
-
ptr = realloc(ptr, size);
if (ptr == NULL)
err((int)MANDOCLEVEL_SYSERR, NULL);
return ptr;
}
void *
mandoc_reallocarray(void *ptr, size_t num, size_t size)
{
-
ptr = reallocarray(ptr, num, size);
+ if (ptr == NULL)
+ err((int)MANDOCLEVEL_SYSERR, NULL);
+ return ptr;
+}
+
+void *
+mandoc_recallocarray(void *ptr, size_t oldnum, size_t num, size_t size)
+{
+ ptr = recallocarray(ptr, oldnum, num, size);
if (ptr == NULL)
err((int)MANDOCLEVEL_SYSERR, NULL);
return ptr;
}
char *
mandoc_strdup(const char *ptr)
{
char *p;
p = strdup(ptr);
if (p == NULL)
err((int)MANDOCLEVEL_SYSERR, NULL);
return p;
}
char *
mandoc_strndup(const char *ptr, size_t sz)
{
char *p;
p = mandoc_malloc(sz + 1);
memcpy(p, ptr, sz);
p[(int)sz] = '\0';
return p;
}
Index: vendor/mdocml/dist/mandoc_aux.h
===================================================================
--- vendor/mdocml/dist/mandoc_aux.h (revision 321806)
+++ vendor/mdocml/dist/mandoc_aux.h (revision 321807)
@@ -1,26 +1,27 @@
-/* $Id: mandoc_aux.h,v 1.6 2017/02/17 14:31:52 schwarze Exp $ */
+/* $Id: mandoc_aux.h,v 1.7 2017/06/12 19:05:47 schwarze Exp $ */
/*
* Copyright (c) 2009, 2011 Kristaps Dzonsons
- * Copyright (c) 2014 Ingo Schwarze
+ * Copyright (c) 2014, 2017 Ingo Schwarze
*
* 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.
*/
int mandoc_asprintf(char **, const char *, ...)
__attribute__((__format__ (__printf__, 2, 3)));
void *mandoc_calloc(size_t, size_t);
void *mandoc_malloc(size_t);
void *mandoc_realloc(void *, size_t);
void *mandoc_reallocarray(void *, size_t, size_t);
+void *mandoc_recallocarray(void *, size_t, size_t, size_t);
char *mandoc_strdup(const char *);
char *mandoc_strndup(const char *, size_t);
Index: vendor/mdocml/dist/mandoc_char.7
===================================================================
--- vendor/mdocml/dist/mandoc_char.7 (revision 321806)
+++ vendor/mdocml/dist/mandoc_char.7 (revision 321807)
@@ -1,807 +1,808 @@
-.\" $Id: mandoc_char.7,v 1.66 2017/06/02 12:43:52 schwarze Exp $
+.\" $Id: mandoc_char.7,v 1.67 2017/06/14 20:57:07 schwarze Exp $
.\"
.\" Copyright (c) 2003 Jason McIntyre